diff --git a/README.md b/README.md index c0b5c82..4869f88 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ export default { | `variant` | `monochrome`, `neutral`, `tonal-spot`, `vibrant`, `expressive`, `fidelity`, `content`, `rainbow`, `fruit-salad` | `tonal-spot` | | `spec-version` | `2021`, `2025` | `2021` | | `gamut` | `srgb`, `display-p3` (or `p3`), `rec2020` | `srgb` | +| `colors` | `extend`, `replace` | `extend` | +| `contrasts` | any of `default`, `reduced`, `medium`, `high`, or `all` | `default` | Every option also accepts camelCase (`sourceColor`, `specVersion`) so the same names work in a `tailwind.config.js`. @@ -64,6 +66,7 @@ work in a `tailwind.config.js`. variant: vibrant; spec-version: 2025; gamut: display-p3; + colors: replace; } ``` @@ -128,12 +131,192 @@ Some things worth knowing before turning it on: Browser support is not a concern: `oklch()` has been Baseline since 2023, which is older than the `light-dark()` these colors are already emitted with. +#### `colors` + +Whether the generated colors are added to Tailwind's palette or take its place. + +Material names its palettes for their role, and two of those names — `neutral` and +`error` — are also Tailwind color names. Material's steps go `0, 5, 10, … 95, 98, 99, 100` +and Tailwind's go `50, 100, 200, … 950`, so under the default `extend` the two scales +interleave. Material wins the steps it defines and Tailwind keeps the rest: + +``` +bg-neutral-50 Material tone 50 a mid grey +bg-neutral-500 Tailwind's neutral-500 +``` + +`replace` drops Tailwind's palette entirely, so every color name means exactly one thing: + +```css +@plugin "@claas.dev/material-tailwind" { + source-color: #0c1445; + colors: replace; +} +``` + +This removes `bg-red-500`, `text-sky-300` and every other Tailwind color utility. The +color keywords are built into the utilities rather than read from the theme, so +`bg-transparent`, `bg-current` and `bg-inherit` are unaffected, and `black` and `white` +are kept explicitly because they do come from the palette and are too widely used to drop. + +`extend` stays the default so upgrading does not move anyone's colors. + +#### `contrasts` + +Material defines every color role at four contrast levels. Only the default one is +generated unless you ask for more, because the other three are two thirds of everything +this plugin emits and most themes never use them: + +```css +@plugin "@claas.dev/material-tailwind" { + source-color: #0c1445; + contrasts: high; +} +``` + +That adds `bg-high-contrast-primary`, `bg-light-high-contrast-primary` and the rest of the +high contrast roles. The list is not exclusive, and any separator that reads naturally +works — `high medium`, `high, medium`, or `all` for every level. + +The `default` level is always generated whether or not you list it, because the +unqualified roles (`bg-primary`, `text-on-surface`) come from it. + +# Overriding colors at runtime + +Every color is emitted as a CSS variable in Tailwind's own `--color-*` namespace, so you +can change one at runtime without rebuilding: + +```js +document.documentElement.style.setProperty("--color-light-primary", "#ff0000"); +``` + +### How the variables are wired + +There are two kinds of token. **Leaves** hold a literal color — every per-scheme role and +every palette step: + +```css +--color-light-primary #525a92 +--color-dark-primary #bbc3ff +--color-light-high-contrast-primary #1f275c +--color-primary-40 #525a92 +``` + +**Composites** are built out of leaves with `light-dark()`, and are what the unqualified +utilities use: + +```css +.bg-primary { + background-color: var( + --color-primary, + light-dark(var(--color-light-primary), var(--color-dark-primary)) + ); +} +``` + +Composites reference the leaves rather than restating their literals, so overriding +`--color-light-primary` moves `--color-primary` and every utility built on it. + +Composites are never declared anywhere — they exist only as the fallback above. That means +you can override either level, and from anywhere: + +```css +/* Retint every default-contrast color that builds on it. */ +:root { + --color-light-primary: #ff0000; +} + +/* Or replace one composite outright, light and dark together. */ +@theme { + --color-primary: #ff0000; +} +``` + +### The leaves are registered with `@property` + +```css +@property --color-light-primary { + syntax: ""; + inherits: true; + initial-value: #525a92; +} +``` + +This buys two things. An override that is not a color falls back to the generated default +instead of poisoning every declaration that reads it — an unregistered custom property +would take the whole `background-color` down with it. And a registered property is +animatable, so a theme change can be transitioned: + +```css +:root { + transition: --color-light-primary 300ms, --color-dark-primary 300ms; +} +``` + +The transition has to be declared on the element where the value changes — usually +`:root` — not on the element being painted. Interpolation propagates through the +`light-dark()` composites to the utilities. + +### Why composites are not registered + +A registered `` property resolves to a single color at the element it is declared +on and inherits as that color. A registered `light-dark()` is therefore frozen at the +root's `color-scheme` and stops following a `color-scheme: dark` subtree. Composites have +to stay unregistered so `light-dark()` resolves where it is used. This also rules out +folding them into an `initial-value`, which may not contain `var()` at all. + +### Roles are not derived from palette steps + +It is tempting to make `--color-light-primary` reference `--color-primary-40`, so that +overriding five palettes would retint everything. It does not hold up. A role is exactly a +palette tone often enough to look right and not often enough to be correct: + +| | light | dark | light-high-contrast | +| --- | --- | --- | --- | +| `spec-version: 2021` | 53/59 | 45/59 | 35/59 | +| `spec-version: 2025` | 12/59 | 13/59 | 28/59 | + +The 2025 chroma multipliers and the contrast levels break the correspondence. Roles and +palette steps are therefore independent leaves. + +### What this does not do + +Changing the **source color** at runtime is not possible this way. Deriving a scheme from +a source color needs Material's HCT solver, which is JavaScript. CSS variables let you +override individual roles and swap between schemes you generated ahead of time. + +### The cost + +Because a Tailwind plugin cannot register real theme variables, every leaf ships whether +or not a utility uses it — Tailwind's tree shaking does not apply to what a plugin writes. +That is 227 registrations, about 1.83 kB gzipped, at the default contrast. Adding all four +contrast levels raises it to 581 registrations and about 4.20 kB. + +Composites cost nothing when unused, since they live in the utilities rather than in a +block of their own. In the [example app](example) the stylesheet went from 3.90 kB to +6.27 kB gzipped. See [docs/tailwind-plugin-api.md](docs/tailwind-plugin-api.md) for why +the fixed part cannot be tree-shaken away. + # How it works The plugin generates colors with [@material/material-color-utilites](https://www.npmjs.com/package/@material/material-color-utilities) and extends the Tailwind CSS theme to make them available for you. Additionally this plugin extends the default theme with various design tokens collected from [material.io](https://material.io) and the [Material 3 Design Kit (Community)](https://www.figma.com/community/file/1035203688168086460). # Known issues +### Tailwind CSS IntelliSense shows no color swatch + +The colored square the VS Code extension draws next to a color utility does not appear for +the colors this plugin generates. `bg-red-500` still gets one, `bg-primary` does not. + +The extension resolves a utility's value and then asks Tailwind's design system for any +theme variable in it. A plugin cannot register a real theme variable, so the design system +has never heard of `--color-primary`, the `var()` is left unresolved, and the value stops +being parseable as a color. + +There is no way to fix this from inside a plugin. It is the same limitation that makes the +colors overridable in the first place, seen from the other side — see +[docs/tailwind-plugin-api.md](docs/tailwind-plugin-api.md). + ### `ERR_MODULE_NOT_FOUND` from `@material/material-color-utilities` `@material/material-color-utilities@0.4.0` is an ESM-only package, but some of its diff --git a/docs/tailwind-plugin-api.md b/docs/tailwind-plugin-api.md new file mode 100644 index 0000000..079feea --- /dev/null +++ b/docs/tailwind-plugin-api.md @@ -0,0 +1,226 @@ +# Where the Tailwind CSS plugin API constrains this plugin + +Notes on the limits hit while making the generated colors overridable at runtime. +Everything here was verified against **Tailwind CSS 4.2.4** by compiling with the +`compile()` API, against **Tailwind CSS IntelliSense 0.16.0** by reading what the language +server actually does, and, where the question was about browser behaviour, by measuring in +a browser. Findings are dated to those versions — the plugin API is not versioned +separately. + +The short version: a JS plugin cannot participate in Tailwind v4's theme system. It can +only hand Tailwind a v3-shaped config object and write base styles. Everything below +follows from that, including the editor tooling breaking, which looks like a separate +problem and is not. + +## 1. Plugin theme values are inlined, never emitted as variables + +A plugin returning `{ theme: { extend: { colors: { primary: "#525a92" } } } }` produces: + +```css +.bg-primary { background-color: #525a92; } +``` + +No `--color-primary` is emitted anywhere. Tailwind's JS-config compat layer registers +plugin theme values as *inline*, so they are substituted into utilities directly. + +Contrast a color that came from CSS `@theme`, in the same stylesheet: + +```css +.bg-red-500 { background-color: var(--color-red-500); } +``` + +Same namespace, same theme, different mechanism — purely because of where the value +entered. This is the root limitation; the rest are consequences of working around it. + +**Worked around by** making every theme value a `var(--color-…)` reference and defining +the variables ourselves through `addBase`. + +## 2. `@theme` is unreachable from a plugin + +The obvious fix is for the plugin to emit an `@theme` block. It cannot. Passing one to +`addBase` copies it into the output verbatim, nested inside `@layer base`: + +```css +@layer base { + @theme static { + --color-probe: #bbc3ff; + } +} +``` + +Tailwind never parses it, no utilities are generated from it, and browsers ignore the +unknown at-rule. `@theme`, `@theme static`, `@theme inline` and `@theme default` all +behave this way. `@theme` is a CSS-level directive processed while parsing the stylesheet, +and plugins run after that. + +This also means the modifiers Tailwind documents for exactly our situation are +unavailable: `static` (always emit) and `inline` (for variables that reference other +variables) are things we have to hand-roll. + +## 3. No API to register a theme variable + +The `PluginAPI` type in Tailwind 4.2.4 exposes: + +``` +addBase addUtilities addComponents addVariant matchUtilities +``` + +There is no `addTheme`, no `registerTheme`, nothing that reaches the theme system the way +CSS `@theme` does. `addBase` is the only place a plugin can put a declaration. + +## 4. Consequence: no tree shaking + +This is the expensive one. + +Variables that enter through `@theme` are tree-shaken — only the ones actually used are +emitted. Anything written through `addBase` is an ordinary base style, so all of it ships, +every build, whether or not a utility references it. We cannot know which utilities the +user's content will produce, and even if we could there is no hook that runs late enough +to prune. + +Only what a plugin *writes* has this problem. Values that live inside the theme, and so +inside the utilities, are still tree-shaken by usage. That is what pushed the composites +into fallbacks (§5) and left only the leaf registrations as fixed cost. + +Two things were done about the size: + +- **Composites moved into the utilities.** 236 tokens that now cost nothing when unused. +- **Contrast levels became opt-in.** Material defines every role at four contrast levels, + and the three non-default ones were 531 of 817 tokens — 68% of the output — which the + example app did not use a single one of. + +Measured on the example app: + +| | raw | gzip | +| --- | --- | --- | +| before (inlined literals) | 17.34 kB | 3.90 kB | +| variables, all four contrasts, composites declared | 131.59 kB | 11.62 kB | +| variables, default contrast, composites as fallbacks | 43.38 kB | 6.27 kB | + +The fixed part is now 227 registrations, about 1.83 kB gzip (581 and 4.20 kB with +`contrasts: all`). + +The escape hatch for the rest is not a plugin at all — a codegen step that writes a `.css` +file with a real `@theme static { … }` block, which the user `@import`s. That gets genuine +theme registration, tree shaking, and `@theme inline`, at the cost of a build step and +giving up `@plugin` configuration. Worth revisiting if the size becomes a problem again. + +## 5. `addBase` output lands in `@layer base`, which beats `@theme` + +Tailwind's layer order is `theme, base, components, utilities`. Anything a plugin +*declares* lands in `base`; a user's `@theme` block lands in `theme`. Later layers win, so +a plugin declaration silently beats the user's own override — the opposite of what anyone +would expect. + +This bit us. A first version declared the composites in a `:root` block and made +`@theme { --color-primary: … }` stop working, which it had done before the change. + +The fix was to stop declaring anything. Composites are fallbacks inside the theme value +instead: + +```css +.bg-primary { + background-color: var(--color-primary, light-dark(var(--color-light-primary), …)); +} +``` + +Nothing defines `--color-primary`, so setting it anywhere wins, `@theme` included. It also +costs nothing when no utility uses the color, which is as close to tree shaking as a +plugin gets. + +`@property` registrations are unaffected either way — registration is not a cascading +declaration, so being nested in a layer does not matter. That was verified rather than +assumed. + +The general lesson: **a plugin should read variables, not declare them.** Every value it +declares is a value the user cannot override from the place Tailwind documents. + +## 6. Editor tooling stops showing color swatches + +Tailwind CSS IntelliSense draws a colored square next to a color utility in the editor. +For every color this plugin generates, that square is now gone. + +It is the same root cause as §1–§3 rather than a separate problem, and the mechanism is +worth writing down because it is not obvious. Checked against +`bradlc.vscode-tailwindcss@0.16.0`: + +- The extension resolves a utility's value and then asks the **design system** for any + theme variable in it — `designSystem.resolveThemeValue(name, true)`. That is why + `bg-red-500`, which compiles to `var(--color-red-500)`, still gets a swatch: the design + system knows that variable. +- Our variables are registered with `@property` in base styles. The design system has + never heard of them, so `resolveThemeValue` returns nothing and the `var()` survives. +- Before parsing a color, the extension replaces any `var(…)` with the literal `1`. An + unresolved variable therefore becomes an unparseable value, and no swatch is drawn. +- The regex it uses for that is `/var\([^)]+\)/`, which stops at the first `)`. Our + composite fallback nests variables inside a `light-dark()`, so it is not merely + unresolved but mangled. + +The part that stings is that this is a **regression**, not a pre-existing gap. The +extension does understand `light-dark()` — it rewrites `light-dark(a, b)` to `a` and +swatches the light value. So before the colors became variables, every utility here had a +working swatch: the per-scheme roles were literal hex, and the composites were +`light-dark(#525a92, #bbc3ff)`. Both resolved. Trading that away was not a considered +decision at the time. + +Nothing in the plugin API can fix it. The extension is asking the design system a +reasonable question; we simply cannot put anything into the design system (§3). The +codegen escape hatch in §4 would fix this too, and for the same reason it fixes the +others — a real `@theme` block is exactly what `resolveThemeValue` reads. + +## 7. Both plugin callbacks need the same work done + +`plugin.withOptions` takes two functions: one returning the config, one receiving the +`PluginAPI`. Because the theme values and the variable definitions are two halves of the +same computation, both need the generated colors, and neither can hand anything to the +other. Solving a Material theme is not cheap — eight schemes, each fitted to a gamut — so +the result is memoised per distinct set of options. + +Not a serious limitation, but the API shape does force the caching. + +## 8. `theme.colors` replacement is all-or-nothing + +Setting `theme.colors` rather than `theme.extend.colors` does work from a plugin and +cleanly replaces Tailwind's palette, which is how the `colors: replace` option is built. +But it is a whole-namespace switch — there is no way to say "drop Tailwind's `neutral` +scale but keep everything else", which is all that is actually needed to resolve the name +collision. Users who want the collision gone must drop `bg-red-500` and every other +Tailwind color with it. + +Worth noting: `transparent`, `current` and `inherit` are built into the utilities and +survive replacement, but `black` and `white` come from `theme.colors` and disappear. The +plugin re-adds those explicitly. + +## Browser-level constraints (not Tailwind's fault) + +These shaped the design just as much and are recorded here so the reasoning is in one +place. All measured in a browser. + +- **A registered `` property freezes `light-dark()`.** It computes to a resolved + color at the element it is declared on, so it stops following a `color-scheme: dark` + subtree. Verified: a registered composite returned the same color in both a + `color-scheme: light` and a `color-scheme: dark` subtree, while an unregistered one + switched correctly. This is why composites are not registered. +- **`initial-value` may not contain `var()`.** It must be computationally independent; a + rule that violates this is dropped entirely. This independently rules out registering + the composites. +- **Registration makes invalid overrides safe.** An invalid value on a registered property + falls back to `initial-value`; on an unregistered one it takes the whole declaration + down (`rgba(0, 0, 0, 0)`). +- **Registered properties are animatable**, and interpolation propagates through an + unregistered `light-dark()` composite to the utilities reading it. The `transition` must + be declared where the value changes, not where it is painted. + +## Open questions + +- Is the codegen approach from §4 worth offering alongside the plugin? It removes §1, §2, + §4, §5 and §6 at once, which is most of this document. The cost is a build step and + giving up `@plugin` configuration. +- The palettes are 109 of the remaining 227 registrations and are arguably a lower-level + tool than the roles. Should they be opt-in the way the contrast levels now are? +- Could the leaves become fallbacks too, the way the composites did, and drop the fixed + cost to nothing? It would mean giving up `@property`, and with it the invalid-override + fallback and animatable theme changes. That is the real trade: a few kB against those + two properties. +- Does a later Tailwind version expose anything closer to theme registration for plugins? + Worth re-checking §3 on upgrade; the whole design would change if it did. diff --git a/index.js b/index.js index 08bf207..dc8efbb 100644 --- a/index.js +++ b/index.js @@ -64,9 +64,34 @@ const specVersions = ["2021", "2025"]; /** @type {SpecVersion} */ const defaultSpecVersion = "2021"; +/** + * Whether the generated colors are added to Tailwind's own palette or take its + * place. Material's palettes are named for their role, and two of those names + * ("neutral" and "error") are also Tailwind color names, so in "extend" the two + * scales interleave: Material defines the steps it has and Tailwind's survive + * at the rest, leaving `bg-neutral-50` Material's mid grey while + * `bg-neutral-500` is still Tailwind's. "replace" drops Tailwind's palette so + * every color name means exactly one thing. + * @typedef {"extend" | "replace"} ColorsMode + */ + +/** + * Typed as strings so an unvalidated option can be checked against it + * @type {string[]} + */ +const colorsModes = ["extend", "replace"]; + +/** + * Extending is what the plugin has always done, so it stays the default and + * nobody's colors move when they upgrade. + * @type {ColorsMode} + */ +const defaultColorsMode = "extend"; + //TODO update Tailwind CSS to a version after 4.0.6 to fix types /** * @import {Config} from "tailwindcss" + * @import {ThemeConfig} from "tailwindcss/plugin" */ /** @@ -150,6 +175,30 @@ function createPalettes(materialPalettes, gamut) { return palettes; } +/** + * The namespace Tailwind reads color utilities out of. Every token this plugin + * emits is a `--color-*` variable, which is what Tailwind documents for adding + * colors to a theme, so `var(--color-primary)` works in an arbitrary value the + * same way `var(--color-red-500)` does. + * @see https://tailwindcss.com/docs/theme + */ +const namespace = "--color-"; + +/** + * A Tailwind plugin cannot register real theme variables. `@theme` is only a + * CSS-level directive: handed to `addBase` it is copied into the output + * verbatim as an at-rule no browser understands, and no utilities come out of + * it. So the theme value a utility inlines is made a `var()` reference and the + * definition it points at is written separately, which reproduces what `@theme` + * would have emitted. The one thing that cannot be reproduced is Tailwind's + * tree shaking: every token ships whether or not a utility uses it. + * @param {string} name + * @returns {string} + */ +function reference(name) { + return `var(${namespace}${name})`; +} + /** * The color accessors on MaterialDynamicColors. Every one of them is a method * taking no arguments that returns the DynamicColor for the scheme's spec @@ -219,15 +268,29 @@ function requestedHct(scheme, color) { return [palette.hue, palette.chroma, tone]; } +/** + * @typedef {object} Tokens + * @property {Record>} colors + * The Tailwind theme, every value a `var()` reference + * @property {Record} leaves + * Tokens whose value is a literal color, keyed by the bare token name without + * the `--color-` the variable gets when it is registered. These are the ones + * worth overriding and the only ones that can be registered with `@property`. + * The colors composed out of them live in the theme values instead. + */ + /** * Creates colors * @param {Schemes} schemes * @param {Gamut} gamut - * @returns {Record>} + * @param {ContrastName[]} contrasts + * @returns {Tokens} */ -function createColors(schemes, gamut) { +function createColors(schemes, gamut, contrasts) { /** @type {Record >} */ const colors = {}; + /** @type {Record} */ + const leaves = {}; for (const [schemeName, scheme] of Object.entries(schemes)) { /** @type {Record} */ @@ -237,67 +300,145 @@ function createColors(schemes, gamut) { const color = resolveColor(scheme, name, gamut); if (color === undefined) continue; - schemeColors[camelToKebabCase(name)] = color; + // Tailwind flattens a nested color object with a dash, so `light.primary` + // is the `--color-light-primary` a `bg-light-primary` utility reads + const token = `${camelToKebabCase(schemeName)}-${camelToKebabCase(name)}`; + leaves[token] = color; + schemeColors[camelToKebabCase(name)] = reference(token); } colors[camelToKebabCase(schemeName)] = schemeColors; } - /** - * The contrast levels, as the prefix they get in the color name and the pair - * of schemes the `light-dark()` value is built from - * @type {[prefix: string, light: SchemeName, dark: SchemeName][]} - */ - const contrasts = [ - ["", "light", "dark"], - ["reduced-contrast-", "light-reduced-contrast", "dark-reduced-contrast"], - ["medium-contrast-", "light-medium-contrast", "dark-medium-contrast"], - ["high-contrast-", "light-high-contrast", "dark-high-contrast"], - ]; - for (const name of colorNames) { - for (const [prefix, light, dark] of contrasts) { - const lightColor = resolveColor(schemes[light], name, gamut); - const darkColor = resolveColor(schemes[dark], name, gamut); + for (const contrast of contrasts) { + const { prefix, light, dark } = contrastLevels[contrast]; + const lightScheme = schemes[light]; + const darkScheme = schemes[dark]; + if (lightScheme === undefined || darkScheme === undefined) continue; + + const lightColor = resolveColor(lightScheme, name, gamut); + const darkColor = resolveColor(darkScheme, name, gamut); if (lightColor === undefined || darkColor === undefined) continue; - colors[`${prefix}${camelToKebabCase(name)}`] = - `light-dark(${lightColor}, ${darkColor})`; + const role = camelToKebabCase(name); + const token = `${prefix}${role}`; + + // Composed out of the per-scheme tokens rather than restating their + // literals, so overriding `--color-light-primary` moves `--color-primary` + // and every utility built on it too. + // + // It goes in the theme as a fallback rather than being declared anywhere. + // A declaration would land in `@layer base`, which beats the + // `@layer theme` a user's `@theme` override lands in, and would silently + // ignore it. Only reading the variable means setting it anywhere wins, + // and nothing ships for a color no utility uses. + const composite = `light-dark(${reference(`${light}-${role}`)}, ${reference(`${dark}-${role}`)})`; + colors[token] = `var(${namespace}${token}, ${composite})`; } } - return colors; + return { colors, leaves }; } /** * @typedef {"light" | "dark"} Scheme * @typedef {"reduced" | "medium" | "high"} Contrast * @typedef {Scheme | `${Scheme}-${Contrast}-contrast`} SchemeName - * @typedef {Record} Schemes + * @typedef {Partial>} Schemes */ /** - * Using contrast values as recommended by https://github.com/material-foundation/material-color-utilities/blob/9889de141b3b5194b8574f9e378e55f4428bdb5e/dev_guide/creating_color_scheme.md + * Every color role exists at four contrast levels. Only the default one is + * generated unless asked for, because the other three are two thirds of + * everything this plugin emits and most themes never use them. * + * Contrast values are the ones recommended by + * https://github.com/material-foundation/material-color-utilities/blob/9889de141b3b5194b8574f9e378e55f4428bdb5e/dev_guide/creating_color_scheme.md + * @satisfies {Record} + */ +const contrastLevels = { + default: { contrast: 0, prefix: "", light: "light", dark: "dark" }, + reduced: { + contrast: -1, + prefix: "reduced-contrast-", + light: "light-reduced-contrast", + dark: "dark-reduced-contrast", + }, + medium: { + contrast: 0.5, + prefix: "medium-contrast-", + light: "light-medium-contrast", + dark: "dark-medium-contrast", + }, + high: { + contrast: 1, + prefix: "high-contrast-", + light: "light-high-contrast", + dark: "dark-high-contrast", + }, +}; + +/** @typedef {keyof typeof contrastLevels} ContrastName */ + +/** + * The unqualified color roles come from the default level, so it is always + * generated whether or not it was asked for. + * @type {ContrastName} + */ +const requiredContrast = "default"; + +/** * @param {string} sourceColor * @param {VariantName} variant * @param {SpecVersion} specVersion + * @param {ContrastName[]} contrasts * @returns {Schemes} */ -function createSchemes(sourceColor, variant, specVersion) { +function createSchemes(sourceColor, variant, specVersion, contrasts) { const color = Hct.fromInt(argbFromHex(sourceColor)); const Scheme = variants[variant]; - return { - "light-reduced-contrast": new Scheme(color, false, -1, specVersion), - light: new Scheme(color, false, 0, specVersion), - "light-medium-contrast": new Scheme(color, false, 0.5, specVersion), - "light-high-contrast": new Scheme(color, false, 1, specVersion), - "dark-reduced-contrast": new Scheme(color, true, -1, specVersion), - dark: new Scheme(color, true, 0, specVersion), - "dark-medium-contrast": new Scheme(color, true, 0.5, specVersion), - "dark-high-contrast": new Scheme(color, true, 1, specVersion), - }; + /** @type {Schemes} */ + const schemes = {}; + for (const name of contrasts) { + const { contrast, light, dark } = contrastLevels[name]; + schemes[light] = new Scheme(color, false, contrast, specVersion); + schemes[dark] = new Scheme(color, true, contrast, specVersion); + } + + return schemes; +} + +/** + * Registering a custom property makes an override that is not a color fall back + * to the generated default instead of poisoning every declaration that reads + * it, and makes the token animatable, so a theme change can be transitioned. + * + * Only the leaves get this. A registered `` property computes to a + * resolved color at the element it is declared on, so a registered + * `light-dark()` is frozen at the root's `color-scheme` and stops following a + * `color-scheme: dark` subtree. The composites therefore have to stay + * unregistered, which also rules out `initial-value`, as that may not contain + * `var()`. + * @param {Record} leaves + * @returns {Record>} + */ +function registerProperties(leaves) { + /** @type {Record>} */ + const properties = {}; + + for (const [token, color] of Object.entries(leaves)) { + properties[`@property ${namespace}${token}`] = { + syntax: '""', + // Colors are inherited, and Tailwind's own `--tw-*` internals are not, so + // this cannot be left to the default + inherits: "true", + "initial-value": color, + }; + } + + return properties; } /** @@ -305,38 +446,60 @@ function createSchemes(sourceColor, variant, specVersion) { * @param {VariantName} variant * @param {SpecVersion} specVersion * @param {Gamut} gamut + * @param {ColorsMode} colorsMode + * @param {ContrastName[]} contrasts + * @returns {{theme: ThemeConfig, base: Record>}} */ -function createTheme(sourceColor, variant, specVersion, gamut) { - const schemes = createSchemes(sourceColor, variant, specVersion); - const colors = createColors(schemes, gamut); +function createTheme( + sourceColor, + variant, + specVersion, + gamut, + colorsMode, + contrasts, +) { + const schemes = createSchemes(sourceColor, variant, specVersion, contrasts); + const { colors, leaves } = createColors(schemes, gamut, contrasts); // The palettes are the same for light and dark /** @type {PaletteArray} */ - const sourcePalettes = Object.entries(schemes.light) + const sourcePalettes = Object.entries(schemes.light ?? {}) .filter(([, value]) => value instanceof TonalPalette) // Remove "palette" postfix .map(([key, value]) => [key.replace("Palette", ""), value]); const palettes = createPalettes(sourcePalettes, gamut); - const tailwindTheme = defaultConfiguration; - // The source color is an sRGB hex the user gave us, so there is no wider // gamut version of it to recover. It is only restated in the theme's format. - const source = + leaves.source = gamut === "srgb" ? sourceColor : oklchFromArgb(argbFromHex(sourceColor)); - // Set colors - tailwindTheme.extend = { - ...tailwindTheme.extend, - colors: { - source, - ...colors, - ...palettes, - }, - }; + /** @type {Record>} */ + const themeColors = { source: reference("source"), ...colors }; + for (const [token, color] of Object.entries(palettes)) { + leaves[token] = color; + themeColors[token] = reference(token); + } - return tailwindTheme; + const theme = { ...defaultConfiguration }; + + if (colorsMode === "replace") { + // `theme.colors` replaces Tailwind's palette instead of merging with it, so + // nothing of Tailwind's is left to collide with a Material palette step. + // The color keywords (`transparent`, `current`, `inherit`) are built into + // the utilities rather than read from the theme and survive on their own, + // but black and white do come from here and are too widely used to drop. + theme.colors = { black: "#000000", white: "#ffffff", ...themeColors }; + theme.extend = { ...theme.extend }; + } else { + theme.extend = { ...theme.extend, colors: themeColors }; + } + + // Only the leaves are written out. They carry their color as `initial-value`, + // and the composites are fallbacks inside the theme values, so there is + // nothing left to declare. + return { theme, base: registerProperties(leaves) }; } class PluginOptionsUndefinedError extends Error { @@ -382,6 +545,24 @@ class UnknownGamutError extends Error { } } +class UnknownColorsModeError extends Error { + /** @param {string} colorsMode */ + constructor(colorsMode) { + super( + `"${colorsMode}" is not a way to apply the colors. Pick one of: ${colorsModes.join(", ")}.`, + ); + } +} + +class UnknownContrastError extends Error { + /** @param {string} contrast */ + constructor(contrast) { + super( + `"${contrast}" is not a Material contrast level. Pick any of: ${Object.keys(contrastLevels).join(", ")}, or "all".`, + ); + } +} + /** * Aliases accepted for a gamut, so the CSS can say what reads naturally. A Map * rather than an object so a name like "constructor" misses instead of @@ -419,68 +600,149 @@ function readOption(options, names) { return undefined; } -// This is based on code I saw in Tailwinds own plugin repositories like @tailwindcss/typography -// Types are a bit cursed right now /** - * @import {PluginCreator, PluginsConfig} from "tailwindcss/plugin" + * Reads the contrast levels to generate. Takes a list, because they are not + * exclusive, in whatever separator reads naturally: `high`, `high medium`, + * `high, medium` and `all` all work. + * @param {Record} options + * @returns {ContrastName[]} */ -/** @type {PluginsConfig} */ -const materialTailwindPlugin = plugin.withOptions( - () => { - return (_api) => {}; - }, - (options) => { - let sourceColor; - if (options === undefined) throw new PluginOptionsUndefinedError(); - if ("source-color" in options) { - sourceColor = options["source-color"]; - } else if ("sourceColor" in options) { - sourceColor = options.sourceColor; - } else if ("source" in options) { - sourceColor = options.source; - } else { - throw new PluginOptionsUndefinedError(); - } +function readContrasts(options) { + const requested = readOption(options, ["contrasts", "contrast"]); + if (requested === undefined) return [requiredContrast]; + + const names = requested + .split(/[\s,]+/) + .filter(Boolean) + .map((name) => name.toLowerCase()); + + if (names.includes("all")) + return /** @type {ContrastName[]} */ (Object.keys(contrastLevels)); + + for (const name of names) + if (!(name in contrastLevels)) throw new UnknownContrastError(name); + + // The default level is what the unqualified roles come from, so it is always + // generated. A Set keeps the rest from being generated twice if listed twice. + return [ + ...new Set( + /** @type {ContrastName[]} */ ([requiredContrast, ...names]), + ), + ]; +} + +/** + * Reads the plugin options, in either their CSS or their camelCase spelling + * @param {Record | undefined} options + * @returns {{sourceColor: string, variant: VariantName, specVersion: SpecVersion, gamut: Gamut, colorsMode: ColorsMode, contrasts: ContrastName[]}} + */ +function resolveOptions(options) { + if (options === undefined) throw new PluginOptionsUndefinedError(); + + const sourceColor = readOption(options, [ + "source-color", + "sourceColor", + "source", + ]); + if (sourceColor === undefined) throw new SourceColorUndefinedError(); + + /** @type {VariantName} */ + let variant = defaultVariant; + const requestedVariant = readOption(options, ["variant", "style"]); + if (requestedVariant !== undefined) { + // Accept "tonalSpot" as well as "tonal-spot" + const name = camelToKebabCase(requestedVariant.trim()).toLowerCase(); + if (!(name in variants)) throw new UnknownVariantError(requestedVariant); + + variant = /** @type {VariantName} */ (name); + } - /** @type {VariantName} */ - let variantName = defaultVariant; - const variant = readOption(options, ["variant", "style"]); - if (variant !== undefined) { - // Accept "tonalSpot" as well as "tonal-spot" - const name = camelToKebabCase(variant.trim()).toLowerCase(); - if (!(name in variants)) throw new UnknownVariantError(variant); + const specVersion = + readOption(options, ["spec-version", "specVersion", "spec"]) ?? + defaultSpecVersion; + if (!specVersions.includes(specVersion)) + throw new UnknownSpecVersionError(specVersion); + + /** @type {Gamut} */ + let gamut = defaultGamut; + const requestedGamut = readOption(options, [ + "gamut", + "color-gamut", + "colorGamut", + ]); + if (requestedGamut !== undefined) { + const alias = gamutAliases.get(requestedGamut.trim().toLowerCase()); + if (alias === undefined) throw new UnknownGamutError(requestedGamut); + + gamut = alias; + } - variantName = /** @type {VariantName} */ (name); - } + /** @type {ColorsMode} */ + let colorsMode = defaultColorsMode; + const requestedColorsMode = readOption(options, ["colors", "colorsMode"]); + if (requestedColorsMode !== undefined) { + const name = requestedColorsMode.trim().toLowerCase(); + if (!colorsModes.includes(name)) + throw new UnknownColorsModeError(requestedColorsMode); - const specVersion = - readOption(options, ["spec-version", "specVersion", "spec"]) ?? - defaultSpecVersion; - if (!specVersions.includes(specVersion)) - throw new UnknownSpecVersionError(specVersion); - - /** @type {Gamut} */ - let gamut = defaultGamut; - const requestedGamut = readOption(options, [ - "gamut", - "color-gamut", - "colorGamut", - ]); - if (requestedGamut !== undefined) { - const alias = gamutAliases.get(requestedGamut.trim().toLowerCase()); - if (alias === undefined) throw new UnknownGamutError(requestedGamut); - - gamut = alias; - } + colorsMode = /** @type {ColorsMode} */ (name); + } - const tailwindTheme = createTheme( - sourceColor, - variantName, - /** @type {SpecVersion} */ (specVersion), - gamut, + return { + sourceColor, + variant, + specVersion: /** @type {SpecVersion} */ (specVersion), + gamut, + colorsMode, + contrasts: readContrasts(options), + }; +} + +/** + * `plugin.withOptions` calls one function for the theme and another for the + * base styles, and both need the same generated colors. Solving a whole theme + * is not cheap, so it is done once per distinct set of options. + * @type {Map>} + */ +const themes = new Map(); + +/** + * @param {Record | undefined} options + * @returns {ReturnType} + */ +function build(options) { + const resolved = resolveOptions(options); + const key = JSON.stringify(resolved); + + let theme = themes.get(key); + if (theme === undefined) { + theme = createTheme( + resolved.sourceColor, + resolved.variant, + resolved.specVersion, + resolved.gamut, + resolved.colorsMode, + resolved.contrasts, ); - return { theme: tailwindTheme }; + themes.set(key, theme); + } + + return theme; +} + +// This is based on code I saw in Tailwinds own plugin repositories like @tailwindcss/typography +// Types are a bit cursed right now +/** + * @import {PluginCreator, PluginsConfig} from "tailwindcss/plugin" + */ +/** @type {PluginsConfig} */ +const materialTailwindPlugin = plugin.withOptions( + (options) => (api) => { + // `addBase` is the only place a plugin can put a declaration, so the + // variables the theme references are defined from here + api.addBase(build(options).base); }, + (options) => ({ theme: build(options).theme }), ); export default materialTailwindPlugin; diff --git a/index.test.js b/index.test.js index 93772d9..509b9ca 100644 --- a/index.test.js +++ b/index.test.js @@ -2,20 +2,222 @@ import { expect, it } from "vitest"; import materialTailwind from "."; /** + * The theme values are `var()` references now, so the literal a color resolves + * to lives in the variable the plugin registers through `addBase` rather than + * in the theme. This collects both sides. + * @param {Record} options + * @returns {{references: Record, variables: Record, base: Record}} + */ +function createTheme(options) { + const plugin = materialTailwind({ sourceColor: "#0c1445", ...options }); + + /** @type {Record} */ + let base = {}; + plugin.handler( + /** @type {any} */ ({ + addBase(/** @type {Record} */ rules) { + base = rules; + }, + }), + ); + + /** @type {Record} */ + const variables = {}; + for (const [selector, declarations] of Object.entries(base)) + if (selector.startsWith("@property ")) + variables[selector.slice("@property ".length)] = + declarations["initial-value"]; + + const theme = plugin.config.theme; + + return { references: theme.colors ?? theme.extend.colors, variables, base }; +} + +/** + * A theme value is one of two shapes: a bare reference to a registered leaf, or + * a reference to a composite that is never defined, so what it actually shows is + * the fallback. + * @param {string} value + * @returns {{name: string, fallback: string | undefined}} + */ +function parseReference(value) { + const match = /^var\((--color-[a-z0-9-]+)(?:, (.+))?\)$/.exec(value); + if (match === null) throw new Error(`Not a variable reference: ${value}`); + + return { name: match[1], fallback: match[2] }; +} + +/** + * The color a theme key ends up showing, following the reference and anything + * its fallback is composed out of. * @param {Record} options * @returns {Record} */ function createColors(options) { - return materialTailwind({ sourceColor: "#0c1445", ...options }).config.theme - .extend.colors; + const { references, variables } = createTheme(options); + + /** + * @param {string} value + * @returns {string} + */ + const resolve = (value) => { + // `black` and `white` are literals the replace mode adds back, not tokens + if (!value.startsWith("var(")) return value; + + const { name, fallback } = parseReference(value); + // Nothing defines a composite, so a fallback is always what applies + const resolved = fallback ?? variables[name] ?? `UNDEFINED(${name})`; + + return resolved.replace( + /var\((--color-[a-z0-9-]+)\)/g, + (_, nested) => variables[nested] ?? `UNDEFINED(${nested})`, + ); + }; + + /** @type {Record} */ + const colors = {}; + for (const [name, value] of Object.entries(references)) { + if (typeof value === "string") { + colors[name] = resolve(value); + continue; + } + + /** @type {Record} */ + const scheme = {}; + for (const [role, reference] of Object.entries(value)) + scheme[role] = resolve(/** @type {string} */ (reference)); + + colors[name] = scheme; + } + + return colors; } // This test is rather simple and more of a smoke test to ensure in CI that we build the dependency correctly it("Can create a Material design TailwindCSS configuration", async () => { const plugin = materialTailwind({ sourceColor: "#0c1445" }); + const { variables } = createTheme({}); + + // The theme only holds references now, so snapshotting it alone would stop + // catching a color changing. The variables are where the colors went. + const json = JSON.stringify( + { theme: plugin.config.theme, variables }, + null, + 2, + ); + await expect(json).toMatchFileSnapshot("./theme test.snapshot.json"); +}); + +it("Resolves every theme color to something defined", () => { + const { references, variables } = createTheme({}); + + /** @type {string[]} */ + const values = []; + for (const value of Object.values(references)) + if (typeof value === "string") values.push(value); + else values.push(...Object.values(value)); + + expect(values.length).toBeGreaterThan(0); + for (const value of values) { + const { name, fallback } = parseReference(value); + + // Either the variable is registered, or it has a fallback whose own + // references are. Anything else silently resolves to nothing. + if (fallback === undefined) { + expect(variables).toHaveProperty([name]); + continue; + } + + for (const [, nested] of fallback.matchAll(/var\((--color-[a-z0-9-]+)\)/g)) + expect(variables).toHaveProperty([nested]); + } +}); + +it("Composes the light-dark() colors out of the per-scheme variables", () => { + const { references } = createTheme({ contrasts: "high" }); + + // Restating the literals here would mean an override of the light color did + // not move the color that uses it + expect(references.primary).toBe( + "var(--color-primary, light-dark(var(--color-light-primary), var(--color-dark-primary)))", + ); + expect(references["high-contrast-on-surface"]).toBe( + "var(--color-high-contrast-on-surface, light-dark(var(--color-light-high-contrast-on-surface), var(--color-dark-high-contrast-on-surface)))", + ); +}); + +it("Declares nothing, so a user's @theme override still wins", () => { + const { base } = createTheme({}); + + // A declaration would land in @layer base, which beats the @layer theme an + // `@theme` override lands in, and would silently ignore it. Registering a + // property is not a declaration and does not have that problem. + for (const selector of Object.keys(base)) + expect(selector).toMatch(/^@property --color-/); +}); + +it("Registers the literal colors, but never a light-dark() one", () => { + const { base } = createTheme({ contrasts: "all" }); + + let registered = 0; + for (const declarations of Object.values(base)) { + registered++; + expect(declarations.syntax).toBe('""'); + // Colors inherit, and an unregistered composite reading a registered leaf + // depends on it + expect(declarations.inherits).toBe("true"); + // A registered resolves light-dark() against the root's + // color-scheme and then stops following a dark subtree, so a composite must + // not be registered. An initial-value may not hold a var() either. + expect(declarations["initial-value"]).not.toMatch(/light-dark\(|var\(/); + } + + expect(registered).toBeGreaterThan(500); +}); + +it("Generates only the default contrast unless asked", () => { + const colors = createColors({}); - const themeJson = JSON.stringify(plugin.config.theme, null, 2); - await expect(themeJson).toMatchFileSnapshot("./theme test.snapshot.json"); + expect(colors.primary).toBeDefined(); + expect(colors.light.primary).toBeDefined(); + expect(colors["high-contrast-primary"]).toBeUndefined(); + expect(colors["light-high-contrast"]).toBeUndefined(); +}); + +it("Adds the contrast levels it is asked for", () => { + const colors = createColors({ contrasts: "high" }); + + expect(colors["high-contrast-primary"]).toMatch( + /^light-dark\(#[0-9a-f]{6}, #[0-9a-f]{6}\)$/, + ); + expect(colors["light-high-contrast"].primary).toMatch(/^#[0-9a-f]{6}$/); + // The unqualified roles come from the default level, so it is always there + expect(colors.primary).toBeDefined(); + expect(colors["medium-contrast-primary"]).toBeUndefined(); +}); + +it.each(["high medium", "high,medium", "high, medium"])( + "Takes a list of contrast levels as %o", + (contrasts) => { + const colors = createColors({ contrasts }); + + expect(colors["high-contrast-primary"]).toBeDefined(); + expect(colors["medium-contrast-primary"]).toBeDefined(); + expect(colors["reduced-contrast-primary"]).toBeUndefined(); + }, +); + +it("Generates every contrast level for all", () => { + const colors = createColors({ contrasts: "all" }); + + for (const prefix of ["", "reduced-contrast-", "medium-contrast-", "high-contrast-"]) + expect(colors[`${prefix}primary`]).toBeDefined(); +}); + +it("Rejects an unknown contrast level", () => { + expect(() => createColors({ contrasts: "extreme" })).toThrowError( + /not a Material contrast level/, + ); }); const variants = [ @@ -91,6 +293,49 @@ it("Rejects an unknown variant or spec version", () => { ); }); +it("Extends Tailwind's colors by default, and replaces them when asked", () => { + const extended = materialTailwind({ sourceColor: "#0c1445" }).config.theme; + expect(extended.extend.colors).toBeDefined(); + // Leaving `colors` unset is what keeps Tailwind's own palette + expect(extended.colors).toBeUndefined(); + + const replaced = materialTailwind({ + sourceColor: "#0c1445", + colors: "replace", + }).config.theme; + expect(replaced.colors).toBeDefined(); + expect(replaced.extend.colors).toBeUndefined(); + // The other parts of the theme still only extend + expect(replaced.extend.borderRadius).toBeDefined(); +}); + +it("Keeps black and white when replacing, as those come from the palette", () => { + // `transparent`, `current` and `inherit` are built into the utilities and + // survive on their own, but these two are read from the theme + const { colors } = materialTailwind({ + sourceColor: "#0c1445", + colors: "replace", + }).config.theme; + + expect(colors.black).toBe("#000000"); + expect(colors.white).toBe("#ffffff"); +}); + +it("Names the same colors whether extending or replacing", () => { + const names = (/** @type {Record} */ options) => + Object.keys(createColors(options)).sort(); + + expect(names({ colors: "replace" }).filter((n) => n !== "black" && n !== "white")).toStrictEqual( + names({}), + ); +}); + +it("Rejects an unknown way to apply the colors", () => { + expect(() => createColors({ colors: "merge" })).toThrowError( + /not a way to apply the colors/, + ); +}); + /** Matches an `oklch()` value with a lightness, a chroma and a hue */ const oklch = /^oklch\(\d+(\.\d+)? \d+(\.\d+)? \d+(\.\d+)?\)$/; diff --git a/theme test.snapshot.json b/theme test.snapshot.json index 18bd188..079fe7c 100644 --- a/theme test.snapshot.json +++ b/theme test.snapshot.json @@ -1,1035 +1,723 @@ { - "extend": { - "borderRadius": { - "extra-small": "0.25rem", - "small": "0.5rem", - "medium": "0.75rem", - "large": "1rem", - "extra-large": "1.75rem" - }, - "boxShadow": { - "elevation-light-level-1": "0px 1px 3px 1px rgba(0, 0, 0, 0.15), 0px 1px 2px 0px rgba(0, 0, 0, 0.3)", - "elevation-light-level-2": "0px 2px 6px 2px rgba(0, 0, 0, 0.15), 0px 1px 2px 0px rgba(0, 0, 0, 0.3)", - "elevation-light-level-3": "0px 1px 3px 0px rgba(0, 0, 0, 0.3), 0px 4px 8px 3px rgba(0, 0, 0, 0.15)", - "elevation-light-level-4": "0px 2px 3px 0px rgba(0, 0, 0, 0.3), 0px 6px 10px 4px rgba(0, 0, 0, 0.15)", - "elevation-light-level-5": " 0px 4px 4px 0px rgba(0, 0, 0, 0.3), 0px 8px 12px 6px rgba(0, 0, 0, 0.15)", - "elevation-dark-level-1": "0px 1px 2px 0px rgba(0, 0, 0, 0.3), 0px 1px 3px 1px rgba(0, 0, 0, 0.15)", - "elevation-dark-level-2": "0px 1px 2px 0px rgba(0, 0, 0, 0.3), 0px 2px 6px 2px rgba(0, 0, 0, 0.15)", - "elevation-dark-level-3": "0px 1px 3px 0px rgba(0, 0, 0, 0.3), 0px 4px 8px 3px rgba(0, 0, 0, 0.15)", - "elevation-dark-level-4": "0px 2px 3px 0px rgba(0, 0, 0, 0.3), 0px 6px 10px 4px rgba(0, 0, 0, 0.15)", - "elevation-dark-level-5": "0px 4px 4px 0px rgba(0, 0, 0, 0.3), 0px 8px 12px 6px rgba(0, 0, 0, 0.15)" - }, - "fontSize": { - "display-lg": [ - "3.5625rem", - { - "fontWeight": "400", - "lineHeight": "4rem" - } - ], - "display-md": [ - "2.8125rem", - { - "fontWeight": "400", - "lineHeight": "3.25rem" - } - ], - "display-sm": [ - "2.25rem", - { - "fontWeight": "400", - "lineHeight": "2.75rem" - } - ], - "headline-lg": [ - "2rem", - { - "fontWeight": "400", - "lineHeight": "2.5rem" - } - ], - "headline-md": [ - "1.75rem", - { - "fontWeight": "400", - "lineHeight": "2.25rem" - } - ], - "headline-sm": [ - "1.5rem", - { - "fontWeight": "400", - "lineHeight": "2rem" - } - ], - "body-lg": [ - "1rem", - { - "fontWeight": "400", - "lineHeight": "1.5rem" - } - ], - "body-md": [ - "0.875rem", - { - "fontWeight": "400", - "lineHeight": "1.25rem" - } - ], - "body-sm": [ - "0.75rem", - { - "fontWeight": "400", - "lineHeight": "1rem" - } - ], - "label-lg": [ - "0.875rem", - { - "fontWeight": "500", - "lineHeight": "1.25rem" - } - ], - "label-md": [ - "0.75rem", - { - "fontWeight": "500", - "lineHeight": "1rem" - } - ], - "label-sm": [ - "0.675rem", - { - "fontWeight": "500", - "lineHeight": "1rem" - } - ], - "title-lg": [ - "1.375rem", - { - "fontWeight": "400", - "lineHeight": "1.75rem" - } - ], - "title-md": [ - "1rem", - { - "fontWeight": "500", - "lineHeight": "1.5rem" - } - ], - "title-sm": [ - "0.875rem", - { - "fontWeight": "500", - "lineHeight": "1.25rem" - } - ] - }, - "fontWeight": { - "display-lg": "400", - "display-md": "400", - "display-sm": "400", - "headline-lg": "400", - "headline-md": "400", - "headline-sm": "400", - "body-lg": "400", - "body-md": "400", - "body-sm": "400", - "label-lg": "500", - "label-md": "500", - "label-sm": "500", - "title-lg": "400", - "title-md": "500", - "title-sm": "500" - }, - "lineHeight": { - "display-lg": "4rem", - "display-md": "3.25rem", - "display-sm": "2.75rem", - "headline-lg": "2.5rem", - "headline-md": "2.25rem", - "headline-sm": "2rem", - "body-lg": "1.5rem", - "body-md": "1.25rem", - "body-sm": "1rem", - "label-lg": "1.25rem", - "label-md": "1rem", - "label-sm": "1rem", - "title-lg": "1.75rem", - "title-md": "1.5rem", - "title-sm": "1.25rem" - }, - "transitionDuration": { - "none": "0ms", - "short-1": "50ms", - "short-2": "100ms", - "short-3": "150ms", - "short-4": "200ms", - "medium-1": "250ms", - "medium-2": "300ms", - "medium-3": "350ms", - "medium-4": "400ms", - "long-1": "450ms", - "long-2": "500ms", - "long-3": "550ms", - "long-4": "600ms", - "extra-long-1": "700ms", - "extra-long-2": "800ms", - "extra-long-3": "900ms", - "extra-long-4": "1s" - }, - "zIndex": { - "elevation-level-0": "0", - "elevation-level-1": "1", - "elevation-level-2": "3", - "elevation-level-3": "6", - "elevation-level-4": "8", - "elevation-level-5": "12" - }, - "transitionTimingFunction": { - "standard": "cubic-bezier(0.2, 0, 0, 1)", - "accelerate": "cubic-bezier(0.3, 0, 1, 1)", - "decelerate": "cubic-bezier(0, 0, 0, 1)", - "linear": "linear", - "emphasized": "linear(\n 0,\n 0.002,\n 0.01 3.6%,\n 0.034,\n 0.074 9.1%,\n 0.128 11.4%,\n 0.194 13.4%,\n 0.271 15%,\n 0.344 16.1%,\n 0.544,\n 0.66 20.6%,\n 0.717 22.4%,\n 0.765 24.6%,\n 0.808 27.3%,\n 0.845 30.4%,\n 0.883 35.1%,\n 0.916 40.6%,\n 0.942 47.2%,\n 0.963 55%,\n 0.979 64%,\n 0.991 74.4%,\n 0.998 86.4%,\n 1\n )", - "emphasized-accelerate": "cubic-bezier(0.3, 0, 0.8, 0.15)", - "emphasized-decelerate": "cubic-bezier(0.05, 0.7, 0.1, 1)" - }, - "colors": { - "source": "#0c1445", - "light-reduced-contrast": { - "primary-palette-key-color": "#6b73ad", - "secondary-palette-key-color": "#74768c", - "tertiary-palette-key-color": "#926c86", - "neutral-palette-key-color": "#77767d", - "neutral-variant-palette-key-color": "#767680", - "error-palette-key-color": "#de3730", - "background": "#fbf8ff", - "on-background": "#908f96", - "surface": "#fbf8ff", - "surface-dim": "#dbd9e0", - "surface-bright": "#fbf8ff", - "surface-container-lowest": "#ffffff", - "surface-container-low": "#f5f2fa", - "surface-container": "#efedf4", - "surface-container-high": "#e9e7ef", - "surface-container-highest": "#e4e1e9", - "on-surface": "#5f5e65", - "surface-variant": "#e3e1ec", - "on-surface-variant": "#7a7a83", - "outline": "#b2b1bb", - "outline-variant": "#d9d8e2", - "inverse-surface": "#303036", - "inverse-on-surface": "#99979e", - "shadow": "#000000", - "scrim": "#000000", - "surface-tint": "#525a92", - "primary": "#6971aa", - "primary-dim": "#5c649c", - "on-primary": "#fffbff", - "primary-container": "#d3d6ff", - "on-primary-container": "#6e76b0", - "inverse-primary": "#6e76b0", - "primary-fixed": "#d3d6ff", - "primary-fixed-dim": "#b1b9f8", - "on-primary-fixed": "#40487e", - "on-primary-fixed-variant": "#5a629b", - "secondary": "#717389", - "secondary-dim": "#65667b", - "on-secondary": "#fffbff", - "secondary-container": "#d6d7f0", - "on-secondary-container": "#77788e", - "secondary-fixed": "#d6d7f0", - "secondary-fixed-dim": "#babbd3", - "on-secondary-fixed": "#494b5f", - "on-secondary-fixed-variant": "#63657a", - "tertiary": "#8f6983", - "tertiary-dim": "#815d76", - "on-tertiary": "#fffbff", - "tertiary-container": "#f9ccea", - "on-tertiary-container": "#956e89", - "tertiary-fixed": "#f9ccea", - "tertiary-fixed-dim": "#dcb0cd", - "on-tertiary-fixed": "#63425a", - "on-tertiary-fixed-variant": "#805b75", - "error": "#da342e", - "error-dim": "#c82623", - "on-error": "#fffbff", - "error-container": "#ffcdc7", - "on-error-container": "#e23a32" + "theme": { + "extend": { + "borderRadius": { + "extra-small": "0.25rem", + "small": "0.5rem", + "medium": "0.75rem", + "large": "1rem", + "extra-large": "1.75rem" }, - "light": { - "primary-palette-key-color": "#6b73ad", - "secondary-palette-key-color": "#74768c", - "tertiary-palette-key-color": "#926c86", - "neutral-palette-key-color": "#77767d", - "neutral-variant-palette-key-color": "#767680", - "error-palette-key-color": "#de3730", - "background": "#fbf8ff", - "on-background": "#1b1b21", - "surface": "#fbf8ff", - "surface-dim": "#dbd9e0", - "surface-bright": "#fbf8ff", - "surface-container-lowest": "#ffffff", - "surface-container-low": "#f5f2fa", - "surface-container": "#efedf4", - "surface-container-high": "#e9e7ef", - "surface-container-highest": "#e4e1e9", - "on-surface": "#1b1b21", - "surface-variant": "#e3e1ec", - "on-surface-variant": "#46464f", - "outline": "#767680", - "outline-variant": "#c7c5d0", - "inverse-surface": "#303036", - "inverse-on-surface": "#f2eff7", - "shadow": "#000000", - "scrim": "#000000", - "surface-tint": "#525a92", - "primary": "#525a92", - "primary-dim": "#464e85", - "on-primary": "#ffffff", - "primary-container": "#dfe0ff", - "on-primary-container": "#3a4279", - "inverse-primary": "#bbc3ff", - "primary-fixed": "#dfe0ff", - "primary-fixed-dim": "#bbc3ff", - "on-primary-fixed": "#0c154b", - "on-primary-fixed-variant": "#3a4279", - "secondary": "#5b5d72", - "secondary-dim": "#4f5165", - "on-secondary": "#ffffff", - "secondary-container": "#e0e1f9", - "on-secondary-container": "#434559", - "secondary-fixed": "#e0e1f9", - "secondary-fixed-dim": "#c4c5dd", - "on-secondary-fixed": "#181a2c", - "on-secondary-fixed-variant": "#434559", - "tertiary": "#77536c", - "tertiary-dim": "#6a4860", - "on-tertiary": "#ffffff", - "tertiary-container": "#ffd7f0", - "on-tertiary-container": "#5d3c54", - "tertiary-fixed": "#ffd7f0", - "tertiary-fixed-dim": "#e6bad7", - "on-tertiary-fixed": "#2d1227", - "on-tertiary-fixed-variant": "#5d3c54", - "error": "#ba1a1a", - "error-dim": "#a80710", - "on-error": "#ffffff", - "error-container": "#ffdad6", - "on-error-container": "#93000a" + "boxShadow": { + "elevation-light-level-1": "0px 1px 3px 1px rgba(0, 0, 0, 0.15), 0px 1px 2px 0px rgba(0, 0, 0, 0.3)", + "elevation-light-level-2": "0px 2px 6px 2px rgba(0, 0, 0, 0.15), 0px 1px 2px 0px rgba(0, 0, 0, 0.3)", + "elevation-light-level-3": "0px 1px 3px 0px rgba(0, 0, 0, 0.3), 0px 4px 8px 3px rgba(0, 0, 0, 0.15)", + "elevation-light-level-4": "0px 2px 3px 0px rgba(0, 0, 0, 0.3), 0px 6px 10px 4px rgba(0, 0, 0, 0.15)", + "elevation-light-level-5": " 0px 4px 4px 0px rgba(0, 0, 0, 0.3), 0px 8px 12px 6px rgba(0, 0, 0, 0.15)", + "elevation-dark-level-1": "0px 1px 2px 0px rgba(0, 0, 0, 0.3), 0px 1px 3px 1px rgba(0, 0, 0, 0.15)", + "elevation-dark-level-2": "0px 1px 2px 0px rgba(0, 0, 0, 0.3), 0px 2px 6px 2px rgba(0, 0, 0, 0.15)", + "elevation-dark-level-3": "0px 1px 3px 0px rgba(0, 0, 0, 0.3), 0px 4px 8px 3px rgba(0, 0, 0, 0.15)", + "elevation-dark-level-4": "0px 2px 3px 0px rgba(0, 0, 0, 0.3), 0px 6px 10px 4px rgba(0, 0, 0, 0.15)", + "elevation-dark-level-5": "0px 4px 4px 0px rgba(0, 0, 0, 0.3), 0px 8px 12px 6px rgba(0, 0, 0, 0.15)" }, - "light-medium-contrast": { - "primary-palette-key-color": "#6b73ad", - "secondary-palette-key-color": "#74768c", - "tertiary-palette-key-color": "#926c86", - "neutral-palette-key-color": "#77767d", - "neutral-variant-palette-key-color": "#767680", - "error-palette-key-color": "#de3730", - "background": "#fbf8ff", - "on-background": "#1b1b21", - "surface": "#fbf8ff", - "surface-dim": "#c7c5cd", - "surface-bright": "#fbf8ff", - "surface-container-lowest": "#ffffff", - "surface-container-low": "#f5f2fa", - "surface-container": "#e9e7ef", - "surface-container-high": "#dedce3", - "surface-container-highest": "#d3d0d8", - "on-surface": "#101116", - "surface-variant": "#e3e1ec", - "on-surface-variant": "#35353e", - "outline": "#52525b", - "outline-variant": "#6c6c76", - "inverse-surface": "#303036", - "inverse-on-surface": "#f2eff7", - "shadow": "#000000", - "scrim": "#000000", - "surface-tint": "#525a92", - "primary": "#293267", - "primary-dim": "#2d356a", - "on-primary": "#ffffff", - "primary-container": "#6169a2", - "on-primary-container": "#ffffff", - "inverse-primary": "#bbc3ff", - "primary-fixed": "#6169a2", - "primary-fixed-dim": "#495188", - "on-primary-fixed": "#ffffff", - "on-primary-fixed-variant": "#ffffff", - "secondary": "#333548", - "secondary-dim": "#36384b", - "on-secondary": "#ffffff", - "secondary-container": "#6a6c81", - "on-secondary-container": "#ffffff", - "secondary-fixed": "#6a6c81", - "secondary-fixed-dim": "#515368", - "on-secondary-fixed": "#ffffff", - "on-secondary-fixed-variant": "#ffffff", - "tertiary": "#4b2c43", - "tertiary-dim": "#4e2f46", - "on-tertiary": "#ffffff", - "tertiary-container": "#87627c", - "on-tertiary-container": "#ffffff", - "tertiary-fixed": "#87627c", - "tertiary-fixed-dim": "#6d4a63", - "on-tertiary-fixed": "#ffffff", - "on-tertiary-fixed-variant": "#ffffff", - "error": "#740006", - "error-dim": "#790006", - "on-error": "#ffffff", - "error-container": "#cf2c27", - "on-error-container": "#ffffff" + "fontSize": { + "display-lg": [ + "3.5625rem", + { + "fontWeight": "400", + "lineHeight": "4rem" + } + ], + "display-md": [ + "2.8125rem", + { + "fontWeight": "400", + "lineHeight": "3.25rem" + } + ], + "display-sm": [ + "2.25rem", + { + "fontWeight": "400", + "lineHeight": "2.75rem" + } + ], + "headline-lg": [ + "2rem", + { + "fontWeight": "400", + "lineHeight": "2.5rem" + } + ], + "headline-md": [ + "1.75rem", + { + "fontWeight": "400", + "lineHeight": "2.25rem" + } + ], + "headline-sm": [ + "1.5rem", + { + "fontWeight": "400", + "lineHeight": "2rem" + } + ], + "body-lg": [ + "1rem", + { + "fontWeight": "400", + "lineHeight": "1.5rem" + } + ], + "body-md": [ + "0.875rem", + { + "fontWeight": "400", + "lineHeight": "1.25rem" + } + ], + "body-sm": [ + "0.75rem", + { + "fontWeight": "400", + "lineHeight": "1rem" + } + ], + "label-lg": [ + "0.875rem", + { + "fontWeight": "500", + "lineHeight": "1.25rem" + } + ], + "label-md": [ + "0.75rem", + { + "fontWeight": "500", + "lineHeight": "1rem" + } + ], + "label-sm": [ + "0.675rem", + { + "fontWeight": "500", + "lineHeight": "1rem" + } + ], + "title-lg": [ + "1.375rem", + { + "fontWeight": "400", + "lineHeight": "1.75rem" + } + ], + "title-md": [ + "1rem", + { + "fontWeight": "500", + "lineHeight": "1.5rem" + } + ], + "title-sm": [ + "0.875rem", + { + "fontWeight": "500", + "lineHeight": "1.25rem" + } + ] }, - "light-high-contrast": { - "primary-palette-key-color": "#6b73ad", - "secondary-palette-key-color": "#74768c", - "tertiary-palette-key-color": "#926c86", - "neutral-palette-key-color": "#77767d", - "neutral-variant-palette-key-color": "#767680", - "error-palette-key-color": "#de3730", - "background": "#fbf8ff", - "on-background": "#1b1b21", - "surface": "#fbf8ff", - "surface-dim": "#b9b8bf", - "surface-bright": "#fbf8ff", - "surface-container-lowest": "#ffffff", - "surface-container-low": "#f2eff7", - "surface-container": "#e4e1e9", - "surface-container-high": "#d5d3db", - "surface-container-highest": "#c7c5cd", - "on-surface": "#000000", - "surface-variant": "#e3e1ec", - "on-surface-variant": "#000000", - "outline": "#2b2c34", - "outline-variant": "#484851", - "inverse-surface": "#303036", - "inverse-on-surface": "#ffffff", - "shadow": "#000000", - "scrim": "#000000", - "surface-tint": "#525a92", - "primary": "#1f275c", - "primary-dim": "#11194f", - "on-primary": "#ffffff", - "primary-container": "#3d457b", - "on-primary-container": "#ffffff", - "inverse-primary": "#bbc3ff", - "primary-fixed": "#3d457b", - "primary-fixed-dim": "#262e63", - "on-primary-fixed": "#ffffff", - "on-primary-fixed-variant": "#ffffff", - "secondary": "#292b3d", - "secondary-dim": "#1c1e30", - "on-secondary": "#ffffff", - "secondary-container": "#46485c", - "on-secondary-container": "#ffffff", - "secondary-fixed": "#46485c", - "secondary-fixed-dim": "#2f3144", - "on-secondary-fixed": "#ffffff", - "on-secondary-fixed-variant": "#ffffff", - "tertiary": "#402239", - "tertiary-dim": "#32152b", - "on-tertiary": "#ffffff", - "tertiary-container": "#603f57", - "on-tertiary-container": "#ffffff", - "tertiary-fixed": "#603f57", - "tertiary-fixed-dim": "#47283f", - "on-tertiary-fixed": "#ffffff", - "on-tertiary-fixed-variant": "#ffffff", - "error": "#600004", - "error-dim": "#480002", - "on-error": "#ffffff", - "error-container": "#98000a", - "on-error-container": "#ffffff" + "fontWeight": { + "display-lg": "400", + "display-md": "400", + "display-sm": "400", + "headline-lg": "400", + "headline-md": "400", + "headline-sm": "400", + "body-lg": "400", + "body-md": "400", + "body-sm": "400", + "label-lg": "500", + "label-md": "500", + "label-sm": "500", + "title-lg": "400", + "title-md": "500", + "title-sm": "500" }, - "dark-reduced-contrast": { - "primary-palette-key-color": "#6b73ad", - "secondary-palette-key-color": "#74768c", - "tertiary-palette-key-color": "#926c86", - "neutral-palette-key-color": "#77767d", - "neutral-variant-palette-key-color": "#767680", - "error-palette-key-color": "#de3730", - "background": "#131318", - "on-background": "#626268", - "surface": "#131318", - "surface-dim": "#131318", - "surface-bright": "#39393f", - "surface-container-lowest": "#0d0e13", - "surface-container-low": "#1b1b21", - "surface-container": "#1f1f25", - "surface-container-high": "#29292f", - "surface-container-highest": "#34343a", - "on-surface": "#a3a2a9", - "surface-variant": "#46464f", - "on-surface-variant": "#83828c", - "outline": "#53535c", - "outline-variant": "#393942", - "inverse-surface": "#e4e1e9", - "inverse-on-surface": "#64646a", - "shadow": "#000000", - "scrim": "#000000", - "surface-tint": "#bbc3ff", - "primary": "#858dc8", - "primary-dim": "#858dc9", - "on-primary": "#1c255a", - "primary-container": "#2d366b", - "on-primary-container": "#7880bb", - "inverse-primary": "#757db7", - "primary-fixed": "#454d84", - "primary-fixed-dim": "#2d366b", - "on-primary-fixed": "#b8c0ff", - "on-primary-fixed-variant": "#949cd9", - "secondary": "#8e8fa6", - "secondary-dim": "#8e90a6", - "on-secondary": "#26283b", - "secondary-container": "#37394c", - "on-secondary-container": "#818399", - "secondary-fixed": "#4e5064", - "secondary-fixed-dim": "#37394c", - "on-secondary-fixed": "#c1c2da", - "on-secondary-fixed-variant": "#9d9eb5", - "tertiary": "#ad85a0", - "tertiary-dim": "#ad85a0", - "on-tertiary": "#3d2036", - "tertiary-container": "#4f3047", - "on-tertiary-container": "#9f7893", - "tertiary-fixed": "#68465f", - "tertiary-fixed-dim": "#4f3047", - "on-tertiary-fixed": "#e3b7d4", - "on-tertiary-fixed-variant": "#bd94b0", - "error": "#ff5449", - "error-dim": "#ff554a", - "on-error": "#5c0003", - "error-container": "#7b0007", - "on-error-container": "#f0443b" + "lineHeight": { + "display-lg": "4rem", + "display-md": "3.25rem", + "display-sm": "2.75rem", + "headline-lg": "2.5rem", + "headline-md": "2.25rem", + "headline-sm": "2rem", + "body-lg": "1.5rem", + "body-md": "1.25rem", + "body-sm": "1rem", + "label-lg": "1.25rem", + "label-md": "1rem", + "label-sm": "1rem", + "title-lg": "1.75rem", + "title-md": "1.5rem", + "title-sm": "1.25rem" }, - "dark": { - "primary-palette-key-color": "#6b73ad", - "secondary-palette-key-color": "#74768c", - "tertiary-palette-key-color": "#926c86", - "neutral-palette-key-color": "#77767d", - "neutral-variant-palette-key-color": "#767680", - "error-palette-key-color": "#de3730", - "background": "#131318", - "on-background": "#e4e1e9", - "surface": "#131318", - "surface-dim": "#131318", - "surface-bright": "#39393f", - "surface-container-lowest": "#0d0e13", - "surface-container-low": "#1b1b21", - "surface-container": "#1f1f25", - "surface-container-high": "#29292f", - "surface-container-highest": "#34343a", - "on-surface": "#e4e1e9", - "surface-variant": "#46464f", - "on-surface-variant": "#c7c5d0", - "outline": "#90909a", - "outline-variant": "#46464f", - "inverse-surface": "#e4e1e9", - "inverse-on-surface": "#303036", - "shadow": "#000000", - "scrim": "#000000", - "surface-tint": "#bbc3ff", - "primary": "#bbc3ff", - "primary-dim": "#b8c0ff", - "on-primary": "#232c61", - "primary-container": "#3a4279", - "on-primary-container": "#dfe0ff", - "inverse-primary": "#525a92", - "primary-fixed": "#dfe0ff", - "primary-fixed-dim": "#bbc3ff", - "on-primary-fixed": "#0c154b", - "on-primary-fixed-variant": "#3a4279", - "secondary": "#c4c5dd", - "secondary-dim": "#dadbf4", - "on-secondary": "#2d2f42", - "secondary-container": "#434559", - "on-secondary-container": "#e0e1f9", - "secondary-fixed": "#e0e1f9", - "secondary-fixed-dim": "#c4c5dd", - "on-secondary-fixed": "#181a2c", - "on-secondary-fixed-variant": "#434559", - "tertiary": "#e6bad7", - "tertiary-dim": "#fed0ee", - "on-tertiary": "#45263d", - "tertiary-container": "#5d3c54", - "on-tertiary-container": "#ffd7f0", - "tertiary-fixed": "#ffd7f0", - "tertiary-fixed-dim": "#e6bad7", - "on-tertiary-fixed": "#2d1227", - "on-tertiary-fixed-variant": "#5d3c54", - "error": "#ffb4ab", - "error-dim": "#ff554a", - "on-error": "#690005", - "error-container": "#93000a", - "on-error-container": "#ffdad6" + "transitionDuration": { + "none": "0ms", + "short-1": "50ms", + "short-2": "100ms", + "short-3": "150ms", + "short-4": "200ms", + "medium-1": "250ms", + "medium-2": "300ms", + "medium-3": "350ms", + "medium-4": "400ms", + "long-1": "450ms", + "long-2": "500ms", + "long-3": "550ms", + "long-4": "600ms", + "extra-long-1": "700ms", + "extra-long-2": "800ms", + "extra-long-3": "900ms", + "extra-long-4": "1s" }, - "dark-medium-contrast": { - "primary-palette-key-color": "#6b73ad", - "secondary-palette-key-color": "#74768c", - "tertiary-palette-key-color": "#926c86", - "neutral-palette-key-color": "#77767d", - "neutral-variant-palette-key-color": "#767680", - "error-palette-key-color": "#de3730", - "background": "#131318", - "on-background": "#e4e1e9", - "surface": "#131318", - "surface-dim": "#131318", - "surface-bright": "#44444a", - "surface-container-lowest": "#07070c", - "surface-container-low": "#1d1d23", - "surface-container": "#27272d", - "surface-container-high": "#323238", - "surface-container-highest": "#3d3d43", - "on-surface": "#ffffff", - "surface-variant": "#46464f", - "on-surface-variant": "#dddbe6", - "outline": "#b2b1bb", - "outline-variant": "#908f99", - "inverse-surface": "#e4e1e9", - "inverse-on-surface": "#292a2f", - "shadow": "#000000", - "scrim": "#000000", - "surface-tint": "#bbc3ff", - "primary": "#d7daff", - "primary-dim": "#b8c0ff", - "on-primary": "#182055", - "primary-container": "#858dc8", - "on-primary-container": "#000000", - "inverse-primary": "#3c447a", - "primary-fixed": "#dfe0ff", - "primary-fixed-dim": "#bbc3ff", - "on-primary-fixed": "#010841", - "on-primary-fixed-variant": "#293267", - "secondary": "#dadaf3", - "secondary-dim": "#dadbf4", - "on-secondary": "#222437", - "secondary-container": "#8e8fa6", - "on-secondary-container": "#000000", - "secondary-fixed": "#e0e1f9", - "secondary-fixed-dim": "#c4c5dd", - "on-secondary-fixed": "#0d1021", - "on-secondary-fixed-variant": "#333548", - "tertiary": "#fdcfed", - "tertiary-dim": "#fed0ee", - "on-tertiary": "#391c32", - "tertiary-container": "#ad85a0", - "on-tertiary-container": "#000000", - "tertiary-fixed": "#ffd7f0", - "tertiary-fixed-dim": "#e6bad7", - "on-tertiary-fixed": "#21071c", - "on-tertiary-fixed-variant": "#4b2c43", - "error": "#ffd2cc", - "error-dim": "#ffaca2", - "on-error": "#540003", - "error-container": "#ff5449", - "on-error-container": "#000000" + "zIndex": { + "elevation-level-0": "0", + "elevation-level-1": "1", + "elevation-level-2": "3", + "elevation-level-3": "6", + "elevation-level-4": "8", + "elevation-level-5": "12" }, - "dark-high-contrast": { - "primary-palette-key-color": "#6b73ad", - "secondary-palette-key-color": "#74768c", - "tertiary-palette-key-color": "#926c86", - "neutral-palette-key-color": "#77767d", - "neutral-variant-palette-key-color": "#767680", - "error-palette-key-color": "#de3730", - "background": "#131318", - "on-background": "#e4e1e9", - "surface": "#131318", - "surface-dim": "#131318", - "surface-bright": "#504f56", - "surface-container-lowest": "#000000", - "surface-container-low": "#1f1f25", - "surface-container": "#303036", - "surface-container-high": "#3b3b41", - "surface-container-highest": "#46464c", - "on-surface": "#ffffff", - "surface-variant": "#46464f", - "on-surface-variant": "#ffffff", - "outline": "#f1effa", - "outline-variant": "#c3c1cc", - "inverse-surface": "#e4e1e9", - "inverse-on-surface": "#000000", - "shadow": "#000000", - "scrim": "#000000", - "surface-tint": "#bbc3ff", - "primary": "#efeeff", - "primary-dim": "#f0efff", - "on-primary": "#000000", - "primary-container": "#b7bffd", - "on-primary-container": "#000434", - "inverse-primary": "#3c447a", - "primary-fixed": "#dfe0ff", - "primary-fixed-dim": "#bbc3ff", - "on-primary-fixed": "#000000", - "on-primary-fixed-variant": "#010841", - "secondary": "#efeeff", - "secondary-dim": "#f0efff", - "on-secondary": "#000000", - "secondary-container": "#c0c1d9", - "on-secondary-container": "#070a1b", - "secondary-fixed": "#e0e1f9", - "secondary-fixed-dim": "#c4c5dd", - "on-secondary-fixed": "#000000", - "on-secondary-fixed-variant": "#0d1021", - "tertiary": "#ffebf5", - "tertiary-dim": "#ffecf6", - "on-tertiary": "#000000", - "tertiary-container": "#e2b6d3", - "on-tertiary-container": "#1a0316", - "tertiary-fixed": "#ffd7f0", - "tertiary-fixed-dim": "#e6bad7", - "on-tertiary-fixed": "#000000", - "on-tertiary-fixed-variant": "#21071c", - "error": "#ffece9", - "error-dim": "#ffedea", - "on-error": "#000000", - "error-container": "#ffaea4", - "on-error-container": "#220001" + "transitionTimingFunction": { + "standard": "cubic-bezier(0.2, 0, 0, 1)", + "accelerate": "cubic-bezier(0.3, 0, 1, 1)", + "decelerate": "cubic-bezier(0, 0, 0, 1)", + "linear": "linear", + "emphasized": "linear(\n 0,\n 0.002,\n 0.01 3.6%,\n 0.034,\n 0.074 9.1%,\n 0.128 11.4%,\n 0.194 13.4%,\n 0.271 15%,\n 0.344 16.1%,\n 0.544,\n 0.66 20.6%,\n 0.717 22.4%,\n 0.765 24.6%,\n 0.808 27.3%,\n 0.845 30.4%,\n 0.883 35.1%,\n 0.916 40.6%,\n 0.942 47.2%,\n 0.963 55%,\n 0.979 64%,\n 0.991 74.4%,\n 0.998 86.4%,\n 1\n )", + "emphasized-accelerate": "cubic-bezier(0.3, 0, 0.8, 0.15)", + "emphasized-decelerate": "cubic-bezier(0.05, 0.7, 0.1, 1)" }, - "primary-palette-key-color": "light-dark(#6b73ad, #6b73ad)", - "reduced-contrast-primary-palette-key-color": "light-dark(#6b73ad, #6b73ad)", - "medium-contrast-primary-palette-key-color": "light-dark(#6b73ad, #6b73ad)", - "high-contrast-primary-palette-key-color": "light-dark(#6b73ad, #6b73ad)", - "secondary-palette-key-color": "light-dark(#74768c, #74768c)", - "reduced-contrast-secondary-palette-key-color": "light-dark(#74768c, #74768c)", - "medium-contrast-secondary-palette-key-color": "light-dark(#74768c, #74768c)", - "high-contrast-secondary-palette-key-color": "light-dark(#74768c, #74768c)", - "tertiary-palette-key-color": "light-dark(#926c86, #926c86)", - "reduced-contrast-tertiary-palette-key-color": "light-dark(#926c86, #926c86)", - "medium-contrast-tertiary-palette-key-color": "light-dark(#926c86, #926c86)", - "high-contrast-tertiary-palette-key-color": "light-dark(#926c86, #926c86)", - "neutral-palette-key-color": "light-dark(#77767d, #77767d)", - "reduced-contrast-neutral-palette-key-color": "light-dark(#77767d, #77767d)", - "medium-contrast-neutral-palette-key-color": "light-dark(#77767d, #77767d)", - "high-contrast-neutral-palette-key-color": "light-dark(#77767d, #77767d)", - "neutral-variant-palette-key-color": "light-dark(#767680, #767680)", - "reduced-contrast-neutral-variant-palette-key-color": "light-dark(#767680, #767680)", - "medium-contrast-neutral-variant-palette-key-color": "light-dark(#767680, #767680)", - "high-contrast-neutral-variant-palette-key-color": "light-dark(#767680, #767680)", - "error-palette-key-color": "light-dark(#de3730, #de3730)", - "reduced-contrast-error-palette-key-color": "light-dark(#de3730, #de3730)", - "medium-contrast-error-palette-key-color": "light-dark(#de3730, #de3730)", - "high-contrast-error-palette-key-color": "light-dark(#de3730, #de3730)", - "background": "light-dark(#fbf8ff, #131318)", - "reduced-contrast-background": "light-dark(#fbf8ff, #131318)", - "medium-contrast-background": "light-dark(#fbf8ff, #131318)", - "high-contrast-background": "light-dark(#fbf8ff, #131318)", - "on-background": "light-dark(#1b1b21, #e4e1e9)", - "reduced-contrast-on-background": "light-dark(#908f96, #626268)", - "medium-contrast-on-background": "light-dark(#1b1b21, #e4e1e9)", - "high-contrast-on-background": "light-dark(#1b1b21, #e4e1e9)", - "surface": "light-dark(#fbf8ff, #131318)", - "reduced-contrast-surface": "light-dark(#fbf8ff, #131318)", - "medium-contrast-surface": "light-dark(#fbf8ff, #131318)", - "high-contrast-surface": "light-dark(#fbf8ff, #131318)", - "surface-dim": "light-dark(#dbd9e0, #131318)", - "reduced-contrast-surface-dim": "light-dark(#dbd9e0, #131318)", - "medium-contrast-surface-dim": "light-dark(#c7c5cd, #131318)", - "high-contrast-surface-dim": "light-dark(#b9b8bf, #131318)", - "surface-bright": "light-dark(#fbf8ff, #39393f)", - "reduced-contrast-surface-bright": "light-dark(#fbf8ff, #39393f)", - "medium-contrast-surface-bright": "light-dark(#fbf8ff, #44444a)", - "high-contrast-surface-bright": "light-dark(#fbf8ff, #504f56)", - "surface-container-lowest": "light-dark(#ffffff, #0d0e13)", - "reduced-contrast-surface-container-lowest": "light-dark(#ffffff, #0d0e13)", - "medium-contrast-surface-container-lowest": "light-dark(#ffffff, #07070c)", - "high-contrast-surface-container-lowest": "light-dark(#ffffff, #000000)", - "surface-container-low": "light-dark(#f5f2fa, #1b1b21)", - "reduced-contrast-surface-container-low": "light-dark(#f5f2fa, #1b1b21)", - "medium-contrast-surface-container-low": "light-dark(#f5f2fa, #1d1d23)", - "high-contrast-surface-container-low": "light-dark(#f2eff7, #1f1f25)", - "surface-container": "light-dark(#efedf4, #1f1f25)", - "reduced-contrast-surface-container": "light-dark(#efedf4, #1f1f25)", - "medium-contrast-surface-container": "light-dark(#e9e7ef, #27272d)", - "high-contrast-surface-container": "light-dark(#e4e1e9, #303036)", - "surface-container-high": "light-dark(#e9e7ef, #29292f)", - "reduced-contrast-surface-container-high": "light-dark(#e9e7ef, #29292f)", - "medium-contrast-surface-container-high": "light-dark(#dedce3, #323238)", - "high-contrast-surface-container-high": "light-dark(#d5d3db, #3b3b41)", - "surface-container-highest": "light-dark(#e4e1e9, #34343a)", - "reduced-contrast-surface-container-highest": "light-dark(#e4e1e9, #34343a)", - "medium-contrast-surface-container-highest": "light-dark(#d3d0d8, #3d3d43)", - "high-contrast-surface-container-highest": "light-dark(#c7c5cd, #46464c)", - "on-surface": "light-dark(#1b1b21, #e4e1e9)", - "reduced-contrast-on-surface": "light-dark(#5f5e65, #a3a2a9)", - "medium-contrast-on-surface": "light-dark(#101116, #ffffff)", - "high-contrast-on-surface": "light-dark(#000000, #ffffff)", - "surface-variant": "light-dark(#e3e1ec, #46464f)", - "reduced-contrast-surface-variant": "light-dark(#e3e1ec, #46464f)", - "medium-contrast-surface-variant": "light-dark(#e3e1ec, #46464f)", - "high-contrast-surface-variant": "light-dark(#e3e1ec, #46464f)", - "on-surface-variant": "light-dark(#46464f, #c7c5d0)", - "reduced-contrast-on-surface-variant": "light-dark(#7a7a83, #83828c)", - "medium-contrast-on-surface-variant": "light-dark(#35353e, #dddbe6)", - "high-contrast-on-surface-variant": "light-dark(#000000, #ffffff)", - "outline": "light-dark(#767680, #90909a)", - "reduced-contrast-outline": "light-dark(#b2b1bb, #53535c)", - "medium-contrast-outline": "light-dark(#52525b, #b2b1bb)", - "high-contrast-outline": "light-dark(#2b2c34, #f1effa)", - "outline-variant": "light-dark(#c7c5d0, #46464f)", - "reduced-contrast-outline-variant": "light-dark(#d9d8e2, #393942)", - "medium-contrast-outline-variant": "light-dark(#6c6c76, #908f99)", - "high-contrast-outline-variant": "light-dark(#484851, #c3c1cc)", - "inverse-surface": "light-dark(#303036, #e4e1e9)", - "reduced-contrast-inverse-surface": "light-dark(#303036, #e4e1e9)", - "medium-contrast-inverse-surface": "light-dark(#303036, #e4e1e9)", - "high-contrast-inverse-surface": "light-dark(#303036, #e4e1e9)", - "inverse-on-surface": "light-dark(#f2eff7, #303036)", - "reduced-contrast-inverse-on-surface": "light-dark(#99979e, #64646a)", - "medium-contrast-inverse-on-surface": "light-dark(#f2eff7, #292a2f)", - "high-contrast-inverse-on-surface": "light-dark(#ffffff, #000000)", - "shadow": "light-dark(#000000, #000000)", - "reduced-contrast-shadow": "light-dark(#000000, #000000)", - "medium-contrast-shadow": "light-dark(#000000, #000000)", - "high-contrast-shadow": "light-dark(#000000, #000000)", - "scrim": "light-dark(#000000, #000000)", - "reduced-contrast-scrim": "light-dark(#000000, #000000)", - "medium-contrast-scrim": "light-dark(#000000, #000000)", - "high-contrast-scrim": "light-dark(#000000, #000000)", - "surface-tint": "light-dark(#525a92, #bbc3ff)", - "reduced-contrast-surface-tint": "light-dark(#525a92, #bbc3ff)", - "medium-contrast-surface-tint": "light-dark(#525a92, #bbc3ff)", - "high-contrast-surface-tint": "light-dark(#525a92, #bbc3ff)", - "primary": "light-dark(#525a92, #bbc3ff)", - "reduced-contrast-primary": "light-dark(#6971aa, #858dc8)", - "medium-contrast-primary": "light-dark(#293267, #d7daff)", - "high-contrast-primary": "light-dark(#1f275c, #efeeff)", - "primary-dim": "light-dark(#464e85, #b8c0ff)", - "reduced-contrast-primary-dim": "light-dark(#5c649c, #858dc9)", - "medium-contrast-primary-dim": "light-dark(#2d356a, #b8c0ff)", - "high-contrast-primary-dim": "light-dark(#11194f, #f0efff)", - "on-primary": "light-dark(#ffffff, #232c61)", - "reduced-contrast-on-primary": "light-dark(#fffbff, #1c255a)", - "medium-contrast-on-primary": "light-dark(#ffffff, #182055)", - "high-contrast-on-primary": "light-dark(#ffffff, #000000)", - "primary-container": "light-dark(#dfe0ff, #3a4279)", - "reduced-contrast-primary-container": "light-dark(#d3d6ff, #2d366b)", - "medium-contrast-primary-container": "light-dark(#6169a2, #858dc8)", - "high-contrast-primary-container": "light-dark(#3d457b, #b7bffd)", - "on-primary-container": "light-dark(#3a4279, #dfe0ff)", - "reduced-contrast-on-primary-container": "light-dark(#6e76b0, #7880bb)", - "medium-contrast-on-primary-container": "light-dark(#ffffff, #000000)", - "high-contrast-on-primary-container": "light-dark(#ffffff, #000434)", - "inverse-primary": "light-dark(#bbc3ff, #525a92)", - "reduced-contrast-inverse-primary": "light-dark(#6e76b0, #757db7)", - "medium-contrast-inverse-primary": "light-dark(#bbc3ff, #3c447a)", - "high-contrast-inverse-primary": "light-dark(#bbc3ff, #3c447a)", - "primary-fixed": "light-dark(#dfe0ff, #dfe0ff)", - "reduced-contrast-primary-fixed": "light-dark(#d3d6ff, #454d84)", - "medium-contrast-primary-fixed": "light-dark(#6169a2, #dfe0ff)", - "high-contrast-primary-fixed": "light-dark(#3d457b, #dfe0ff)", - "primary-fixed-dim": "light-dark(#bbc3ff, #bbc3ff)", - "reduced-contrast-primary-fixed-dim": "light-dark(#b1b9f8, #2d366b)", - "medium-contrast-primary-fixed-dim": "light-dark(#495188, #bbc3ff)", - "high-contrast-primary-fixed-dim": "light-dark(#262e63, #bbc3ff)", - "on-primary-fixed": "light-dark(#0c154b, #0c154b)", - "reduced-contrast-on-primary-fixed": "light-dark(#40487e, #b8c0ff)", - "medium-contrast-on-primary-fixed": "light-dark(#ffffff, #010841)", - "high-contrast-on-primary-fixed": "light-dark(#ffffff, #000000)", - "on-primary-fixed-variant": "light-dark(#3a4279, #3a4279)", - "reduced-contrast-on-primary-fixed-variant": "light-dark(#5a629b, #949cd9)", - "medium-contrast-on-primary-fixed-variant": "light-dark(#ffffff, #293267)", - "high-contrast-on-primary-fixed-variant": "light-dark(#ffffff, #010841)", - "secondary": "light-dark(#5b5d72, #c4c5dd)", - "reduced-contrast-secondary": "light-dark(#717389, #8e8fa6)", - "medium-contrast-secondary": "light-dark(#333548, #dadaf3)", - "high-contrast-secondary": "light-dark(#292b3d, #efeeff)", - "secondary-dim": "light-dark(#4f5165, #dadbf4)", - "reduced-contrast-secondary-dim": "light-dark(#65667b, #8e90a6)", - "medium-contrast-secondary-dim": "light-dark(#36384b, #dadbf4)", - "high-contrast-secondary-dim": "light-dark(#1c1e30, #f0efff)", - "on-secondary": "light-dark(#ffffff, #2d2f42)", - "reduced-contrast-on-secondary": "light-dark(#fffbff, #26283b)", - "medium-contrast-on-secondary": "light-dark(#ffffff, #222437)", - "high-contrast-on-secondary": "light-dark(#ffffff, #000000)", - "secondary-container": "light-dark(#e0e1f9, #434559)", - "reduced-contrast-secondary-container": "light-dark(#d6d7f0, #37394c)", - "medium-contrast-secondary-container": "light-dark(#6a6c81, #8e8fa6)", - "high-contrast-secondary-container": "light-dark(#46485c, #c0c1d9)", - "on-secondary-container": "light-dark(#434559, #e0e1f9)", - "reduced-contrast-on-secondary-container": "light-dark(#77788e, #818399)", - "medium-contrast-on-secondary-container": "light-dark(#ffffff, #000000)", - "high-contrast-on-secondary-container": "light-dark(#ffffff, #070a1b)", - "secondary-fixed": "light-dark(#e0e1f9, #e0e1f9)", - "reduced-contrast-secondary-fixed": "light-dark(#d6d7f0, #4e5064)", - "medium-contrast-secondary-fixed": "light-dark(#6a6c81, #e0e1f9)", - "high-contrast-secondary-fixed": "light-dark(#46485c, #e0e1f9)", - "secondary-fixed-dim": "light-dark(#c4c5dd, #c4c5dd)", - "reduced-contrast-secondary-fixed-dim": "light-dark(#babbd3, #37394c)", - "medium-contrast-secondary-fixed-dim": "light-dark(#515368, #c4c5dd)", - "high-contrast-secondary-fixed-dim": "light-dark(#2f3144, #c4c5dd)", - "on-secondary-fixed": "light-dark(#181a2c, #181a2c)", - "reduced-contrast-on-secondary-fixed": "light-dark(#494b5f, #c1c2da)", - "medium-contrast-on-secondary-fixed": "light-dark(#ffffff, #0d1021)", - "high-contrast-on-secondary-fixed": "light-dark(#ffffff, #000000)", - "on-secondary-fixed-variant": "light-dark(#434559, #434559)", - "reduced-contrast-on-secondary-fixed-variant": "light-dark(#63657a, #9d9eb5)", - "medium-contrast-on-secondary-fixed-variant": "light-dark(#ffffff, #333548)", - "high-contrast-on-secondary-fixed-variant": "light-dark(#ffffff, #0d1021)", - "tertiary": "light-dark(#77536c, #e6bad7)", - "reduced-contrast-tertiary": "light-dark(#8f6983, #ad85a0)", - "medium-contrast-tertiary": "light-dark(#4b2c43, #fdcfed)", - "high-contrast-tertiary": "light-dark(#402239, #ffebf5)", - "tertiary-dim": "light-dark(#6a4860, #fed0ee)", - "reduced-contrast-tertiary-dim": "light-dark(#815d76, #ad85a0)", - "medium-contrast-tertiary-dim": "light-dark(#4e2f46, #fed0ee)", - "high-contrast-tertiary-dim": "light-dark(#32152b, #ffecf6)", - "on-tertiary": "light-dark(#ffffff, #45263d)", - "reduced-contrast-on-tertiary": "light-dark(#fffbff, #3d2036)", - "medium-contrast-on-tertiary": "light-dark(#ffffff, #391c32)", - "high-contrast-on-tertiary": "light-dark(#ffffff, #000000)", - "tertiary-container": "light-dark(#ffd7f0, #5d3c54)", - "reduced-contrast-tertiary-container": "light-dark(#f9ccea, #4f3047)", - "medium-contrast-tertiary-container": "light-dark(#87627c, #ad85a0)", - "high-contrast-tertiary-container": "light-dark(#603f57, #e2b6d3)", - "on-tertiary-container": "light-dark(#5d3c54, #ffd7f0)", - "reduced-contrast-on-tertiary-container": "light-dark(#956e89, #9f7893)", - "medium-contrast-on-tertiary-container": "light-dark(#ffffff, #000000)", - "high-contrast-on-tertiary-container": "light-dark(#ffffff, #1a0316)", - "tertiary-fixed": "light-dark(#ffd7f0, #ffd7f0)", - "reduced-contrast-tertiary-fixed": "light-dark(#f9ccea, #68465f)", - "medium-contrast-tertiary-fixed": "light-dark(#87627c, #ffd7f0)", - "high-contrast-tertiary-fixed": "light-dark(#603f57, #ffd7f0)", - "tertiary-fixed-dim": "light-dark(#e6bad7, #e6bad7)", - "reduced-contrast-tertiary-fixed-dim": "light-dark(#dcb0cd, #4f3047)", - "medium-contrast-tertiary-fixed-dim": "light-dark(#6d4a63, #e6bad7)", - "high-contrast-tertiary-fixed-dim": "light-dark(#47283f, #e6bad7)", - "on-tertiary-fixed": "light-dark(#2d1227, #2d1227)", - "reduced-contrast-on-tertiary-fixed": "light-dark(#63425a, #e3b7d4)", - "medium-contrast-on-tertiary-fixed": "light-dark(#ffffff, #21071c)", - "high-contrast-on-tertiary-fixed": "light-dark(#ffffff, #000000)", - "on-tertiary-fixed-variant": "light-dark(#5d3c54, #5d3c54)", - "reduced-contrast-on-tertiary-fixed-variant": "light-dark(#805b75, #bd94b0)", - "medium-contrast-on-tertiary-fixed-variant": "light-dark(#ffffff, #4b2c43)", - "high-contrast-on-tertiary-fixed-variant": "light-dark(#ffffff, #21071c)", - "error": "light-dark(#ba1a1a, #ffb4ab)", - "reduced-contrast-error": "light-dark(#da342e, #ff5449)", - "medium-contrast-error": "light-dark(#740006, #ffd2cc)", - "high-contrast-error": "light-dark(#600004, #ffece9)", - "error-dim": "light-dark(#a80710, #ff554a)", - "reduced-contrast-error-dim": "light-dark(#c82623, #ff554a)", - "medium-contrast-error-dim": "light-dark(#790006, #ffaca2)", - "high-contrast-error-dim": "light-dark(#480002, #ffedea)", - "on-error": "light-dark(#ffffff, #690005)", - "reduced-contrast-on-error": "light-dark(#fffbff, #5c0003)", - "medium-contrast-on-error": "light-dark(#ffffff, #540003)", - "high-contrast-on-error": "light-dark(#ffffff, #000000)", - "error-container": "light-dark(#ffdad6, #93000a)", - "reduced-contrast-error-container": "light-dark(#ffcdc7, #7b0007)", - "medium-contrast-error-container": "light-dark(#cf2c27, #ff5449)", - "high-contrast-error-container": "light-dark(#98000a, #ffaea4)", - "on-error-container": "light-dark(#93000a, #ffdad6)", - "reduced-contrast-on-error-container": "light-dark(#e23a32, #f0443b)", - "medium-contrast-on-error-container": "light-dark(#ffffff, #000000)", - "high-contrast-on-error-container": "light-dark(#ffffff, #220001)", - "primary-0": "#000000", - "primary-5": "#010841", - "primary-10": "#0c154b", - "primary-15": "#182055", - "primary-20": "#232c61", - "primary-25": "#2f376c", - "primary-30": "#3a4279", - "primary-35": "#464e85", - "primary-40": "#525a92", - "primary-50": "#6b73ad", - "primary-60": "#858dc8", - "primary-70": "#9fa7e5", - "primary-80": "#bbc3ff", - "primary-90": "#dfe0ff", - "primary-95": "#f0efff", - "primary-98": "#fbf8ff", - "primary-99": "#fffbff", - "primary-100": "#ffffff", - "secondary-0": "#000000", - "secondary-5": "#0d1021", - "secondary-10": "#181a2c", - "secondary-15": "#222537", - "secondary-20": "#2d2f42", - "secondary-25": "#383a4d", - "secondary-30": "#434559", - "secondary-35": "#4f5165", - "secondary-40": "#5b5d72", - "secondary-50": "#74768b", - "secondary-60": "#8e8fa6", - "secondary-70": "#a8a9c1", - "secondary-80": "#c4c5dd", - "secondary-90": "#e0e1f9", - "secondary-95": "#f0efff", - "secondary-98": "#fbf8ff", - "secondary-99": "#fffbff", - "secondary-100": "#ffffff", - "tertiary-0": "#000000", - "tertiary-5": "#21071c", - "tertiary-10": "#2d1227", - "tertiary-15": "#391c32", - "tertiary-20": "#45263d", - "tertiary-25": "#513148", - "tertiary-30": "#5d3c54", - "tertiary-35": "#6a4860", - "tertiary-40": "#77536c", - "tertiary-50": "#916c86", - "tertiary-60": "#ad85a0", - "tertiary-70": "#c99fbb", - "tertiary-80": "#e6bad7", - "tertiary-90": "#ffd7f0", - "tertiary-95": "#ffecf6", - "tertiary-98": "#fff7f9", - "tertiary-99": "#fffbff", - "tertiary-100": "#ffffff", - "neutral-0": "#000000", - "neutral-5": "#101116", - "neutral-10": "#1b1b21", - "neutral-15": "#25252b", - "neutral-20": "#303036", - "neutral-25": "#3b3b41", - "neutral-30": "#46464c", - "neutral-35": "#525258", - "neutral-40": "#5e5e64", - "neutral-50": "#77767d", - "neutral-60": "#919097", - "neutral-70": "#acaab1", - "neutral-80": "#c7c5cd", - "neutral-90": "#e4e1e9", - "neutral-95": "#f2eff7", - "neutral-98": "#fbf8ff", - "neutral-99": "#fffbff", - "neutral-100": "#ffffff", - "neutral-variant-0": "#000000", - "neutral-variant-5": "#101018", - "neutral-variant-10": "#1a1b23", - "neutral-variant-15": "#25252d", - "neutral-variant-20": "#2f3038", - "neutral-variant-25": "#3a3b43", - "neutral-variant-30": "#46464f", - "neutral-variant-35": "#52525b", - "neutral-variant-40": "#5e5e67", - "neutral-variant-50": "#767680", - "neutral-variant-60": "#90909a", - "neutral-variant-70": "#abaab4", - "neutral-variant-80": "#c7c5d0", - "neutral-variant-90": "#e3e1ec", - "neutral-variant-95": "#f1effa", - "neutral-variant-98": "#fbf8ff", - "neutral-variant-99": "#fffbff", - "neutral-variant-100": "#ffffff", - "error-0": "#000000", - "error-5": "#2d0001", - "error-10": "#410002", - "error-15": "#540003", - "error-20": "#690005", - "error-25": "#7e0007", - "error-30": "#93000a", - "error-35": "#a80710", - "error-40": "#ba1a1a", - "error-50": "#de3730", - "error-60": "#ff5449", - "error-70": "#ff897d", - "error-80": "#ffb4ab", - "error-90": "#ffdad6", - "error-95": "#ffedea", - "error-98": "#fff8f7", - "error-99": "#fffbff", - "error-100": "#ffffff" + "colors": { + "source": "var(--color-source)", + "light": { + "primary-palette-key-color": "var(--color-light-primary-palette-key-color)", + "secondary-palette-key-color": "var(--color-light-secondary-palette-key-color)", + "tertiary-palette-key-color": "var(--color-light-tertiary-palette-key-color)", + "neutral-palette-key-color": "var(--color-light-neutral-palette-key-color)", + "neutral-variant-palette-key-color": "var(--color-light-neutral-variant-palette-key-color)", + "error-palette-key-color": "var(--color-light-error-palette-key-color)", + "background": "var(--color-light-background)", + "on-background": "var(--color-light-on-background)", + "surface": "var(--color-light-surface)", + "surface-dim": "var(--color-light-surface-dim)", + "surface-bright": "var(--color-light-surface-bright)", + "surface-container-lowest": "var(--color-light-surface-container-lowest)", + "surface-container-low": "var(--color-light-surface-container-low)", + "surface-container": "var(--color-light-surface-container)", + "surface-container-high": "var(--color-light-surface-container-high)", + "surface-container-highest": "var(--color-light-surface-container-highest)", + "on-surface": "var(--color-light-on-surface)", + "surface-variant": "var(--color-light-surface-variant)", + "on-surface-variant": "var(--color-light-on-surface-variant)", + "outline": "var(--color-light-outline)", + "outline-variant": "var(--color-light-outline-variant)", + "inverse-surface": "var(--color-light-inverse-surface)", + "inverse-on-surface": "var(--color-light-inverse-on-surface)", + "shadow": "var(--color-light-shadow)", + "scrim": "var(--color-light-scrim)", + "surface-tint": "var(--color-light-surface-tint)", + "primary": "var(--color-light-primary)", + "primary-dim": "var(--color-light-primary-dim)", + "on-primary": "var(--color-light-on-primary)", + "primary-container": "var(--color-light-primary-container)", + "on-primary-container": "var(--color-light-on-primary-container)", + "inverse-primary": "var(--color-light-inverse-primary)", + "primary-fixed": "var(--color-light-primary-fixed)", + "primary-fixed-dim": "var(--color-light-primary-fixed-dim)", + "on-primary-fixed": "var(--color-light-on-primary-fixed)", + "on-primary-fixed-variant": "var(--color-light-on-primary-fixed-variant)", + "secondary": "var(--color-light-secondary)", + "secondary-dim": "var(--color-light-secondary-dim)", + "on-secondary": "var(--color-light-on-secondary)", + "secondary-container": "var(--color-light-secondary-container)", + "on-secondary-container": "var(--color-light-on-secondary-container)", + "secondary-fixed": "var(--color-light-secondary-fixed)", + "secondary-fixed-dim": "var(--color-light-secondary-fixed-dim)", + "on-secondary-fixed": "var(--color-light-on-secondary-fixed)", + "on-secondary-fixed-variant": "var(--color-light-on-secondary-fixed-variant)", + "tertiary": "var(--color-light-tertiary)", + "tertiary-dim": "var(--color-light-tertiary-dim)", + "on-tertiary": "var(--color-light-on-tertiary)", + "tertiary-container": "var(--color-light-tertiary-container)", + "on-tertiary-container": "var(--color-light-on-tertiary-container)", + "tertiary-fixed": "var(--color-light-tertiary-fixed)", + "tertiary-fixed-dim": "var(--color-light-tertiary-fixed-dim)", + "on-tertiary-fixed": "var(--color-light-on-tertiary-fixed)", + "on-tertiary-fixed-variant": "var(--color-light-on-tertiary-fixed-variant)", + "error": "var(--color-light-error)", + "error-dim": "var(--color-light-error-dim)", + "on-error": "var(--color-light-on-error)", + "error-container": "var(--color-light-error-container)", + "on-error-container": "var(--color-light-on-error-container)" + }, + "dark": { + "primary-palette-key-color": "var(--color-dark-primary-palette-key-color)", + "secondary-palette-key-color": "var(--color-dark-secondary-palette-key-color)", + "tertiary-palette-key-color": "var(--color-dark-tertiary-palette-key-color)", + "neutral-palette-key-color": "var(--color-dark-neutral-palette-key-color)", + "neutral-variant-palette-key-color": "var(--color-dark-neutral-variant-palette-key-color)", + "error-palette-key-color": "var(--color-dark-error-palette-key-color)", + "background": "var(--color-dark-background)", + "on-background": "var(--color-dark-on-background)", + "surface": "var(--color-dark-surface)", + "surface-dim": "var(--color-dark-surface-dim)", + "surface-bright": "var(--color-dark-surface-bright)", + "surface-container-lowest": "var(--color-dark-surface-container-lowest)", + "surface-container-low": "var(--color-dark-surface-container-low)", + "surface-container": "var(--color-dark-surface-container)", + "surface-container-high": "var(--color-dark-surface-container-high)", + "surface-container-highest": "var(--color-dark-surface-container-highest)", + "on-surface": "var(--color-dark-on-surface)", + "surface-variant": "var(--color-dark-surface-variant)", + "on-surface-variant": "var(--color-dark-on-surface-variant)", + "outline": "var(--color-dark-outline)", + "outline-variant": "var(--color-dark-outline-variant)", + "inverse-surface": "var(--color-dark-inverse-surface)", + "inverse-on-surface": "var(--color-dark-inverse-on-surface)", + "shadow": "var(--color-dark-shadow)", + "scrim": "var(--color-dark-scrim)", + "surface-tint": "var(--color-dark-surface-tint)", + "primary": "var(--color-dark-primary)", + "primary-dim": "var(--color-dark-primary-dim)", + "on-primary": "var(--color-dark-on-primary)", + "primary-container": "var(--color-dark-primary-container)", + "on-primary-container": "var(--color-dark-on-primary-container)", + "inverse-primary": "var(--color-dark-inverse-primary)", + "primary-fixed": "var(--color-dark-primary-fixed)", + "primary-fixed-dim": "var(--color-dark-primary-fixed-dim)", + "on-primary-fixed": "var(--color-dark-on-primary-fixed)", + "on-primary-fixed-variant": "var(--color-dark-on-primary-fixed-variant)", + "secondary": "var(--color-dark-secondary)", + "secondary-dim": "var(--color-dark-secondary-dim)", + "on-secondary": "var(--color-dark-on-secondary)", + "secondary-container": "var(--color-dark-secondary-container)", + "on-secondary-container": "var(--color-dark-on-secondary-container)", + "secondary-fixed": "var(--color-dark-secondary-fixed)", + "secondary-fixed-dim": "var(--color-dark-secondary-fixed-dim)", + "on-secondary-fixed": "var(--color-dark-on-secondary-fixed)", + "on-secondary-fixed-variant": "var(--color-dark-on-secondary-fixed-variant)", + "tertiary": "var(--color-dark-tertiary)", + "tertiary-dim": "var(--color-dark-tertiary-dim)", + "on-tertiary": "var(--color-dark-on-tertiary)", + "tertiary-container": "var(--color-dark-tertiary-container)", + "on-tertiary-container": "var(--color-dark-on-tertiary-container)", + "tertiary-fixed": "var(--color-dark-tertiary-fixed)", + "tertiary-fixed-dim": "var(--color-dark-tertiary-fixed-dim)", + "on-tertiary-fixed": "var(--color-dark-on-tertiary-fixed)", + "on-tertiary-fixed-variant": "var(--color-dark-on-tertiary-fixed-variant)", + "error": "var(--color-dark-error)", + "error-dim": "var(--color-dark-error-dim)", + "on-error": "var(--color-dark-on-error)", + "error-container": "var(--color-dark-error-container)", + "on-error-container": "var(--color-dark-on-error-container)" + }, + "primary-palette-key-color": "var(--color-primary-palette-key-color, light-dark(var(--color-light-primary-palette-key-color), var(--color-dark-primary-palette-key-color)))", + "secondary-palette-key-color": "var(--color-secondary-palette-key-color, light-dark(var(--color-light-secondary-palette-key-color), var(--color-dark-secondary-palette-key-color)))", + "tertiary-palette-key-color": "var(--color-tertiary-palette-key-color, light-dark(var(--color-light-tertiary-palette-key-color), var(--color-dark-tertiary-palette-key-color)))", + "neutral-palette-key-color": "var(--color-neutral-palette-key-color, light-dark(var(--color-light-neutral-palette-key-color), var(--color-dark-neutral-palette-key-color)))", + "neutral-variant-palette-key-color": "var(--color-neutral-variant-palette-key-color, light-dark(var(--color-light-neutral-variant-palette-key-color), var(--color-dark-neutral-variant-palette-key-color)))", + "error-palette-key-color": "var(--color-error-palette-key-color, light-dark(var(--color-light-error-palette-key-color), var(--color-dark-error-palette-key-color)))", + "background": "var(--color-background, light-dark(var(--color-light-background), var(--color-dark-background)))", + "on-background": "var(--color-on-background, light-dark(var(--color-light-on-background), var(--color-dark-on-background)))", + "surface": "var(--color-surface, light-dark(var(--color-light-surface), var(--color-dark-surface)))", + "surface-dim": "var(--color-surface-dim, light-dark(var(--color-light-surface-dim), var(--color-dark-surface-dim)))", + "surface-bright": "var(--color-surface-bright, light-dark(var(--color-light-surface-bright), var(--color-dark-surface-bright)))", + "surface-container-lowest": "var(--color-surface-container-lowest, light-dark(var(--color-light-surface-container-lowest), var(--color-dark-surface-container-lowest)))", + "surface-container-low": "var(--color-surface-container-low, light-dark(var(--color-light-surface-container-low), var(--color-dark-surface-container-low)))", + "surface-container": "var(--color-surface-container, light-dark(var(--color-light-surface-container), var(--color-dark-surface-container)))", + "surface-container-high": "var(--color-surface-container-high, light-dark(var(--color-light-surface-container-high), var(--color-dark-surface-container-high)))", + "surface-container-highest": "var(--color-surface-container-highest, light-dark(var(--color-light-surface-container-highest), var(--color-dark-surface-container-highest)))", + "on-surface": "var(--color-on-surface, light-dark(var(--color-light-on-surface), var(--color-dark-on-surface)))", + "surface-variant": "var(--color-surface-variant, light-dark(var(--color-light-surface-variant), var(--color-dark-surface-variant)))", + "on-surface-variant": "var(--color-on-surface-variant, light-dark(var(--color-light-on-surface-variant), var(--color-dark-on-surface-variant)))", + "outline": "var(--color-outline, light-dark(var(--color-light-outline), var(--color-dark-outline)))", + "outline-variant": "var(--color-outline-variant, light-dark(var(--color-light-outline-variant), var(--color-dark-outline-variant)))", + "inverse-surface": "var(--color-inverse-surface, light-dark(var(--color-light-inverse-surface), var(--color-dark-inverse-surface)))", + "inverse-on-surface": "var(--color-inverse-on-surface, light-dark(var(--color-light-inverse-on-surface), var(--color-dark-inverse-on-surface)))", + "shadow": "var(--color-shadow, light-dark(var(--color-light-shadow), var(--color-dark-shadow)))", + "scrim": "var(--color-scrim, light-dark(var(--color-light-scrim), var(--color-dark-scrim)))", + "surface-tint": "var(--color-surface-tint, light-dark(var(--color-light-surface-tint), var(--color-dark-surface-tint)))", + "primary": "var(--color-primary, light-dark(var(--color-light-primary), var(--color-dark-primary)))", + "primary-dim": "var(--color-primary-dim, light-dark(var(--color-light-primary-dim), var(--color-dark-primary-dim)))", + "on-primary": "var(--color-on-primary, light-dark(var(--color-light-on-primary), var(--color-dark-on-primary)))", + "primary-container": "var(--color-primary-container, light-dark(var(--color-light-primary-container), var(--color-dark-primary-container)))", + "on-primary-container": "var(--color-on-primary-container, light-dark(var(--color-light-on-primary-container), var(--color-dark-on-primary-container)))", + "inverse-primary": "var(--color-inverse-primary, light-dark(var(--color-light-inverse-primary), var(--color-dark-inverse-primary)))", + "primary-fixed": "var(--color-primary-fixed, light-dark(var(--color-light-primary-fixed), var(--color-dark-primary-fixed)))", + "primary-fixed-dim": "var(--color-primary-fixed-dim, light-dark(var(--color-light-primary-fixed-dim), var(--color-dark-primary-fixed-dim)))", + "on-primary-fixed": "var(--color-on-primary-fixed, light-dark(var(--color-light-on-primary-fixed), var(--color-dark-on-primary-fixed)))", + "on-primary-fixed-variant": "var(--color-on-primary-fixed-variant, light-dark(var(--color-light-on-primary-fixed-variant), var(--color-dark-on-primary-fixed-variant)))", + "secondary": "var(--color-secondary, light-dark(var(--color-light-secondary), var(--color-dark-secondary)))", + "secondary-dim": "var(--color-secondary-dim, light-dark(var(--color-light-secondary-dim), var(--color-dark-secondary-dim)))", + "on-secondary": "var(--color-on-secondary, light-dark(var(--color-light-on-secondary), var(--color-dark-on-secondary)))", + "secondary-container": "var(--color-secondary-container, light-dark(var(--color-light-secondary-container), var(--color-dark-secondary-container)))", + "on-secondary-container": "var(--color-on-secondary-container, light-dark(var(--color-light-on-secondary-container), var(--color-dark-on-secondary-container)))", + "secondary-fixed": "var(--color-secondary-fixed, light-dark(var(--color-light-secondary-fixed), var(--color-dark-secondary-fixed)))", + "secondary-fixed-dim": "var(--color-secondary-fixed-dim, light-dark(var(--color-light-secondary-fixed-dim), var(--color-dark-secondary-fixed-dim)))", + "on-secondary-fixed": "var(--color-on-secondary-fixed, light-dark(var(--color-light-on-secondary-fixed), var(--color-dark-on-secondary-fixed)))", + "on-secondary-fixed-variant": "var(--color-on-secondary-fixed-variant, light-dark(var(--color-light-on-secondary-fixed-variant), var(--color-dark-on-secondary-fixed-variant)))", + "tertiary": "var(--color-tertiary, light-dark(var(--color-light-tertiary), var(--color-dark-tertiary)))", + "tertiary-dim": "var(--color-tertiary-dim, light-dark(var(--color-light-tertiary-dim), var(--color-dark-tertiary-dim)))", + "on-tertiary": "var(--color-on-tertiary, light-dark(var(--color-light-on-tertiary), var(--color-dark-on-tertiary)))", + "tertiary-container": "var(--color-tertiary-container, light-dark(var(--color-light-tertiary-container), var(--color-dark-tertiary-container)))", + "on-tertiary-container": "var(--color-on-tertiary-container, light-dark(var(--color-light-on-tertiary-container), var(--color-dark-on-tertiary-container)))", + "tertiary-fixed": "var(--color-tertiary-fixed, light-dark(var(--color-light-tertiary-fixed), var(--color-dark-tertiary-fixed)))", + "tertiary-fixed-dim": "var(--color-tertiary-fixed-dim, light-dark(var(--color-light-tertiary-fixed-dim), var(--color-dark-tertiary-fixed-dim)))", + "on-tertiary-fixed": "var(--color-on-tertiary-fixed, light-dark(var(--color-light-on-tertiary-fixed), var(--color-dark-on-tertiary-fixed)))", + "on-tertiary-fixed-variant": "var(--color-on-tertiary-fixed-variant, light-dark(var(--color-light-on-tertiary-fixed-variant), var(--color-dark-on-tertiary-fixed-variant)))", + "error": "var(--color-error, light-dark(var(--color-light-error), var(--color-dark-error)))", + "error-dim": "var(--color-error-dim, light-dark(var(--color-light-error-dim), var(--color-dark-error-dim)))", + "on-error": "var(--color-on-error, light-dark(var(--color-light-on-error), var(--color-dark-on-error)))", + "error-container": "var(--color-error-container, light-dark(var(--color-light-error-container), var(--color-dark-error-container)))", + "on-error-container": "var(--color-on-error-container, light-dark(var(--color-light-on-error-container), var(--color-dark-on-error-container)))", + "primary-0": "var(--color-primary-0)", + "primary-5": "var(--color-primary-5)", + "primary-10": "var(--color-primary-10)", + "primary-15": "var(--color-primary-15)", + "primary-20": "var(--color-primary-20)", + "primary-25": "var(--color-primary-25)", + "primary-30": "var(--color-primary-30)", + "primary-35": "var(--color-primary-35)", + "primary-40": "var(--color-primary-40)", + "primary-50": "var(--color-primary-50)", + "primary-60": "var(--color-primary-60)", + "primary-70": "var(--color-primary-70)", + "primary-80": "var(--color-primary-80)", + "primary-90": "var(--color-primary-90)", + "primary-95": "var(--color-primary-95)", + "primary-98": "var(--color-primary-98)", + "primary-99": "var(--color-primary-99)", + "primary-100": "var(--color-primary-100)", + "secondary-0": "var(--color-secondary-0)", + "secondary-5": "var(--color-secondary-5)", + "secondary-10": "var(--color-secondary-10)", + "secondary-15": "var(--color-secondary-15)", + "secondary-20": "var(--color-secondary-20)", + "secondary-25": "var(--color-secondary-25)", + "secondary-30": "var(--color-secondary-30)", + "secondary-35": "var(--color-secondary-35)", + "secondary-40": "var(--color-secondary-40)", + "secondary-50": "var(--color-secondary-50)", + "secondary-60": "var(--color-secondary-60)", + "secondary-70": "var(--color-secondary-70)", + "secondary-80": "var(--color-secondary-80)", + "secondary-90": "var(--color-secondary-90)", + "secondary-95": "var(--color-secondary-95)", + "secondary-98": "var(--color-secondary-98)", + "secondary-99": "var(--color-secondary-99)", + "secondary-100": "var(--color-secondary-100)", + "tertiary-0": "var(--color-tertiary-0)", + "tertiary-5": "var(--color-tertiary-5)", + "tertiary-10": "var(--color-tertiary-10)", + "tertiary-15": "var(--color-tertiary-15)", + "tertiary-20": "var(--color-tertiary-20)", + "tertiary-25": "var(--color-tertiary-25)", + "tertiary-30": "var(--color-tertiary-30)", + "tertiary-35": "var(--color-tertiary-35)", + "tertiary-40": "var(--color-tertiary-40)", + "tertiary-50": "var(--color-tertiary-50)", + "tertiary-60": "var(--color-tertiary-60)", + "tertiary-70": "var(--color-tertiary-70)", + "tertiary-80": "var(--color-tertiary-80)", + "tertiary-90": "var(--color-tertiary-90)", + "tertiary-95": "var(--color-tertiary-95)", + "tertiary-98": "var(--color-tertiary-98)", + "tertiary-99": "var(--color-tertiary-99)", + "tertiary-100": "var(--color-tertiary-100)", + "neutral-0": "var(--color-neutral-0)", + "neutral-5": "var(--color-neutral-5)", + "neutral-10": "var(--color-neutral-10)", + "neutral-15": "var(--color-neutral-15)", + "neutral-20": "var(--color-neutral-20)", + "neutral-25": "var(--color-neutral-25)", + "neutral-30": "var(--color-neutral-30)", + "neutral-35": "var(--color-neutral-35)", + "neutral-40": "var(--color-neutral-40)", + "neutral-50": "var(--color-neutral-50)", + "neutral-60": "var(--color-neutral-60)", + "neutral-70": "var(--color-neutral-70)", + "neutral-80": "var(--color-neutral-80)", + "neutral-90": "var(--color-neutral-90)", + "neutral-95": "var(--color-neutral-95)", + "neutral-98": "var(--color-neutral-98)", + "neutral-99": "var(--color-neutral-99)", + "neutral-100": "var(--color-neutral-100)", + "neutral-variant-0": "var(--color-neutral-variant-0)", + "neutral-variant-5": "var(--color-neutral-variant-5)", + "neutral-variant-10": "var(--color-neutral-variant-10)", + "neutral-variant-15": "var(--color-neutral-variant-15)", + "neutral-variant-20": "var(--color-neutral-variant-20)", + "neutral-variant-25": "var(--color-neutral-variant-25)", + "neutral-variant-30": "var(--color-neutral-variant-30)", + "neutral-variant-35": "var(--color-neutral-variant-35)", + "neutral-variant-40": "var(--color-neutral-variant-40)", + "neutral-variant-50": "var(--color-neutral-variant-50)", + "neutral-variant-60": "var(--color-neutral-variant-60)", + "neutral-variant-70": "var(--color-neutral-variant-70)", + "neutral-variant-80": "var(--color-neutral-variant-80)", + "neutral-variant-90": "var(--color-neutral-variant-90)", + "neutral-variant-95": "var(--color-neutral-variant-95)", + "neutral-variant-98": "var(--color-neutral-variant-98)", + "neutral-variant-99": "var(--color-neutral-variant-99)", + "neutral-variant-100": "var(--color-neutral-variant-100)", + "error-0": "var(--color-error-0)", + "error-5": "var(--color-error-5)", + "error-10": "var(--color-error-10)", + "error-15": "var(--color-error-15)", + "error-20": "var(--color-error-20)", + "error-25": "var(--color-error-25)", + "error-30": "var(--color-error-30)", + "error-35": "var(--color-error-35)", + "error-40": "var(--color-error-40)", + "error-50": "var(--color-error-50)", + "error-60": "var(--color-error-60)", + "error-70": "var(--color-error-70)", + "error-80": "var(--color-error-80)", + "error-90": "var(--color-error-90)", + "error-95": "var(--color-error-95)", + "error-98": "var(--color-error-98)", + "error-99": "var(--color-error-99)", + "error-100": "var(--color-error-100)" + } } + }, + "variables": { + "--color-light-primary-palette-key-color": "#6b73ad", + "--color-light-secondary-palette-key-color": "#74768c", + "--color-light-tertiary-palette-key-color": "#926c86", + "--color-light-neutral-palette-key-color": "#77767d", + "--color-light-neutral-variant-palette-key-color": "#767680", + "--color-light-error-palette-key-color": "#de3730", + "--color-light-background": "#fbf8ff", + "--color-light-on-background": "#1b1b21", + "--color-light-surface": "#fbf8ff", + "--color-light-surface-dim": "#dbd9e0", + "--color-light-surface-bright": "#fbf8ff", + "--color-light-surface-container-lowest": "#ffffff", + "--color-light-surface-container-low": "#f5f2fa", + "--color-light-surface-container": "#efedf4", + "--color-light-surface-container-high": "#e9e7ef", + "--color-light-surface-container-highest": "#e4e1e9", + "--color-light-on-surface": "#1b1b21", + "--color-light-surface-variant": "#e3e1ec", + "--color-light-on-surface-variant": "#46464f", + "--color-light-outline": "#767680", + "--color-light-outline-variant": "#c7c5d0", + "--color-light-inverse-surface": "#303036", + "--color-light-inverse-on-surface": "#f2eff7", + "--color-light-shadow": "#000000", + "--color-light-scrim": "#000000", + "--color-light-surface-tint": "#525a92", + "--color-light-primary": "#525a92", + "--color-light-primary-dim": "#464e85", + "--color-light-on-primary": "#ffffff", + "--color-light-primary-container": "#dfe0ff", + "--color-light-on-primary-container": "#3a4279", + "--color-light-inverse-primary": "#bbc3ff", + "--color-light-primary-fixed": "#dfe0ff", + "--color-light-primary-fixed-dim": "#bbc3ff", + "--color-light-on-primary-fixed": "#0c154b", + "--color-light-on-primary-fixed-variant": "#3a4279", + "--color-light-secondary": "#5b5d72", + "--color-light-secondary-dim": "#4f5165", + "--color-light-on-secondary": "#ffffff", + "--color-light-secondary-container": "#e0e1f9", + "--color-light-on-secondary-container": "#434559", + "--color-light-secondary-fixed": "#e0e1f9", + "--color-light-secondary-fixed-dim": "#c4c5dd", + "--color-light-on-secondary-fixed": "#181a2c", + "--color-light-on-secondary-fixed-variant": "#434559", + "--color-light-tertiary": "#77536c", + "--color-light-tertiary-dim": "#6a4860", + "--color-light-on-tertiary": "#ffffff", + "--color-light-tertiary-container": "#ffd7f0", + "--color-light-on-tertiary-container": "#5d3c54", + "--color-light-tertiary-fixed": "#ffd7f0", + "--color-light-tertiary-fixed-dim": "#e6bad7", + "--color-light-on-tertiary-fixed": "#2d1227", + "--color-light-on-tertiary-fixed-variant": "#5d3c54", + "--color-light-error": "#ba1a1a", + "--color-light-error-dim": "#a80710", + "--color-light-on-error": "#ffffff", + "--color-light-error-container": "#ffdad6", + "--color-light-on-error-container": "#93000a", + "--color-dark-primary-palette-key-color": "#6b73ad", + "--color-dark-secondary-palette-key-color": "#74768c", + "--color-dark-tertiary-palette-key-color": "#926c86", + "--color-dark-neutral-palette-key-color": "#77767d", + "--color-dark-neutral-variant-palette-key-color": "#767680", + "--color-dark-error-palette-key-color": "#de3730", + "--color-dark-background": "#131318", + "--color-dark-on-background": "#e4e1e9", + "--color-dark-surface": "#131318", + "--color-dark-surface-dim": "#131318", + "--color-dark-surface-bright": "#39393f", + "--color-dark-surface-container-lowest": "#0d0e13", + "--color-dark-surface-container-low": "#1b1b21", + "--color-dark-surface-container": "#1f1f25", + "--color-dark-surface-container-high": "#29292f", + "--color-dark-surface-container-highest": "#34343a", + "--color-dark-on-surface": "#e4e1e9", + "--color-dark-surface-variant": "#46464f", + "--color-dark-on-surface-variant": "#c7c5d0", + "--color-dark-outline": "#90909a", + "--color-dark-outline-variant": "#46464f", + "--color-dark-inverse-surface": "#e4e1e9", + "--color-dark-inverse-on-surface": "#303036", + "--color-dark-shadow": "#000000", + "--color-dark-scrim": "#000000", + "--color-dark-surface-tint": "#bbc3ff", + "--color-dark-primary": "#bbc3ff", + "--color-dark-primary-dim": "#b8c0ff", + "--color-dark-on-primary": "#232c61", + "--color-dark-primary-container": "#3a4279", + "--color-dark-on-primary-container": "#dfe0ff", + "--color-dark-inverse-primary": "#525a92", + "--color-dark-primary-fixed": "#dfe0ff", + "--color-dark-primary-fixed-dim": "#bbc3ff", + "--color-dark-on-primary-fixed": "#0c154b", + "--color-dark-on-primary-fixed-variant": "#3a4279", + "--color-dark-secondary": "#c4c5dd", + "--color-dark-secondary-dim": "#dadbf4", + "--color-dark-on-secondary": "#2d2f42", + "--color-dark-secondary-container": "#434559", + "--color-dark-on-secondary-container": "#e0e1f9", + "--color-dark-secondary-fixed": "#e0e1f9", + "--color-dark-secondary-fixed-dim": "#c4c5dd", + "--color-dark-on-secondary-fixed": "#181a2c", + "--color-dark-on-secondary-fixed-variant": "#434559", + "--color-dark-tertiary": "#e6bad7", + "--color-dark-tertiary-dim": "#fed0ee", + "--color-dark-on-tertiary": "#45263d", + "--color-dark-tertiary-container": "#5d3c54", + "--color-dark-on-tertiary-container": "#ffd7f0", + "--color-dark-tertiary-fixed": "#ffd7f0", + "--color-dark-tertiary-fixed-dim": "#e6bad7", + "--color-dark-on-tertiary-fixed": "#2d1227", + "--color-dark-on-tertiary-fixed-variant": "#5d3c54", + "--color-dark-error": "#ffb4ab", + "--color-dark-error-dim": "#ff554a", + "--color-dark-on-error": "#690005", + "--color-dark-error-container": "#93000a", + "--color-dark-on-error-container": "#ffdad6", + "--color-source": "#0c1445", + "--color-primary-0": "#000000", + "--color-primary-5": "#010841", + "--color-primary-10": "#0c154b", + "--color-primary-15": "#182055", + "--color-primary-20": "#232c61", + "--color-primary-25": "#2f376c", + "--color-primary-30": "#3a4279", + "--color-primary-35": "#464e85", + "--color-primary-40": "#525a92", + "--color-primary-50": "#6b73ad", + "--color-primary-60": "#858dc8", + "--color-primary-70": "#9fa7e5", + "--color-primary-80": "#bbc3ff", + "--color-primary-90": "#dfe0ff", + "--color-primary-95": "#f0efff", + "--color-primary-98": "#fbf8ff", + "--color-primary-99": "#fffbff", + "--color-primary-100": "#ffffff", + "--color-secondary-0": "#000000", + "--color-secondary-5": "#0d1021", + "--color-secondary-10": "#181a2c", + "--color-secondary-15": "#222537", + "--color-secondary-20": "#2d2f42", + "--color-secondary-25": "#383a4d", + "--color-secondary-30": "#434559", + "--color-secondary-35": "#4f5165", + "--color-secondary-40": "#5b5d72", + "--color-secondary-50": "#74768b", + "--color-secondary-60": "#8e8fa6", + "--color-secondary-70": "#a8a9c1", + "--color-secondary-80": "#c4c5dd", + "--color-secondary-90": "#e0e1f9", + "--color-secondary-95": "#f0efff", + "--color-secondary-98": "#fbf8ff", + "--color-secondary-99": "#fffbff", + "--color-secondary-100": "#ffffff", + "--color-tertiary-0": "#000000", + "--color-tertiary-5": "#21071c", + "--color-tertiary-10": "#2d1227", + "--color-tertiary-15": "#391c32", + "--color-tertiary-20": "#45263d", + "--color-tertiary-25": "#513148", + "--color-tertiary-30": "#5d3c54", + "--color-tertiary-35": "#6a4860", + "--color-tertiary-40": "#77536c", + "--color-tertiary-50": "#916c86", + "--color-tertiary-60": "#ad85a0", + "--color-tertiary-70": "#c99fbb", + "--color-tertiary-80": "#e6bad7", + "--color-tertiary-90": "#ffd7f0", + "--color-tertiary-95": "#ffecf6", + "--color-tertiary-98": "#fff7f9", + "--color-tertiary-99": "#fffbff", + "--color-tertiary-100": "#ffffff", + "--color-neutral-0": "#000000", + "--color-neutral-5": "#101116", + "--color-neutral-10": "#1b1b21", + "--color-neutral-15": "#25252b", + "--color-neutral-20": "#303036", + "--color-neutral-25": "#3b3b41", + "--color-neutral-30": "#46464c", + "--color-neutral-35": "#525258", + "--color-neutral-40": "#5e5e64", + "--color-neutral-50": "#77767d", + "--color-neutral-60": "#919097", + "--color-neutral-70": "#acaab1", + "--color-neutral-80": "#c7c5cd", + "--color-neutral-90": "#e4e1e9", + "--color-neutral-95": "#f2eff7", + "--color-neutral-98": "#fbf8ff", + "--color-neutral-99": "#fffbff", + "--color-neutral-100": "#ffffff", + "--color-neutral-variant-0": "#000000", + "--color-neutral-variant-5": "#101018", + "--color-neutral-variant-10": "#1a1b23", + "--color-neutral-variant-15": "#25252d", + "--color-neutral-variant-20": "#2f3038", + "--color-neutral-variant-25": "#3a3b43", + "--color-neutral-variant-30": "#46464f", + "--color-neutral-variant-35": "#52525b", + "--color-neutral-variant-40": "#5e5e67", + "--color-neutral-variant-50": "#767680", + "--color-neutral-variant-60": "#90909a", + "--color-neutral-variant-70": "#abaab4", + "--color-neutral-variant-80": "#c7c5d0", + "--color-neutral-variant-90": "#e3e1ec", + "--color-neutral-variant-95": "#f1effa", + "--color-neutral-variant-98": "#fbf8ff", + "--color-neutral-variant-99": "#fffbff", + "--color-neutral-variant-100": "#ffffff", + "--color-error-0": "#000000", + "--color-error-5": "#2d0001", + "--color-error-10": "#410002", + "--color-error-15": "#540003", + "--color-error-20": "#690005", + "--color-error-25": "#7e0007", + "--color-error-30": "#93000a", + "--color-error-35": "#a80710", + "--color-error-40": "#ba1a1a", + "--color-error-50": "#de3730", + "--color-error-60": "#ff5449", + "--color-error-70": "#ff897d", + "--color-error-80": "#ffb4ab", + "--color-error-90": "#ffdad6", + "--color-error-95": "#ffedea", + "--color-error-98": "#fff8f7", + "--color-error-99": "#fffbff", + "--color-error-100": "#ffffff" } } \ No newline at end of file