--gog-*
Theming
Every value the library paints with is a plain CSS custom property. No build step, no Sass config, no JS theming API required to change how it looks.
Pick a component, tweak its tokens live and copy the result — no IDE guesswork.
Guild of Gleks UI is themed entirely through CSS custom properties (--gog-*). There is
no build step, Sass config or JS theming API required to change how it looks — every
value the library paints with can be overridden from plain CSS.
How theming is layered
Foundation — the base palette, type scale, spacing and motion tokens (
--gog-accent-color,--gog-background-color,--gog-text-xs,--gog-radius, …). Overriding these restyles the whole library at once.Component — tokens scoped to one component (
--gog-button-*,--gog-accordion-*,--gog-table-*, …). Most derive from the foundation layer, so a palette swap already carries through; override a component token directly only when you need to restyle just that component.Instance — a handful of tokens (
--gog-button-bg,--gog-tag-bg, …) are left undeclared on purpose, as an escape hatch for styling a single element without touching a theme at all:html<gog-button style="--gog-button-bg: #ff4edb">One-off button</gog-button>
The character layer
A named part of Foundation, and the short path to a custom look: corner rounding
(--gog-radius), the three border-weight tiers (--gog-control-border-* for form fields,
--gog-panel-border-* for raised surfaces like dialogs, and the plain --gog-border-* pair
for everything smaller and inline — chip, tag, table row), emphasis casing and tracking
(--gog-text-transform, --gog-letter-spacing), weight (--gog-font-weight-medium …
-heavy) and leading (--gog-line-height-none … -loose), and density (--gog-density,
the single multiplier every padding and gap in the library derives from). Most component tokens
read one of these instead of declaring their own literal, so a theme is expected to set these —
not the dozens of component tokens that derive from them. material.css, primeng.css and
ledger.css are what a theme with real character looks like once it uses this layer instead of
re-listing component tokens: each is a short list of declarations, not a fork of the whole
stylesheet. Try them in the Theme Generator, which edits this exact
layer live.
One number instead of fifty
The axes above are all the same bet: a value that appears in many component tokens is worth
extracting so a theme can move all of them at once. It is worth stating plainly, because the
alternative looks reasonable right up until you try it — a house style that wants lighter chrome
edits --gog-font-weight-*, not the fifteen component weights that used to each hold a bare
number, and one that wants roomier text edits --gog-line-height-* rather than the twenty that
held theirs. Seven of those twenty were the same 1.4, which is what a missing axis looks like
from the inside: the same decision made over and over, independently, with nothing naming it.
--gog-z-base is the clearest demonstration, because you can watch the whole library move.
It is the stacking floor, and every layer is base + N — badge +1, toast +100, dropdowns,
dialogs and menus +300, tooltip +400, the blocking spinner overlay +8000. An app with its
own fixed header that has to sit above or below the library changes one number:
:root {
--gog-z-base: 10000;
}
Every layer follows and the order between them is untouched — the badge is still under the
toast, the tooltip still over the dropdown. Setting --gog-dropdown-z directly is the version
of this that goes wrong: it moves one layer out of a stack the other four still agree on.
The elevation ladder
21.12.0 The same bet again, and the clearest case of it, because before the ladder eleven themes hand-authored twenty-two shadow values with no stated relationship between any two of them — and two of those themes gave a modal dialog the elevation of a card, because restating the second value was work.
There is now one ladder of six heights, --gog-elevation-0 through -5, and every raised
surface in the package reads a step off it. Z doubles: 0, 1, 2, 4, 8, 16. A height is assigned by
what a thing is, not by how heavy it should look:
| Step | What sits on it |
|---|---|
| 0 | flat — in the flow of the page |
| 1 | a thumb riding on a control (the toggle's) |
| 2 | an elevated card or panel |
| 3 | anything anchored to a control — the four dropdown panels, the menu, the tooltip |
| 4 | a toast |
| 5 | a modal dialog |
You do not write a step. A theme turns ten knobs and all six follow:
:root[data-theme='midnight'],
[data-theme='midnight'] {
--gog-elevation-ink: 0 0 0; /* unwrapped RGB, so the alphas below can composite it */
--gog-elevation-key-alpha: 0.55;
--gog-elevation-ambient-alpha: 0.28;
--gog-elevation-contact-blur: 3px;
--gog-elevation-key-x: 0;
--gog-elevation-key-y: 1;
--gog-elevation-key-blur: 3;
--gog-elevation-ring-width: 1px;
--gog-elevation-highlight-ink: 255 255 255;
--gog-elevation-highlight-alpha: 0.07;
}
State all ten or none — and this is the one that will bite. Custom properties inherit, so a theme block declaring six of them silently borrows the other four from whatever encloses it. There is no error; you get a shadow that looks nearly right, on some surfaces, in one theme.
A step is two lights. The contact shadow hugs the object and does not grow with height — that
is what ambient occlusion does, and it is what this library already did every time it hand-wrote
two soft layers. The key light is the one that moves: its offset is Z and its blur three times
it. Those three multipliers are the style axis, and between them they cover every look the eleven
shipped presets actually use. Soft is the default. A hard-offset theme — bevel, ledger — sets
x and y to a fraction and blur to 0. A glow theme — terminal — sets y to 0 and keeps the
blur, and the key light becomes a halo without the ladder knowing anything about halos.
Two things are deliberately outside the steps, as their own tokens: the hairline ring and the
top-edge catch light. They belong to particular surfaces rather than to height — a dark theme's
overlay wants the ring and its in-flow elevated card must not have it, or elevated and
outlined render identically. A component composes them:
box-shadow: var(--gog-elevation-ring), var(--gog-elevation-3).
--gog-panel-shadow, --gog-dialog-shadow and --gog-toast-shadow are still the names you
override for one surface, and overriding one works exactly as it always did. What changed is their
value: each is now a step rather than a literal, so a theme that turns one knob moves all of them
together and keeps the order between them intact.
--gog-density is the same idea applied to spacing, and since 21.9.0 the claim above it is
literally true rather than nearly so. Fourteen lengths were still bare pixels that ignored it —
dropdown panel gaps, the menu offset, a clear button's inset, two error-line offsets — so a
theme that tightened everything left those where they were. They read the scale now, which is
worth knowing if you had compensated for it.
What index.css pulls in
One import is the whole setup, and it is a thin wrapper over four files:
| File | What it carries |
|---|---|
theme.css |
every --gog-* token the components read, in both the light and dark layers |
typography.css |
the font-body / font-heading helpers component templates apply to themselves |
utilities.css |
the utility classes those templates rely on (gog-contained-layout, …) |
button.css 21.4.0 |
the [gogButton] directive's styles — global because that directive styles an element you wrote (an <a>), which no component stylesheet can reach |
fonts.css is deliberately not among them: it pulls three families from Google Fonts, which a
library has no business imposing. Import it explicitly if you want this site's typography.
The full catalogue of tokens ships with the package as TOKENS.md — generated from
theme.css, so it cannot drift. The Token Reference at the bottom of this page is the same data,
browsable.
Built-in themes
The library ships two themes, light and dark, switched with a data-theme
attribute on any element (usually <html>):
<html data-theme="dark"></html>
data-theme can also be scoped to a smaller subtree, so several themes can render
side by side on the same page.
Ready-made presets
Nine presets ship as importable stylesheets, each at styles/presets/<name>.css and
activated by data-theme="<name>". Until 21.7.0 there were three and each declared palette
tokens only; that framing is gone. All nine now set palette and character — corner
rounding, border weight, density, label casing — which is what makes them identities rather than
recolours. None of them names a single component token it does not have to.
| Preset | data-theme |
The identity |
|---|---|---|
| Slate | slate |
soft modern — 12px corners, hairline borders, roomier than the default |
| One Dark / One Light | one-dark, one-light |
editor chrome — 4px corners, compact, sentence case; one UI, two tones |
| Material / PrimeNG | material, primeng |
Material Design 3 and PrimeNG Aura, including their shape and density |
| Ledger | ledger |
administrative software — square corners, hard offset shadow, no motion |
| Terminal | terminal |
green phosphor — monospaced throughout, square, no motion |
| Bevel | bevel |
the early-web desktop — raised buttons, sunken fields, grey and navy |
| Parchment | parchment |
ink on laid paper — old-style serif, oxblood accent, roomy |
Every one of them is in the theme switcher in this site's header. Try material or primeng
against the comparison pages: those two are the point of the exercise made literal — the
library wearing another ecosystem's identity, from one imported stylesheet and no component code.
Add the one you want to your global styles, then set the attribute:
"styles": [
"node_modules/@guildofgleks/ui/styles/index.css",
"node_modules/@guildofgleks/ui/styles/presets/one-dark.css",
"src/styles.scss"
]
The short path arrived in 21.3.2 21.3.2 and is the only one from 21.5.0, which dropped the duplicate
./src/styles/*export. If yourangular.jsonstill names@guildofgleks/ui/src/styles/…, drop thesrc/segment. The short path is listed in the package'sexportsmap, which means it resolves from a SCSS@import '@guildofgleks/ui/styles/theme.css'as well; the old path never did.
<html data-theme="one-dark"></html>
The One presets map the editor's syntax hues onto the library's semantic roles — blue becomes the
accent, and green / red / yellow / cyan become success / danger / warning / info. Neither preset
mentions --gog-button-primary-bg by name, yet buttons pick it up: that is the derived layer
re-resolving, and it is why a preset can be a short list of declarations rather than a fork of the
whole stylesheet.
No preset downloads a font
Importing a preset never adds a network request. Each one sets a stack that resolves to a real
system face — the platform's own monospace for terminal, Tahoma/Verdana for bevel, Iowan Old
Style/Palatino for parchment. Where a webfont makes a visible difference it lives in a separate
opt-in file you import after the preset:
@import '@guildofgleks/ui/styles/presets/parchment.css';
@import '@guildofgleks/ui/styles/presets/parchment.fonts.css'; /* optional: EB Garamond */
terminal.fonts.css (IBM Plex Mono) is the other one. This site imports neither, on purpose:
a global stylesheet is loaded whether or not anyone picks that theme, and making every visitor pay
for a font two of eleven themes use would contradict the rule this section is stating. So
terminal and parchment render here in their system stacks — which is exactly what a consumer
who imports the preset alone will see.
Switching the theme from code
ThemeService wraps that attribute in a signal-based API:
import { Component, inject } from '@angular/core';
import { ThemeService } from '@guildofgleks/ui';
@Component({
selector: 'app-theme-switcher',
template: `
<button (click)="setDark()">Dark</button>
<button (click)="toggle()">Toggle</button>
`,
})
export class ThemeSwitcher {
private readonly themeService = inject(ThemeService);
protected readonly theme = this.themeService.theme; // Signal<string> — read-only
setDark(): void {
this.themeService.setTheme('dark');
}
toggle(): void {
this.themeService.toggleTheme(); // flips between 'light' and 'dark'
}
}
theme is a read-only Signal, so setTheme / toggleTheme are the only way to change it.
That is the point: the service also writes the data-theme attribute and persists the choice, and
a .set() straight onto the signal skipped both — the document kept its old theme while the signal
claimed otherwise.
Which theme it starts on, whether the choice survives a reload, and whether it follows the OS
setting are all configured through GOG_CONFIG.theme
21.3.2 — see
Global Configuration.
This is exactly what the theme switcher (the palette icon) in this site's header uses.
Building your own theme
Declare a palette against a new data-theme value. List both selectors so the theme
works at the document root and on any subtree:
:root[data-theme='midnight'],
[data-theme='midnight'] {
color-scheme: dark;
/* Surfaces */
--gog-background-color: #0b0f1a;
--gog-surface-color: #131a2b;
--gog-hover-color: #1c2540;
--gog-border-color: #2a355a; /* decoration: dividers, table rules, panel outlines */
--gog-control-boundary-color: #6b7aa8; /* identity: the edge of a chip, a switch, a segment */
/* Text */
--gog-text-color: #e8ecf7;
--gog-muted-text-color: #8892b0;
--gog-accent-text-color: #0b0f1a;
/* Brand & accents */
--gog-primary-color: #e8ecf7;
--gog-accent-color: #5b8dff;
--gog-accent-bright: #82a9ff;
--gog-accent-dim: #35528f;
--gog-accent-pale: #1c2c52;
--gog-secondary-color: #7b6bff;
/* Semantic */
--gog-success-color: #2fbf71;
--gog-danger-color: #ef4565;
--gog-warning-color: #f2a541;
--gog-info-color: #38bdf8;
/* Elevation — all ten knobs or none; see the ladder above */
--gog-elevation-ink: 0 0 0;
--gog-elevation-key-alpha: 0.55;
--gog-elevation-ambient-alpha: 0.28;
--gog-elevation-contact-blur: 3px;
--gog-elevation-key-x: 0;
--gog-elevation-key-y: 1;
--gog-elevation-key-blur: 3;
--gog-elevation-ring-width: 1px;
--gog-elevation-highlight-ink: 255 255 255;
--gog-elevation-highlight-alpha: 0.07;
}
Then switch to it exactly like a built-in theme:
themeService.setTheme('midnight');
Because every component token derives from these foundation tokens, a new palette propagates through buttons, tables, dialogs and everything else without touching a single component stylesheet.
Colour that is checked rather than eyeballed
A theme is the one part of this library a consumer writes from scratch, and colour is the part of that which fails silently: nothing renders wrong, nothing throws, and some fraction of your readers simply cannot use the result. So the palettes here are computed and gated rather than picked, and the tooling that does it ships in the repository.
Two kinds of border, and only one of them is a boundary
--gog-border-color is decoration — dividers, table rules, panel outlines — and is deliberately
faint. --gog-control-boundary-color
21.12.0 is the edge that identifies a
control, and WCAG SC 1.4.11 requires it to clear 3:1 against whatever the control sits on.
They cannot be one token, and the proof is what happened while they were: gog-chip, gog-toggle
and gog-button-toggle read the decorative colour as their own edge and measured 1.18 to 2.17:1
in every shipped theme — neither their border nor their fill carried the boundary, so a switch in
its off state was, to WCAG, not there. A theme that sets only the decorative colour has to choose
between shouting its dividers and hiding its controls. Set both.
suggest:color — a check that names the value that would pass
A failing ratio tells you something is wrong; it does not tell you what to write instead. The repository ships a solver that does:
npm run suggest:color -- '#2a355a' '#131a2b' 3.2
# #2a355a on #131a2b: 1.45:1 → #5b6991 3.20:1 (hue and chroma held)
It walks lightness in OKLCH and holds hue and chroma, so the value it hands back is still recognisably your theme's neutral rather than a grey that happens to pass. Every one of the eleven shipped presets' boundary colours was produced this way.
What a contrast ratio cannot see
WCAG's ratio is a luminance formula. It is the right tool for "can this text be read", and it is
blind to three things that are just as much defects — all three passed it comfortably while being
wrong. npm run check:oklch
21.12.0 gates them, in OKLCH, where lightness,
chroma and hue come apart:
- A state step that is invisible. Hover and pressed have to read as different from the rest state. Gated at ΔL ≥ 0.03, roughly the just-noticeable difference for an area of flat colour.
- A status colour that has stopped being a colour. Near-grey stops signalling; maximum chroma reads as neon in a parchment theme. Gated to a band, 0.04 ≤ C ≤ 0.25.
- Two statuses that are the same colour. Every pair of the four must differ by ≥15° of hue
or ≥0.10 of lightness — a disjunction, because hue alone fails a reader with achromatopsia
and lightness alone fails nothing at all.
terminal's success and info sat 4.6° apart, which is two statuses one badge could not tell apart in any rendering.
Every threshold was measured across all eleven palettes before it was set, never the other way round — a threshold chosen in advance is a threshold chosen to flatter what is already there. One rule that looked obvious did not survive that: "the ramp must be monotonic in lightness" fails eight of the eleven, and eight of them are right, because on a light ground the hover fill is darker than the rest state. What is checkable is that the step exists, not which way it points.
Between them, check:contrast (3995 pairs across the eleven themes, including every control
boundary and every focus indicator) and check:oklch are CI steps. If you fork a preset, they are
worth running against your own file.
Rules of thumb
- Prefer overriding foundation tokens over chasing individual component tokens — you get the whole library restyled for the price of one palette.
- Don't hardcode colors in your app that duplicate a token — reference the token instead, so it keeps following theme switches.
- A panel appended to
<body>(dropdowns with[appendToBody], toasts, tooltips, the datepicker's calendar) follows its trigger's theme, not the DOM position it renders at — no extra wiring needed on your side. When the theme is scoped to a subtree the panel gets a copy of thatdata-theme; when it sits on<html>, as it usually does, plain inheritance already does the job. - Custom properties set inline on
<html>reach overlays too, which is what makes a runtime theme editor — like this site's Theme Generator — work. Before 21.4.1 an overlay copied the document'sdata-themeonto itself and, in doing so, re-declared every component token from the plain preset, discarding anything the page had set on the root.
The Elevation Ladder
Six heights, one per step, on this theme's own surface colour. Z doubles — 0, 1, 2, 4, 8, 16 — and every raised surface in the package reads one of them. Change the theme in the header and watch all six move together: that is the whole point of the family.
On a dark theme these six will look nearly alike, and that is the honest result rather than a broken demo: a black blur on a near-black page reads as smudge, not as lift. Each tile here paints the step alone, which is what the token is. A real component composes it with the two layers that sit outside the ladder — box-shadow: var(--gog-elevation-ring), var(--gog-elevation-3) — and on a dark theme it is that hairline ring and the top-edge catch light doing the work the shadow cannot. Switch to a light theme to watch the ladder itself climb.
Token Reference
Every CSS custom property a component paints with, grouped by area. Override any of them — on a single instance, a subtree, or a theme — to restyle the library.
| Token | Value | Description |
|---|---|---|
--gog-background-color | | Page / app background. |
--gog-surface-color | | Card, panel and control surface background. |
--gog-hover-color | | Hover background for interactive surfaces. |
--gog-border-color | | The decorative hairline — dividers, table rules, panel outlines — and deliberately faint. It is not the edge of a control; that is the token below. |
--gog-control-boundary-color | | The edge that identifies a control, and the one WCAG SC 1.4.11 measures: it has to clear 3:1 against whatever the control sits on. Split off from --gog-border-color in 21.12.0, because one token cannot be both — a theme that sets only the decorative one either shouts its dividers or hides its controls, and three of this package’s own presets were doing the second, at 1.18 to 2.17:1. gog-chip, gog-toggle and gog-button-toggle read it. Set both, and check the boundary rather than eyeballing it: npm run suggest:color in the repo computes a value that clears a target ratio while holding your theme’s own hue and chroma. |
--gog-text-color | | Primary text color. |
--gog-muted-text-color | | Secondary / placeholder text color. |
--gog-accent-text-color | | Text color placed on top of an accent-colored background. |
--gog-primary-color | | Primary brand color. |
--gog-accent-color | | Accent / brand color used for interactive elements. |
--gog-accent-bright | | Brighter accent, used for hover states. |
--gog-accent-dim | | Dimmed accent, used for borders and strokes. |
--gog-accent-pale | | Pale accent tint, used for subtle backgrounds. |
--gog-secondary-color | | Secondary brand color. |
--gog-success-color | | Semantic success color. |
--gog-danger-color | | Semantic danger / error color. |
--gog-warning-color | | Semantic warning color. |
--gog-info-color | | Semantic info color. |
--gog-success-text-color / --gog-danger-text-color / --gog-warning-text-color / --gog-info-text-color | | The label a status fill carries, the way --gog-accent-text-color is the accent’s. Each defaults to the accent’s answer, so state one only where your own hue disagrees — and check it, because getting this wrong is silent: white on a bright amber measured 1.97:1 in one of this package’s own presets before these existed. |
--gog-success-shade / --gog-danger-shade / --gog-warning-shade / --gog-info-shade | | Which way a status fill deepens when hovered or held: away from its own label, so the state always makes the label easier to read rather than harder. Defaults to the page’s ink, which is right when the label is white — set it to the opposite when the label is the ink itself. |
--gog-panel-shadow / --gog-dialog-shadow / --gog-toast-shadow | | The surfaces that lift, and still the names you override for one of them. Since 21.12.0 their value is a step off the elevation ladder rather than a hand-written shadow — panel 3, toast 4, dialog 5 — so turning one knob in the Elevation family moves all of them together and keeps the order between them. The gog-panel component reads the first. |
| Token | Value | Description |
|---|---|---|
--gog-font-heading | | Font stack used for headings and titles. |
--gog-font-body | | Font stack used for body text. |
--gog-font-mono | | Monospace font stack (code, numeric values). |
--gog-text-xs … --gog-text-3xl | | Type scale, from 0.75rem to 3rem. |
--gog-text-2xs | | 0.6875rem (11px), one step below xs and the bottom of the scale. It exists because the smallest chip and the smallest tag were already painting 11px as a literal — the step was being used before it had a name. |
--gog-text-slg | | 20px, between lg and xl — named for the control size it serves rather than continuing the t-shirt run, because that is what asked for it. gog-button and the field controls both needed a step for their slg size and, having none, both wrote 1.25rem as a literal. |
| Token | Value | Description |
|---|---|---|
--gog-radius | | Base corner radius used across most components. |
--gog-panel-radius | | Corner radius for larger panels, derived from --gog-radius — and the gog-panel component’s own, which reads the same token. |
--gog-border-width / --gog-border-style | | Border weight for small inline elements — chip, tag, table row — the tier below panel and control. |
--gog-panel-border-width / --gog-panel-border-style | | Border width and style for elevated panels — and for the gog-panel component, which reads the same pair. |
--gog-control-border-width / -style | | Border weight for form controls (buttons, fields) — the thickest of the three tiers. |
--gog-text-transform | | Emphasis casing shared by buttons, section headers, table headers and field labels. |
--gog-letter-spacing | | Emphasis tracking, paired with --gog-text-transform. |
--gog-font-weight-medium / -semibold / -bold / -heavy | | Weight, the third character axis. Four steps because four are painted — there is no normal, since nothing in the library uses 400. Set these and every component weight follows; before them, fifteen component tokens each held a bare number. |
--gog-line-height-none / -tight / -snug / -normal / -relaxed / -loose | | Leading, the fourth. Six steps because six values are painted. gog-panel’s heading keeps its own 1.25, off this scale on purpose the way an 11px chip is off the type scale. |
--gog-density | | Single multiplier every component padding and gap derives from — set once for a tighter or roomier library, never a component padding directly. |
| Token | Value | Description |
|---|---|---|
--gog-space-4 … --gog-space-48 | | The ten-step scale every padding and gap in the library is built from — 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, every one of them a multiple of 4. Each step is calc(Npx * var(--gog-density)), so the whole scale moves together when density changes. It was fourteen steps until 21.11.0; the five odd ones (2, 6, 10, 14, 18) are gone, and a stylesheet still naming one should take the neighbouring step, rounding up, which is the direction the library itself took. |
--gog-space-xs … --gog-space-2xl | | Five named aliases onto that scale — 4, 8, 16, 24 and 48px at density 1. Convenience names, not a second scale: they derive from the numeric steps above, so overriding one with a literal takes it out of density. |
| Token | Value | Description |
|---|---|---|
--gog-duration-fast / -base / -slow | | Transition durations used by every animated component. |
--gog-easing | | Default transition easing function. |
--gog-focus-ring-width / --gog-focus-ring-offset | | Keyboard focus ring size and offset. |
--gog-disabled-opacity | | Opacity applied to disabled controls. |
--gog-{block}-press-bg | | The pressed background, on each of the nine pressable surfaces (button, menu item, chip, tab and accordion header, button-toggle option and the three dropdowns’ option rows). Listed here as well because they share a rule: a press is a colour and not only a movement, so it is the half that survives prefers-reduced-motion. The ripple is the deliberate exception — it is suppressed there, being decoration rather than state. |
| Token | Value | Description |
|---|---|---|
--gog-z-base | | The library’s stacking floor, and the only one of these you set. Every layer is base + N, so moving it lifts the whole library at once and keeps the internal order intact. |
--gog-badge-z / --gog-toast-base-z / --gog-dropdown-z / --gog-tooltip-z / --gog-spinner-overlay-z | | The five layers themselves — +1, +100, +300 (dropdowns, dialogs and menus), +400 and +8000 (the blocking overlay, which outranks even a dialog it covers). Derived, so overriding one takes it out of the base and should be a deliberate exception rather than the way you move the stack. |
| Token | Value | Description |
|---|---|---|
--gog-elevation-0 … --gog-elevation-5 | | The ladder: six heights, generated from the knobs below, and every raised surface in the package reads one. Z doubles — 0, 1, 2, 4, 8, 16 — and the heights are assigned by what a thing is, not by how it looks: 0 flat, 1 a thumb riding on a control, 2 an elevated card or panel, 3 anything anchored to a control (the four dropdown panels, the menu, the tooltip), 4 a toast, 5 a modal dialog. You do not write a step; you turn the knobs and all six follow. |
--gog-elevation-ink / -key-alpha / -ambient-alpha | | The colour of the shadow, as an unwrapped RGB triple, and the two opacities it composites at. A step is two lights: the ambient contact shadow that hugs the object and the key light that moves with height. The default ambient is half the key, which is the ratio the light theme’s hand-written panel already held. |
--gog-elevation-key-x / -key-y / -key-blur | | The style axis, as three unitless multipliers per unit of Z. Soft is the default: x 0, y 1, blur 3. A hard-offset theme (bevel, ledger) sets x and y to a fraction and blur to 0; a glow theme (terminal) sets y to 0 and keeps blur, and the key light becomes a halo without the ladder knowing anything about halos. Blur is 3× Z rather than the 2× the general rule gives, because across the 26 shadow layers this library shipped before the ladder the median ratio was exactly 3.00. |
--gog-elevation-contact-blur | | The contact shadow’s blur, and the one length in the family that does not grow with height — that is what ambient occlusion does, and it is what this library already did every time it hand-wrote two layers. |
--gog-elevation-ring-width / -highlight-ink / -highlight-alpha | | The hairline ring and the top-edge catch light, deliberately outside the steps: they belong to particular surfaces rather than to height. A dark theme’s overlay wants the ring and its in-flow elevated card must not have it, or elevated and outlined render identically. Both are inert by default (0px, 0 alpha); a component that wants one composes it — box-shadow: var(--gog-elevation-ring), var(--gog-elevation-3). |
--gog-elevation-ring / -highlight / -contact | | The three composable layers themselves, derived from the knobs above so a component can prepend one to a step. Derived, so override the knobs rather than these. |
| Token | Value | Description |
|---|---|---|
--gog-control-padding-y / -x | | Shared padding for form controls (buttons, fields). |
--gog-control-icon-offset | | Icon inset shared by form controls. |
--gog-control-clear-icon-ratio | | The clear (×) button’s glyph as a fraction of its box, shared by the five single-line controls that draw one. gog-textarea keeps its own 1 deliberately: its clear button sits in a corner rather than in the field’s icon row. |
--gog-control-checkbox-{size}-box-size / -label-size / -icon-size | | Checkbox box, label and icon size, per size step (xsm/sm/md/lg/slg). |
--gog-field-line-height / -label-line-height / -error-line-height | | Leading for the three things every field renders — its own text, its label and its error line — declared once here and aliased by all eight controls that draw them. The role is what sets the value, not the size: all five size steps of a field share one leading, which is why there is no per-size token to override. |
--gog-field-float-label-reserve / -in-top / -over-gap / -over-reserve | | Float-label geometry shared by every field. Each control’s own --gog-{control}-float-label-* tokens derive from these, so one declaration retunes them all while a single control can still be overridden. |
| Token | Value | Description |
|---|---|---|
--gog-accordion-border-color / -width / -style | | Header border. |
--gog-accordion-text-color / -accent-color | | Text and accent color. |
--gog-accordion-hover-bg | | Header hover background. --gog-accordion-hover-ring was removed in 21.13.0: the hover never drew a ring, so nothing read it. |
--gog-accordion-focus-ring-color / -width | | The keyboard focus ring, and its own colour since 21.12.0. The header’s :focus-visible outline used to read --gog-accordion-hover-ring, so a hover-weight colour was doing focus duty and missed 3:1 in all eleven themes. Hover and focus are different signals and now carry different colours. |
--gog-accordion-press-bg | | Header press background, one step past its own hover. |
--gog-accordion-radius / -body-radius | | Corner radius for the header and body. |
--gog-accordion-header-bg / -body-bg | | Header and body background. |
--gog-accordion-header-gap | | Gap between chevron and title. |
--gog-accordion-transition-duration / -body-transition-duration / -chevron-transition-duration | | Expand/collapse animation timing. |
--gog-accordion-{size}-padding-y / -x / -font-size / -chevron-size / -chevron-font-size | | Header padding and font size, per size step (xsm/sm/md/lg/slg). The chevron is a ratio of the header’s own type since 21.11.0 — 1.4em of box, 1em of glyph, one value at every size — so the three smallest sizes, which all label at --gog-text-xs, now carry identical chevrons. Making it a ratio also surfaced a glyph that had been overflowing its own box at every size. |
| Token | Value | Description |
|---|---|---|
--gog-alert-bg / -color / -font-family | | Surface, body text colour and font stack. The ordinary surface and text pair, not a status tint — the library ships no per-status tint family, and the alert does not invent one. |
--gog-alert-border-color / -border-width / -border-style / -radius | | The frame on three sides, and the corner radius. |
--gog-alert-edge-color / -edge-width | | The leading edge that carries the severity, and the icon colour. Written by the severity class, which outranks a plain class of yours — to repaint a severity, set its own colour token below instead. |
--gog-alert-accent-color / -success-color / -danger-color / -warning-color / -info-color | | What each severity points --gog-alert-edge-color at. Default to the foundation status colours, so a theme that sets those needs nothing here. |
--gog-alert-padding-y / -padding-x / -gap / -main-gap | | Inner padding, the gap between icon, text and close button, and the gap between heading and body. |
--gog-alert-icon-font-size / -icon-line-height | | The glyph, and the box that holds it. |
--gog-alert-heading-color / -heading-font-size / -heading-font-weight / -heading-line-height | | The optional heading. |
--gog-alert-body-font-size / -body-line-height | | The projected body. |
| Token | Value | Description |
|---|---|---|
--gog-autocomplete-label-color | | Field label color. |
--gog-autocomplete-field-bg / -border-color / -text-color | | Field surface, border and text. |
--gog-autocomplete-radius / -min-width | | Field corner radius and the floor an auto-width field cannot collapse past. |
--gog-autocomplete-focus-ring-color / -focus-ring-width / -hover-border-color | | Focus and hover states. |
--gog-autocomplete-panel-bg / -panel-border-color / -panel-shadow / -panel-max-height | | Suggestion panel surface and height cap. |
--gog-autocomplete-option-hover-bg / -option-press-bg / -option-selected-bg | | Suggestion row states. |
--gog-autocomplete-option-height / -panel-gap | | A seed for the first frame rather than the row height — the component measures a real row and corrects itself, which is also what places the panel above or below the field. And the gap between the field and its panel. |
--gog-autocomplete-empty-color / -spinner-size | | The "nothing found" message and the loading spinner. |
--gog-autocomplete-clear-color / -clear-hover-color / -actions-inset | | Clear button color and how far the trailing actions sit from the edge. |
--gog-autocomplete-float-label-reserve / -in-top / -over-gap / -over-reserve | | Float-label geometry, derived from the shared --gog-field-float-label-* scale. |
| Token | Value | Description |
|---|---|---|
--gog-badge-success-bg / -danger-bg / -warning-bg / -info-bg (+ matching -color) | | Fill and text color per semantic variant. |
--gog-badge-size / -dot-size / -padding-inline | | Badge height, the bare-dot diameter, and horizontal padding around a count. |
--gog-badge-radius / -border-color / -border-width / -border-style | | Corner radius and the ring separating the badge from its host. |
--gog-badge-font-family / -font-size / -font-weight / -line-height | | Count typography. |
--gog-badge-offset / -z | | How far the badge overhangs its host corner, and its stacking order. |
| Token | Value | Description |
|---|---|---|
--gog-button-font-family / -font-weight / -letter-spacing / -text-transform | | Label typography. |
--gog-button-radius | | Corner radius. |
--gog-button-border-width / -style | | Border. |
--gog-button-transition-duration | | Hover / active transition timing. |
--gog-button-{variant}-bg / -color / -border / -shadow | | Fill, text, border and shadow per variant (primary/secondary/outline/ghost). |
--gog-button-{variant}-hover-bg / -hover-color / -hover-shadow | | Hover state per variant. |
--gog-button-{variant}-press-bg / -press-color | | Pressed state per variant. The press is a colour and not only the scale below, so it survives prefers-reduced-motion. |
--gog-button-focus-ring-color / -focus-ring-width / -focus-ring-offset | | The keyboard focus ring. Its colour is its own token since 21.13.0 and reads the accent; it used to follow each variant’s hover wash, which on ghost and the severity outline buttons made the ring invisible in four themes (1.07:1 at worst). |
--gog-button-active-scale | | How far a press shrinks the button. Dropped under prefers-reduced-motion, where the press colour carries the state on its own. |
--gog-button-{variant}-toggled-shadow / --gog-button-toggled-ring-width | | The inset ring a button with aria-pressed="true" (or "mixed") draws. A ring rather than a fill, because hover and press already own the background. |
--gog-button-{status}-fill / -fill-hover / -fill-press / -on-fill / -ink / -wash | | The severity palette, per status (danger/success/warning/info). fill and on-fill are a filled button and its label; ink is the label of a transparent one, the status hue mixed halfway toward the page ink; wash is the hover background under it. |
--gog-button-{variant}-spinner-color | | The loading spinner, per variant. |
--gog-button-bg / -color / -border / -padding / -font-size / -press-bg / -press-color / -toggled-shadow | | Undeclared by default — the escape hatch for styling a single button instance. |
| Token | Value | Description |
|---|---|---|
--gog-button-toggle-rest-bg / -rest-color | | An unselected button. |
--gog-button-toggle-selected-bg / -selected-color / -selected-border-color | | The selected button. |
--gog-button-toggle-hover-bg / -hover-color | | Hover state. |
--gog-button-toggle-press-bg / -selected-press-bg | | Press state, with its own value for a button that is already selected — pressing one has to read as a press rather than as a deselection. |
--gog-button-toggle-border-color / -border-width / -border-style / -radius | | Group border and corner radius. The colour defaults to --gog-control-boundary-color since 21.12.0 — it read the decorative hairline before, which is why a segmented control now shows a visibly firmer edge in every theme. |
--gog-button-toggle-separated-gap | | Gap between buttons in the "separated" appearance. "joined" shares borders. |
--gog-button-toggle-font-family / -font-weight / -letter-spacing / -text-transform / -icon-size | | Button typography and icon size. |
--gog-button-toggle-focus-ring-color / -focus-ring-width / -focus-ring-offset | | Keyboard focus ring. |
| Token | Value | Description |
|---|---|---|
--gog-calendar-max-width | | How wide the calendar may get. Defaults to max-content, which caps it at its own month grid and follows the size steps, numberOfMonths and showTime on its own — set it to 100% for a calendar that fills its container instead. Also sizes gog-datepicker in inline mode, which renders this component. |
--gog-calendar-padding / -header-gap / -footer-gap / -months-gap | | Grid padding and the gaps between header, footer and side-by-side months. |
--gog-calendar-day-size (per size step: xsm/sm/md/lg/slg) / -day-radius | | Day cell size and shape. |
--gog-calendar-day-rest-bg / -day-hover-bg / -day-outside-color | | Day cell states, including days spilling in from the neighbouring month. |
--gog-calendar-selected-bg / -selected-color / -selected-font-weight | | The selected day. |
--gog-calendar-range-bg / -range-color | | Days between the two ends of a range selection. |
--gog-calendar-today-border-color / -today-font-weight | | The ring marking today. |
--gog-calendar-nav-bg / -nav-hover-bg / -nav-size / -nav-icon-size | | Previous/next month and year buttons. |
--gog-calendar-weekday-color / -weekday-font-size / -weekday-text-transform | | Weekday header row. |
--gog-calendar-time-input-bg / -time-input-width / -time-gap | | The clock section shown under the grid when showTime is on. |
| Token | Value | Description |
|---|---|---|
--gog-card-bg / -border-color / -shadow / -padding-y / -padding-x / -gap | | The instance tier — left undeclared by the library on purpose, so setting one on an element beats the variant and size classes without a specificity fight. |
--gog-card-outlined-bg / -outlined-border-color / -outlined-shadow | | The outlined variant (the default): a border, no shadow. |
--gog-card-elevated-bg / -elevated-border-color / -elevated-shadow | | The elevated variant: the shared surface shadow, no border. |
--gog-card-filled-bg / -filled-border-color / -filled-shadow | | The filled variant: a tint, neither border nor shadow. |
--gog-card-color / --gog-card-font-family / --gog-card-radius | | Body text color, font stack and corner radius. |
--gog-card-heading-color / -heading-font-family / -heading-font-size / -heading-font-weight / -heading-line-height | | The projected gogCardHeader. The visual size comes from these regardless of which heading level you use. |
--gog-card-footer-border-color / -footer-gap / -footer-padding-top | | The projected gogCardFooter row and the rule above it. |
--gog-card-hover-border-color / --gog-card-hover-shadow | | Hover treatment, which only appears on a card holding a gogCardLink. |
--gog-card-focus-ring / -focus-ring-width / -focus-ring-offset | | The ring drawn around the whole card when its stretched link takes focus. |
--gog-card-xsm-padding-y … --gog-card-slg-padding-y (and -padding-x, -gap) | | Padding and row gap per size tier, xsm through slg. |
--gog-card-disabled-opacity / --gog-card-transition-duration | | Disabled dimming, and the hover/focus transition. |
| Token | Value | Description |
|---|---|---|
--gog-checkbox-gap | | Gap between box and label. |
--gog-checkbox-radius | | Box corner radius. |
--gog-checkbox-border-width / -style / -color | | Box border. |
--gog-checkbox-bg / -checked-bg / -checked-border | | Box background, unchecked and checked. |
--gog-checkbox-icon-color | | Checkmark color. |
--gog-checkbox-label-color | | Label text color. |
--gog-checkbox-focus-ring / -focus-ring-width / -focus-ring-offset | | Keyboard focus ring. The colour reads --gog-accent-color rather than the pale wash it used to, corrected in 21.12.0: this outline is the only thing marking focus on this control, and a wash measured 1.38:1 against the light page where WCAG asks for 3:1. |
| Token | Value | Description |
|---|---|---|
--gog-chip-bg / -hover-bg / -press-bg | | Background, default, hover and pressed. |
--gog-chip-selected-shadow / -selected-ring-width | | The inset ring a filter chip draws while selected ([(selected)], 21.9.0). A ring rather than a fill, because hover and press already own the background. |
--gog-chip-border / -border-width / -style | | Border. Since 21.12.0 the colour defaults to --gog-control-boundary-color rather than the decorative --gog-border-color: a chip is a control, and its edge is what identifies it. That is why chips look outlined more firmly than they did — they were at 1.18:1 in primeng before. |
--gog-chip-focus-ring-color / -width / -offset | | The keyboard focus ring. The colour is new in 21.12.0 — the chip had a width and an offset but no colour of its own, so the stylesheet reached for --gog-chip-border and the ring came out as a hairline. A focus indicator needs its own colour. |
--gog-chip-color / -font-weight | | Text color and weight. |
--gog-chip-radius / -pill-radius | | Corner radius, square and pill shape. |
--gog-chip-remove-color / -remove-hover-color | | Remove (×) icon color. |
--gog-chip-{size}-font-size / -padding-block / -padding-inline / -gap / -avatar-size / -icon-size / -remove-size | | Full sizing scale, per size step (xsm/sm/md/lg/slg). The three glyph sizes are ratios of the chip’s own type rather than px ladders since 21.11.0 — avatar 1.5em, icon 1em, remove mark 1.125em, one value at every size — so overriding a size’s font-size carries its glyphs with it, which the rem ladder did not. |
| Token | Value | Description |
|---|---|---|
--gog-collapsible-transition-duration | | Expand/collapse animation timing. |
--gog-collapsible-max-height | | Height an open panel transitions toward. Defaults to max-content, so a panel is as tall as its content and never truncates it. Set a length to cap one deliberately — the panel is overflow: hidden, so a cap clips rather than scrolls. |
--gog-collapsible-disabled-opacity | | Opacity applied to a disabled trigger. |
| Token | Value | Description |
|---|---|---|
--gog-datepicker-label-color | | Field label color. |
--gog-datepicker-field-bg / -border-color / -text-color | | Field surface, border and text. |
--gog-datepicker-radius / -min-width | | Field corner radius and minimum width. |
--gog-datepicker-focus-ring-color / -focus-ring-width / -hover-border-color | | Focus and hover states. |
--gog-datepicker-icon-color / -icon-hover-color / -toggle-icon-size | | The calendar toggle icon. |
--gog-datepicker-panel-bg / -panel-border-color / -panel-shadow / -panel-radius | | The panel wrapping the calendar. The grid itself is themed by --gog-calendar-*. |
--gog-datepicker-panel-width | | Width of the dropdown panel, max-content by default. Inline mode has no panel — it is gog-calendar on its own, so it sizes from --gog-calendar-max-width. |
--gog-datepicker-clear-color / -clear-icon-ratio / -actions-inset | | Clear button color, glyph size and inset. |
--gog-datepicker-error-color / -error-border-color / -error-font-size | | Validation error message and border. |
--gog-datepicker-float-label-reserve / -in-top / -over-gap / -over-reserve | | Float-label geometry, derived from the shared --gog-field-float-label-* scale. |
| Token | Value | Description |
|---|---|---|
--gog-dialog-backdrop-bg / -backdrop-blur | | Scrim behind the dialog. |
--gog-dialog-bg / -color / -border / -radius / -shadow | | Panel surface. |
--gog-dialog-title-font-size / -title-line-height | | The dialog’s <h2>. New tokens in 21.11.0 and the value is the size it was already rendering — the title had simply been inheriting from the browser rather than reading the type scale, so it was outside a theme’s reach. |
--gog-dialog-header-padding / -body-padding | | Section padding. |
--gog-dialog-close-color / -close-hover-color / -close-hover-bg | | Close button. |
--gog-confirmation-dialog-color / -description-color / -actions-gap | | Confirmation dialog variant. |
--gog-confirmation-dialog-title-font-size / -description-font-size (and their line heights) | | The title and the description, on the type scale since 21.11.0 rather than inherited. The description is the one that visibly moved: 16px to 14px, a step smaller than it was. |
--gog-confirmation-dialog-max-width | | The panel’s cap, in ch since 21.11.0 so raising the font size widens the panel with it. It resolves against .confirm-dialog’s own inherited size, not the description’s — a ch cap always reads the font of the element carrying max-width, never a descendant’s. |
| Token | Value | Description |
|---|---|---|
--gog-divider-line-color / -line-thickness | | The rule itself. |
--gog-divider-solid-style / -dashed-style / -dotted-style | | The border-style each variant maps to. |
--gog-divider-block-spacing / -inline-spacing | | Margin around a horizontal and a vertical divider respectively. |
--gog-divider-vertical-length | | Fallback length for a vertical divider whose row has no height of its own. |
--gog-divider-inset-size | | How far the inset variant is indented from the leading edge. |
--gog-divider-label-color / -label-font-size / -label-font-weight / -label-gap | | The projected label and the gap punched in the rule around it. |
| Token | Value | Description |
|---|---|---|
--gog-icon-size | | Default icon size. |
--gog-icon-stroke-width | | Stroke width for outline icons. |
--gog-icon-fallback-size | | Size used when no size is set. |
| Token | Value | Description |
|---|---|---|
--gog-input-label-color | | Field label color. |
--gog-input-field-bg / -field-border / -field-color | | Field surface, border and text. |
--gog-input-radius | | Field corner radius. |
--gog-input-focus-border / -focus-ring / -focus-glow | | Focus state. |
--gog-input-error-color | | Validation error color. |
--gog-input-icon-color / -icon-hover-color | | Prefix / suffix icon color. |
--gog-input-float-label-reserve / -in-top / -on-bg / -over-gap / -over-reserve | | Float-label geometry, derived from the shared --gog-field-float-label-* scale. -on-bg is an instance-layer token (undeclared) — the patch that masks the border behind an "on" label. |
--gog-textarea-clear-icon-ratio | | Size of gog-textarea’s clear glyph relative to the field. A textarea is a large multi-line box, so it takes a full-size glyph rather than the dropdowns’ denser 0.7 ratio. |
--gog-textarea-scrollbar-width | | Instance-layer (undeclared): written by the component from its own measured scrollbar width, so a clear button on a scrolling textarea does not end up under the thumb. |
| Token | Value | Description |
|---|---|---|
--gog-menu-z | | Stacking order of the portaled panel. Defaults to --gog-dropdown-z, and the panel takes the value its trigger inherits — which is how a menu opened inside a dialog stacks above it. |
--gog-menu-bg | | Panel background. |
--gog-menu-border-color / -border-width / -border-style | | Panel border. |
--gog-menu-radius / --gog-menu-item-radius | | The panel’s corner, and the item’s. The item derives from the panel less the panel’s own padding since 21.11.0, so the first and last rows stay concentric with the corner they sit in instead of looking squarer than it — at the default theme that moved the item from 8px to 12px. |
--gog-menu-shadow | | Panel shadow. Defaults to --gog-panel-shadow, the same step the four dropdown panels sit on. It aliased the dialog’s until 21.12.0, which put a modal’s shadow on a dropdown menu — two overlays of one kind, four steps apart, and the alias is why nobody saw it. |
--gog-menu-font-family | | Panel font family. |
--gog-menu-padding | | Space between the panel edge and its items. |
--gog-menu-gap | | Space between items. |
--gog-menu-item-hover-bg / -item-press-bg | | An item under the pointer, and under a press. |
--gog-menu-panel-gap | | Gap between the trigger and the panel. |
--gog-menu-min-width / -max-width | | Panel width bounds. The panel sizes to its widest item between them, never to the trigger. |
--gog-menu-max-height | | Height past which the panel scrolls itself with gog-scroll instead of growing. The panel takes the smallest of this, its own content, and the room between its trigger and the viewport edge. |
--gog-menu-available-height | | Instance-layer (undeclared): written by the component from the room it measured beside the trigger. Listed because it is the other half of the min() above, not because you would set it. |
--gog-menu-transition-duration | | Open/close transition. |
--gog-menu-focus-ring / -focus-ring-width | | Focus ring on the item the arrow keys landed on. |
--gog-menu-item-color / -hover-bg / -hover-color | | Item foreground, and the pair it swaps to under the pointer or focus. |
--gog-menu-item-font-size / -line-height / -padding / -radius | | Item metrics. |
--gog-menu-item-gap | | Space between an item's icon and its label. |
--gog-menu-item-icon-size | | Size of an icon projected into an item, relative to the item's own text. |
--gog-menu-item-disabled-opacity / -disabled-color | | How a disabled item reads. It stays in the list rather than disappearing. |
| Token | Value | Description |
|---|---|---|
--gog-multiselect-label-color | | Field label color. |
--gog-multiselect-field-bg / -field-border | | Field surface and border. |
--gog-multiselect-radius / -min-width | | The field’s corner radius — the field only, since 21.12.0 — and the floor an auto-width trigger cannot collapse past. |
--gog-multiselect-focus-border / -focus-ring | | Focus state. |
--gog-multiselect-panel-bg / -panel-border / -panel-shadow / -panel-max-width | | Dropdown panel surface, and the cap on a panel that sizes to its own content rather than to the trigger. |
--gog-multiselect-panel-gap | | Gap between the trigger and the panel. It was --gog-multiselect-panel-offset until 21.13.0, and the old name stopped resolving in 21.14.0. |
--gog-multiselect-option-height | | A seed for the first frame, not the row height: the component measures a real row and corrects itself, which is also what decides whether the panel opens up or down. |
--gog-multiselect-panel-radius | | The panel’s own corner, new in 21.12.0 and defaulting to var(--gog-radius). Splitting it off the field’s radius is why shaping the trigger no longer reshapes the overlay; the option row and the filter input both stay concentric with whatever you set here. |
--gog-multiselect-option-hover-bg / -option-press-bg / -option-color | | Option row, default, hover and pressed. |
--gog-multiselect-checkbox-border / -checkbox-checked-bg | | Per-option selection mark. The mark is a glyph, so -checkbox-bg and -checkbox-checked-color had nothing to paint and were removed in 21.13.0. |
--gog-multiselect-float-label-reserve / -in-top / -on-bg / -over-gap / -over-reserve | | Float-label geometry, derived from the shared --gog-field-float-label-* scale. |
| Token | Value | Description |
|---|---|---|
--gog-paginator-gap | | Gap between page controls. |
--gog-paginator-ellipsis-color / -ellipsis-font-size | | The "…" truncation marker. |
| Token | Value | Description |
|---|---|---|
--gog-panel-radius / --gog-panel-shadow / --gog-panel-border-width / --gog-panel-border-style | | Shared with the foundation surface tier — the same four tokens dialogs and dropdown panels read, so a theme’s idea of a raised surface reaches gog-panel for free. Setting them here restyles those surfaces too. |
--gog-panel-outlined-bg / -outlined-border-color / -outlined-shadow | | The outlined variant: a border, no shadow. |
--gog-panel-elevated-bg / -elevated-border-color | | The elevated variant (the default) — takes the shared surface shadow above. |
--gog-panel-filled-bg / -filled-border-color / -filled-shadow | | The filled variant: a tint, neither border nor shadow. |
--gog-panel-color / --gog-panel-font-family | | Body text color and font stack. |
--gog-panel-heading-color / -heading-font-family / -heading-font-size / -heading-font-weight / -heading-line-height | | The projected gogPanelHeader heading. |
--gog-panel-header-gap | | Gap between the heading and the collapse toggle. |
--gog-panel-toggle-size / -toggle-color / -toggle-hover-bg / -toggle-radius / --gog-panel-chevron-size | | The collapse toggle button and its chevron. |
--gog-panel-footer-border-color / -footer-gap / -footer-padding-top | | The projected gogPanelFooter row and the rule above it. |
--gog-panel-xsm-padding-y … --gog-panel-slg-padding-y (and -padding-x, -gap) | | Padding and row gap per size tier, xsm through slg. |
--gog-panel-focus-ring / -focus-ring-width / -focus-ring-offset | | Focus ring on the collapse toggle. |
--gog-panel-disabled-opacity / --gog-panel-transition-duration | | Disabled dimming, and the collapse/hover transition. |
| Token | Value | Description |
|---|---|---|
--gog-progressbar-accent-bg / -success-bg / -danger-bg / -warning-bg / -info-bg | | Fill color per variant. |
--gog-progressbar-{variant}-buffer-bg | | The lighter buffer level shown ahead of the fill in "buffer" mode. |
--gog-progressbar-track-base-bg / -radius | | The unfilled track. |
--gog-progressbar-{size}-height | | Bar thickness, per size step (xsm/sm/md/lg/slg). |
--gog-progressbar-indeterminate-duration / -indeterminate-easing | | Indeterminate animation timing. Replaced by a static stripe under prefers-reduced-motion. |
--gog-progressbar-stripe-color / -stripe-size | | The static stripe that stands in for the animation when motion is reduced. |
--gog-progressbar-value-color / -value-font-size / -value-min-width / -value-gap | | The percentage readout rendered when showValue is on. |
--gog-progressbar-edge-color / -edge-backing-color / -edge-width | | The two hairlines marking where the fill ends, added in 21.10.0 — and, since 21.13.0, where the buffer level ends too. Two rather than one because no single tone clears WCAG 1.4.11 against all five fills: the ink line sits outermost against the track, the surface-coloured one just inside the fill, and whichever tone a fill sits close to, the other one reads. With showValue off — the default — this boundary is the only thing stating the value. |
| Token | Value | Description |
|---|---|---|
--gog-radio-bg / -border-color / -border-width / -border-style | | The circle, unchecked. |
--gog-radio-checked-bg / -checked-border / -dot-color / -dot-size-ratio | | The circle and its dot once checked. |
--gog-radio-label-color / -label-line-height / -gap | | Per-option label and the gap to its circle. |
--gog-radio-group-label-color / -group-label-size / -group-gap | | The group’s own label. |
--gog-radio-group-option-gap / -group-option-gap-horizontal | | Gap between options, vertical and horizontal orientation respectively. |
--gog-radio-focus-ring / -focus-ring-width / -focus-ring-offset | | Keyboard focus ring. The colour reads --gog-accent-color rather than the pale wash it used to, corrected in 21.12.0: this outline is the only thing marking focus on this control, and a wash measured 1.38:1 against the light page where WCAG asks for 3:1. |
--gog-radio-error-color / -error-font-size / -disabled-opacity | | Validation error message and the disabled state. |
| Token | Value | Description |
|---|---|---|
--gog-ripple-color | | The wash. Defaults to currentColor rather than a palette token — the only token in this catalogue that does — so it reads as the surface’s own foreground on a filled surface and a ghost one alike, which is why the ripple needs no per-variant tier. |
--gog-ripple-opacity | | Peak opacity of the wash. |
--gog-ripple-enter-duration | | How long the wave takes to expand from the press point. |
--gog-ripple-exit-duration | | How long it fades once the pointer is released. |
--gog-ripple-easing | | Easing curve for both phases. |
| Token | Value | Description |
|---|---|---|
--gog-scroll-track-bg / -track-radius | | Track background and corner radius. |
--gog-scroll-thumb-bg / -thumb-hover-bg / -thumb-active-bg | | Draggable thumb color, per interaction state. |
--gog-scroll-thumb-radius / -thumb-inset | | Thumb shape and inset from the track edges. |
--gog-scroll-corner-bg | | Background of the corner square where two tracks meet. |
--gog-scroll-fade-duration | | Auto-hide fade animation timing. |
--gog-scroll-focus-ring / -focus-ring-width | | Keyboard focus ring on the viewport. |
--gog-scroll-{normal|thin}-track-width / -thumb-min-size | | Track width and minimum thumb length, per size step. |
| Token | Value | Description |
|---|---|---|
--gog-select-label-color | | Field label color. |
--gog-select-field-bg / -field-border | | Field surface and border. |
--gog-select-radius | | The field’s corner radius — the field only. Until 21.12.0 it shaped the dropdown panel too, so rounding the trigger into a pill rounded the overlay into one as well; that box has its own token now. |
--gog-select-focus-border / -focus-ring | | Focus state. |
--gog-select-panel-bg / -panel-shadow / -panel-max-width | | Dropdown panel surface, and the cap on a panel that sizes to its own content rather than to the trigger. |
--gog-select-panel-gap | | Gap between the trigger and the panel. It was --gog-select-panel-offset until 21.13.0, and the old name stopped resolving in 21.14.0. |
--gog-select-option-height | | A seed for the first frame, not the row height: the component measures a real row and corrects itself, which is also what decides whether the panel opens up or down. |
--gog-select-panel-radius | | The panel’s own corner, new in 21.12.0 and defaulting to var(--gog-radius), so nothing moves unless you change it. gog-autocomplete and gog-datepicker already declared theirs; this and the multiselect’s are the pair that completes the family. |
--gog-select-options-padding / --gog-select-option-radius | | The gutter around the option list and the row’s own corner, matching what gog-autocomplete and gog-multiselect already had. This panel had no interior at all before 21.12.0, which is why its first and last rows were square inside a rounded corner. The row radius derives from the panel radius less the gutter, so it stays concentric once --gog-density moves the padding. |
--gog-select-min-width | | The floor an auto-width trigger cannot collapse past (120px). |
--gog-select-chevron-color / -chevron-inset | | Dropdown arrow color and inset. Since 21.3.0 the inset lands on --gog-control-icon-offset, the same line as gog-inputfield’s icons — the three controls now line up in a form. |
--gog-select-option-hover-bg / -option-press-bg / -option-selected-color | | Option row states. |
--gog-select-float-label-reserve / -in-top / -on-bg / -over-gap / -over-reserve | | Float-label geometry, derived from the shared --gog-field-float-label-* scale. |
| Token | Value | Description |
|---|---|---|
--gog-skeleton-base / -shine | | Placeholder base color and shimmer. |
--gog-skeleton-radius / -line-radius | | Corner radius, block and line shapes. |
--gog-skeleton-pulse-duration / -wave-duration | | Loading animation timing. |
| Token | Value | Description |
|---|---|---|
--gog-slider-label-color / -value-color | | Label and current value. |
--gog-slider-track-bg / -fill-bg | | Track, empty and filled. The fill is applied as background rather than background-color, so -fill-bg also accepts a gradient. |
--gog-slider-track-border-width / -track-border-style / -track-border-color | | An optional border on the track — transparent by default, the same opt-in convention as --gog-button-primary-border. |
--gog-slider-thumb-bg / -thumb-border / -thumb-glow-color / -thumb-glow-size | | Drag handle, and the glow around it. -thumb-glow-color was --gog-slider-thumb-shadow until 21.13.0 — it always held a colour, not a shadow — and the old name stopped resolving in 21.14.0. |
--gog-slider-auto-width / -vertical-length | | Size of a slider that does not fill its container: width when horizontal, length when vertical. |
--gog-slider-focus-ring | | Keyboard focus ring. |
| Token | Value | Description |
|---|---|---|
--gog-spinner-track-color | | Background ring. |
--gog-spinner-arc-outer-color / -arc-inner-color | | Spinning arc colors. |
--gog-spinner-diamond-color / -rune-color / -glow-color | | Decorative elements on the larger spinner variants. |
--gog-spinner-spin-duration / -pulse-duration | | Animation timing. |
| Token | Value | Description |
|---|---|---|
--gog-table-border-color / -border-width | | Outer border. |
--gog-table-surface / -text-color / -accent-color | | Surface, body text and header accent. |
--gog-table-hover-bg | | Row hover background. |
--gog-table-row-press-bg | | An interactiveRows row under the finger, since 21.13.0 — a colour rather than a ripple, so it survives prefers-reduced-motion. A plain row does not use it. |
--gog-table-muted-color | | Secondary text (e.g. empty state). |
--gog-table-header-letter-spacing / -text-transform | | Header cell typography. |
--gog-table-{size}-padding-v / -th-font-size / -td-font-size | | Row density, per size step (xsm/sm/md/lg/slg). |
| Token | Value | Description |
|---|---|---|
--gog-tabs-rest-color / -hover-color / -active-color | | Tab header label, per state. |
--gog-tabs-press-bg / -press-color | | A header under a press. It carries a label colour as well as a background, the way the button does, because a header has little fill of its own to deepen. |
--gog-tabs-indicator-color / -indicator-thickness / -indicator-radius | | The bar marking the active tab. |
--gog-tabs-header-border-color / -header-border-width / -header-border-style | | The rule under the tablist. |
--gog-tabs-{size}-font-size / -{size}-padding | | Header typography and padding, per size step (sm/md/lg/slg). |
--gog-tabs-tab-gap / -gap / -icon-size | | Gap between headers, between a header’s icon and its label, and icon size. |
--gog-tabs-panel-padding / -panel-color | | The content panel below the tablist. |
--gog-tabs-focus-ring-color / -focus-ring-width / -focus-ring-offset / -disabled-opacity | | Keyboard focus ring and the disabled state. |
| Token | Value | Description |
|---|---|---|
--gog-tag-default-color / -success-color / -danger-color / -warning-color / -info-color | | Base color per semantic variant. |
--gog-tag-bg-base / -color-base / -bg-mix / -color-mix | | How the variant color is mixed into background and text. |
--gog-tag-radius / -pill-radius | | Corner radius, square and pill shape. |
--gog-tag-{size}-font-size / -padding-block / -padding-inline / -gap / -icon-size | | Full sizing scale, per size step (xsm/sm/md/lg/slg). |
| Token | Value | Description |
|---|---|---|
--gog-toast-bg / -color / -border | | Card surface. |
--gog-toast-success-color / -error-color / -warning-color / -info-color | | Accent stripe and icon color, per toast type. |
--gog-toast-padding / -radius | | Card padding and corner radius. |
--gog-toast-stack-peek / -stack-scale-step / -stack-expanded-gap | | Card-stack geometry when several toasts are visible at once. |
| Token | Value | Description |
|---|---|---|
--gog-toggle-track-off-bg / -track-on-bg / -on-border-color | | The track, off and on. |
--gog-toggle-border-color / -border-width / -border-style | | The track’s edge in the off state, which is the whole of the control when it is off. It defaults to --gog-control-boundary-color since 21.12.0; reading the decorative hairline instead had left an off switch at under 3:1 in all eleven themes, which is to say invisible to WCAG. |
--gog-toggle-thumb-off-bg / -thumb-on-bg / -thumb-shadow / -thumb-inset | | The sliding thumb. |
--gog-toggle-{size}-track-width / -track-height / -thumb-size / -label-size | | Full sizing scale, per size step (xsm/sm/md/lg/slg). |
--gog-toggle-state-color / -state-font-weight / -state-padding-inline / -state-thumb-gap | | The onLabel / offLabel text rendered inside the track. |
--gog-toggle-label-color / -gap / -radius | | The label next to the switch, its gap, and the track corner radius. |
--gog-toggle-focus-ring-color / -focus-ring-width / -focus-ring-offset / -disabled-opacity | | Keyboard focus ring and the disabled state. |
| Token | Value | Description |
|---|---|---|
--gog-tooltip-bg / -color / -border-color / -shadow / -radius | | The bubble surface. Deliberately the same floating-panel recipe as a dialog or dropdown, not a bespoke inverted bubble. |
--gog-tooltip-max-width / -max-height | | Content wraps at the width and scrolls past the height, inside an internal gog-scroll. |
--gog-tooltip-padding / -gap / -arrow-size | | Bubble padding, its distance from the trigger, and the arrow. |
--gog-tooltip-font-family / -font-size / -line-height | | Bubble typography. |
--gog-tooltip-z / -transition-duration | | Stacking order (raised inside a dialog so a tooltip stacks above it) and fade timing. |
Or copy this one block — every token worth overriding to build a fully custom theme, from fonts through the palette to the component layer:
/*
* Theme starter — every token the library paints with, ready to override.
* Order: fonts, palette, character layer (radius/borders/casing/density — the
* short path to a custom look), structure (motion, focus, the metrics that are
* literals), then every component token grouped by component.
*
* Copy this after the library import and replace the values. Load order is the
* point: this file is meant to come second, so anything you set here beats the
* library's own value at equal specificity.
*
* **"Every token" is now checked, not claimed.** It used to be neither — this
* file carried 714 of the library's 1312 tokens, with fifteen components missing
* outright, because it was hand-copied and nothing compared it to the source.
* The component block is generated by `npm run generate:theme-starter` and
* `npm run check:theme-starter` fails the build if any token is unaccounted for.
* Edit the head freely; leave the generated block to the script.
*/
/* ── Fonts & type scale ──────────────────────────────────────────────────── */
:root {
--gog-font-heading: 'YourHeadingFont', serif;
--gog-font-body: 'YourBodyFont', sans-serif;
--gog-font-mono: 'YourMonoFont', monospace;
/* 11px, the bottom of the scale. It exists because the smallest chip and the smallest
tag were already painting it as a literal — the step was in use before it had a name. */
--gog-text-2xs: 0.6875rem;
--gog-text-xs: 0.75rem;
--gog-text-sm: 0.875rem;
--gog-text-md: 1rem;
--gog-text-lg: 1.125rem;
/* 20px, between `lg` and `xl`, and named for the control size it serves rather than
continuing the t-shirt run: `gog-button` and the field controls both needed a step for
their `slg` size and, having none, both wrote `1.25rem` as a literal. */
--gog-text-slg: 1.25rem;
--gog-text-xl: 1.5rem;
--gog-text-2xl: 2rem;
--gog-text-3xl: 3rem;
}
/* ── Palette — Light (also the default with no data-theme set) ──────────── */
:root,
[data-theme='light'] {
color-scheme: light;
--gog-background-color: #f6f0e6;
--gog-surface-color: #eae0d0;
--gog-hover-color: #dfd3bf;
--gog-border-color: #c4b496;
--gog-text-color: #1e170e;
--gog-accent-text-color: #ece4d0;
--gog-muted-text-color: #6e5438;
--gog-primary-color: #1e170e;
--gog-accent-color: #8c6200;
--gog-accent-bright: #b8860b;
--gog-accent-dim: #634500;
--gog-accent-pale: #f4e8c1;
--gog-secondary-color: #a07800;
--gog-success-color: #2d6a4f;
--gog-danger-color: #9b2226;
--gog-warning-color: #bb3e03;
--gog-info-color: #4a6fa5;
/* The edge that identifies a control, as distinct from --gog-border-color above, which
is the decorative hairline this library draws dividers, table rules and panel outlines
with and deliberately keeps faint. This one has to clear 3:1 under WCAG SC 1.4.11, and
the two cannot be one token: a theme that sets only the decorative colour either shouts
its dividers or hides its controls. Computed rather than picked —
`npm run suggest:color -- #c4b496 #eae0d0 3.2` holds this palette's own hue and chroma
and lands here, 3.21:1 on the surface and 3.70:1 on the page. */
--gog-control-boundary-color: #897a5e;
/* ── Elevation, light ──────────────────────────────────────────────────────
Ten knobs, and the six steps every raised surface reads are generated from them in
the block below — so there is no --gog-panel-shadow or --gog-dialog-shadow here any
more, and there should not be: writing one would take that surface off the ladder
while the others stayed on it, which is the inconsistency the family exists to end.
**State all ten or none.** Custom properties inherit, so a theme block declaring six
of them silently borrows the other four from whatever encloses it, and the failure is
a shadow that looks nearly right rather than an error.
A step is two lights: the contact shadow, which hugs the object and does not grow with
height, and the key light, whose offset is Z and whose blur is three times it. The three
multipliers are the style axis — this is the soft default; a hard-offset theme sets x
and y to a fraction and blur to 0, and a glow theme sets y to 0 and keeps the blur. */
--gog-elevation-ink: 30 23 14;
--gog-elevation-key-alpha: 0.08;
--gog-elevation-ambient-alpha: 0.04;
--gog-elevation-contact-blur: 3px;
--gog-elevation-key-x: 0;
--gog-elevation-key-y: 1;
--gog-elevation-key-blur: 3;
/* The hairline ring and the top-edge catch light are outside the steps on purpose: they
belong to particular surfaces rather than to height. Both inert on a light ground. */
--gog-elevation-ring-width: 0px;
--gog-elevation-highlight-ink: 255 255 255;
--gog-elevation-highlight-alpha: 0;
--gog-spinner-overlay-bg: rgba(246, 240, 230, 0.75);
}
/*
* ── Palette — Dark ─────────────────────────────────────────────────────────
* Same tokens as the light block above, just different values — that's the
* whole pattern for any theme-specific override. Scope it under
* [data-theme='dark'], not a bare :root, or it also becomes the light theme.
*/
[data-theme='dark'] {
color-scheme: dark;
--gog-background-color: #0f0d0a;
--gog-surface-color: #191510;
--gog-hover-color: #262018;
--gog-border-color: #382e22;
--gog-text-color: #e5dec9;
--gog-accent-text-color: #e5dec9;
--gog-muted-text-color: #9e8c72;
--gog-primary-color: #e5dec9;
--gog-accent-color: #f3be3a;
--gog-accent-bright: #ffd05b;
--gog-accent-dim: #b5881a;
--gog-accent-pale: #3d2f0e;
--gog-secondary-color: #d4a373;
--gog-success-color: #52b788;
--gog-danger-color: #e63946;
--gog-warning-color: #f4a261;
--gog-info-color: #64dfdf;
--gog-control-boundary-color: #716558;
--gog-spinner-overlay-bg: rgba(15, 13, 10, 0.75);
/* ── Elevation, dark ───────────────────────────────────────────────────────
All ten again, which is the rule: a theme states the whole family or none of it.
A dark theme genuinely does have to say something different here, and this is where it
says it. On a near-black page a black blur reads as smudge rather than lift, so the two
alphas are far higher than the light theme's; the ring and the catch light, both inert
above, are what actually carry the edge of a raised surface here.
The two hand-written `elevated` shadows this block used to carry are gone, and not
because they were wrong — because the ladder now reproduces them exactly. `inset 0 1px 0
rgba(255, 255, 255, 0.07)` over `0 2px 6px rgba(0, 0, 0, 0.55)` is precisely
`var(--gog-elevation-highlight), var(--gog-elevation-2)` under these knobs. */
--gog-elevation-ink: 0 0 0;
--gog-elevation-key-alpha: 0.55;
--gog-elevation-ambient-alpha: 0.28;
--gog-elevation-contact-blur: 3px;
--gog-elevation-key-x: 0;
--gog-elevation-key-y: 1;
--gog-elevation-key-blur: 3;
--gog-elevation-ring-width: 1px;
--gog-elevation-highlight-ink: 255 255 255;
--gog-elevation-highlight-alpha: 0.07;
}
/*
* ── Character layer — radius, borders, casing ────────────────────────────────
* The short path to a custom look: most component tokens further down read
* these instead of declaring their own literal, so changing a value here
* reshapes the whole library at once, before you ever touch a per-component
* token.
*/
:root {
--gog-radius: 8px;
/* Three border-weight tiers: --gog-control-border-width is form fields,
--gog-panel-border-width is raised/floating surfaces (dialog), and this
plain pair is everything smaller and inline (chip, tag, table row). */
--gog-border-width: 1px;
--gog-border-style: solid;
--gog-panel-border-width: 1px;
--gog-panel-border-style: solid;
--gog-control-border-width: 2px;
--gog-control-border-style: solid;
/* The "emphasis" casing/tracking shared by buttons, section headers, table
headers and field labels. */
--gog-text-transform: uppercase;
--gog-letter-spacing: 1px;
/* Weight, the third character axis. Four steps because four are painted — there is no
`normal`, since nothing in the library uses 400. Set these and every component weight
follows; before them, fifteen component tokens each held a bare number. */
--gog-font-weight-medium: 500;
--gog-font-weight-semibold: 600;
--gog-font-weight-bold: 700;
--gog-font-weight-heavy: 900;
/* Leading, the fourth. Six steps because six values are painted. `gog-panel`'s heading keeps
its own 1.25, off this scale on purpose the way an 11px chip is off the type scale. */
--gog-line-height-none: 1;
--gog-line-height-tight: 1.2;
--gog-line-height-snug: 1.3;
--gog-line-height-normal: 1.4;
--gog-line-height-relaxed: 1.5;
--gog-line-height-loose: 1.6;
/* One multiplier under every padding and gap in the library: the ten-step spacing
scale further down is `calc(Npx * var(--gog-density))`, so 0.9 tightens the whole
UI and 1.15 opens it up without touching a single component token. Keep it here
rather than inside a [data-theme] block — a step declared in a theme scope would be
computed once against :root's density instead of its own. */
--gog-density: 1;
}
/*
* ── Structure — motion, focus, and the metrics that are literals ─────────────
* The geometry every component sizes itself from, and the part of it that is a
* real number rather than a derivation.
*
* The spacing scale is deliberately NOT here. `--gog-space-4` … `--gog-space-48`
* and the five `--gog-space-xs` … `--gog-space-2xl` aliases onto them all read
* `--gog-density`, so they live in the generated block below with everything else
* that derives. Redeclaring one here as a literal is exactly how you would take it
* out of density without meaning to — this file used to do that with all five.
*/
:root {
--gog-duration-fast: 0.12s;
--gog-duration-base: 0.15s;
--gog-duration-slow: 0.2s;
--gog-easing: ease;
--gog-focus-ring-width: 3px;
--gog-focus-ring-offset: 2px;
--gog-disabled-opacity: 0.4;
/* The library's stacking floor. Every layer is `base + N` — badge 1, toast 100, dropdowns
and dialogs 300, tooltip 400, the blocking spinner overlay 8000 — so lifting the whole
library above your own chrome is this one number, with the internal order kept. */
--gog-z-base: 0;
/* The clear (x) button's glyph as a fraction of its box, shared by the five single-line
controls that draw one. `gog-textarea` keeps its own 1 on purpose: its clear button sits
in a corner rather than in the field's icon row. */
--gog-control-clear-icon-ratio: 0.7;
/* Checkbox and radio metrics, per size step (xsm/sm/md/lg/slg). A box is a shape,
not spacing, so these stay literal and do not follow density. */
--gog-control-checkbox-box-size-xsm: 12px;
--gog-control-checkbox-box-size-sm: 18px;
--gog-control-checkbox-box-size-md: 24px;
--gog-control-checkbox-box-size-lg: 32px;
--gog-control-checkbox-box-size-slg: 40px;
--gog-control-checkbox-label-size-xsm: 0.6875rem;
--gog-control-checkbox-label-size-sm: 0.8125rem;
--gog-control-checkbox-label-size-md: 0.9375rem;
--gog-control-checkbox-label-size-lg: 1.0625rem;
--gog-control-checkbox-label-size-slg: 1.1875rem;
--gog-control-checkbox-icon-size-xsm: 10px;
--gog-control-checkbox-icon-size-sm: 12px;
--gog-control-checkbox-icon-size-md: 14px;
--gog-control-checkbox-icon-size-lg: 18px;
--gog-control-checkbox-icon-size-slg: 22px;
/* Field sizing, shared by input / select / multiselect. The glyph box is literal on
purpose while the offsets around it follow density: an icon that shrinks with the
padding stops being legible well before the padding stops being usable. */
--gog-field-icon-glyph-xsm: 12px;
--gog-field-icon-glyph-sm: 14px;
--gog-field-icon-glyph: 16px;
--gog-field-slg-font-size: 1.25rem;
/* Float-label geometry, one scale for every field that can float its label. Each
control reads these through its own --gog-<block>-float-label-* token below, so a
value set here retunes all of them while a single control can still be tuned alone.
`reserve` is the headroom added inside the field for the 'in'/'on' variants;
`in-top` is where the label lands once floated; `over-reserve` is the space kept
permanently clear for the 'over' variant. */
--gog-field-float-label-reserve: 14px;
--gog-field-float-label-in-top: 6px;
--gog-field-float-label-over-reserve: 1.4em;
--gog-icon-size: 1.2em;
--gog-icon-stroke-width: 2;
--gog-spinner-size-xsm: 12px;
--gog-spinner-size-sm: 18px;
--gog-spinner-size-md: 48px;
--gog-spinner-size-lg: 96px;
--gog-spinner-size-slg: 144px;
--gog-spinner-rune-size: 20px;
/* Toast stack geometry */
--gog-toast-min-width: 280px;
--gog-toast-max-width: 400px;
--gog-toast-z-index: 9999;
--gog-toast-enter-distance: 110%;
/* Stacking order for dropdown panels and the spinner overlay */
--gog-dropdown-z: 300;
--gog-spinner-overlay-z: 8000;
}
/* theme-starter:derived-start */
/*
* ── Component tokens — every one, generated ─────────────────────────────────
* Copied verbatim from the installed @guildofgleks/ui's theme.css derived layer by
* `npm run generate:theme-starter`. Do not hand-edit between the markers: run the
* script instead, or the next run reverts you. Everything here reads another token,
* so a palette or character-layer edit above already carries through — override one
* of these directly only when that one component has to differ from the rest.
*
* theme.css re-declares seventeen of these inside an `@supports (color: color-mix(…))`
* block, which is how 21.7.1 gives older browsers a flat fallback. That block is
* deliberately not mirrored here: this file is loaded after the library, so a value you
* set below wins in every browser, which is what an override file should do.
*/
:root,
[data-theme] {
/* ── Derived foundation tokens ───────────────────────────────────────────────
Split out of the literal block above because they read other tokens: they have
to re-resolve inside each theme scope. */
/* ── The elevation ladder ────────────────────────────────────────────────────
Generated from the knobs in the literal block above; see the long note there for why the
key light's blur is three times its offset and why the ring and the highlight are not part
of a step. Every step but 0 is the same two layers with one number changed, which is the
property that makes the arithmetic assertable by reading rather than by a check.
The heights, and what the library puts on each:
0 -- flat. Every button at rest, and the `outlined` and `filled` card and panel.
1 -- a mark riding on a control: the toggle's thumb.
2 -- a surface raised in normal flow: the `elevated` card and panel.
4 -- an overlay anchored to a control: the four dropdown panels, the tooltip, the menu.
8 -- an overlay floating free of one: the toast.
16 -- a modal that owns the screen: the dialog.
`gog-menu` is the one whose height *changes* here rather than being restated. It aliased
`--gog-dialog-shadow`, so a dropdown menu carried a modal's shadow while the four dropdown
panels beside it carried a panel's -- two overlays of one kind, four steps apart, and the
alias is why nobody saw it. */
--gog-elevation-contact: 0 1px var(--gog-elevation-contact-blur)
rgb(var(--gog-elevation-ink) / var(--gog-elevation-ambient-alpha));
/* Composable character layers, not steps. A component that wants one prepends it. */
--gog-elevation-ring: 0 0 0 var(--gog-elevation-ring-width) var(--gog-border-color);
--gog-elevation-highlight: inset 0 1px 0
rgb(var(--gog-elevation-highlight-ink) / var(--gog-elevation-highlight-alpha));
--gog-elevation-0: none;
--gog-elevation-1:
var(--gog-elevation-contact),
calc(1px * var(--gog-elevation-key-x)) calc(1px * var(--gog-elevation-key-y))
calc(1px * var(--gog-elevation-key-blur))
rgb(var(--gog-elevation-ink) / var(--gog-elevation-key-alpha));
--gog-elevation-2:
var(--gog-elevation-contact),
calc(2px * var(--gog-elevation-key-x)) calc(2px * var(--gog-elevation-key-y))
calc(2px * var(--gog-elevation-key-blur))
rgb(var(--gog-elevation-ink) / var(--gog-elevation-key-alpha));
--gog-elevation-3:
var(--gog-elevation-contact),
calc(4px * var(--gog-elevation-key-x)) calc(4px * var(--gog-elevation-key-y))
calc(4px * var(--gog-elevation-key-blur))
rgb(var(--gog-elevation-ink) / var(--gog-elevation-key-alpha));
--gog-elevation-4:
var(--gog-elevation-contact),
calc(8px * var(--gog-elevation-key-x)) calc(8px * var(--gog-elevation-key-y))
calc(8px * var(--gog-elevation-key-blur))
rgb(var(--gog-elevation-ink) / var(--gog-elevation-key-alpha));
--gog-elevation-5:
var(--gog-elevation-contact),
calc(16px * var(--gog-elevation-key-x)) calc(16px * var(--gog-elevation-key-y))
calc(16px * var(--gog-elevation-key-blur))
rgb(var(--gog-elevation-ink) / var(--gog-elevation-key-alpha));
/* The library's own surfaces, placed on the ladder. These stay the public names a consumer
overrides — what changed in 21.12.0 is that their *value* is a step rather than a hand-written
shadow, so a theme moves all of them by turning one knob. Overriding any single one still
works exactly as before. */
--gog-panel-shadow: var(--gog-elevation-ring), var(--gog-elevation-3);
--gog-toast-shadow: var(--gog-elevation-ring), var(--gog-elevation-4);
--gog-dialog-shadow: var(--gog-elevation-ring), var(--gog-elevation-5);
--gog-toggle-thumb-shadow: var(--gog-elevation-1);
/* ── Text on a status fill ───────────────────────────────────────────────────
`--gog-accent-text-color` means "text on the accent fill" and flips with the theme, which
made it the obvious label for a status fill too — `gogBadge` used it for all four. It is
wrong for some of them, and silently: measured 2026-09-04, `material`'s amber under white
was 1.97:1 and `primeng`'s green 2.28:1, both far under AA, in a pair no check had. The
accent is one colour a theme tunes deliberately; the four statuses are four more, and
nothing says one label reads on all five.
So each status names its own, defaulting to the accent's answer because that is right in
seven of the eleven themes. A theme states one of these only where its own hue disagrees —
`material` puts near-black on its amber, which is Material 3's own convention, and `primeng`
does the same on all three of Aura's bright hues. Where *neither* label reached AA the hue
itself moved instead; see the preset files. */
--gog-success-text-color: var(--gog-accent-text-color, var(--gog-primary-color));
--gog-danger-text-color: var(--gog-accent-text-color, var(--gog-primary-color));
--gog-warning-text-color: var(--gog-accent-text-color, var(--gog-primary-color));
--gog-info-text-color: var(--gog-accent-text-color, var(--gog-primary-color));
/* Which way a status fill deepens when it is hovered or held: **away from its own label**, so
the step always makes the label easier to read rather than harder. That is the theme's ink
for a fill wearing the accent's white, which is nine of the eleven themes — and the other way
round for the four fills whose label is the ink itself, `material`'s amber and `primeng`'s
three, which say so in their own files. Mixing toward a fixed colour instead is what a first
pass did, and it cost `primeng`'s info button 6.44:1 down to 4.23:1 on press: deepening
toward the ink walked the fill into the label. */
--gog-success-shade: var(--gog-text-color);
--gog-danger-shade: var(--gog-text-color);
--gog-warning-shade: var(--gog-text-color);
--gog-info-shade: var(--gog-text-color);
/* ── Stacking layers ─────────────────────────────────────────────────────────
All five read `--gog-z-base`, so the whole library moves together. The gaps are
deliberate: an app that needs to slot its own element between two of these has room
without touching the library's numbers. */
--gog-badge-z: calc(var(--gog-z-base) + 1);
--gog-toast-base-z: calc(var(--gog-z-base) + 100);
--gog-dropdown-z: calc(var(--gog-z-base) + 300);
--gog-tooltip-z: calc(var(--gog-z-base) + 400);
/* The blocking overlay outranks everything, including a dialog it may be covering. */
--gog-spinner-overlay-z: calc(var(--gog-z-base) + 8000);
--gog-space-4: calc(4px * var(--gog-density));
--gog-space-8: calc(8px * var(--gog-density));
--gog-space-12: calc(12px * var(--gog-density));
--gog-space-16: calc(16px * var(--gog-density));
--gog-space-20: calc(20px * var(--gog-density));
--gog-space-24: calc(24px * var(--gog-density));
--gog-space-28: calc(28px * var(--gog-density));
--gog-space-32: calc(32px * var(--gog-density));
/* 21.11.0. Added because the optical ratio requires it, not because a design asked: a control
with 20px of vertical padding needs exactly 40px horizontal, and `slg` is that control on
`gog-button`, `gog-inputfield` and every field that shares their tier. The scale had 32 and
then jumped to 48. */
--gog-space-40: calc(40px * var(--gog-density));
--gog-space-48: calc(48px * var(--gog-density));
--gog-space-xs: var(--gog-space-4);
--gog-space-sm: var(--gog-space-8);
--gog-space-md: var(--gog-space-16);
--gog-space-lg: var(--gog-space-24);
--gog-space-2xl: var(--gog-space-48);
/* The shared control tier, on the 4px grid at a ratio of exactly 2.0 (styling.instructions.md,
law 3). It was 10/14, a ratio of 1.40; `--gog-field-md-padding-*` derives from it, so this
pair is what an `md` input, select, multiselect, autocomplete and datepicker are padded by. */
--gog-control-padding-y: var(--gog-space-12);
--gog-control-padding-x: var(--gog-space-24);
/* One value, all four sides: this is the padding a checkable control's `<label>` carries around
its box, and it is part of the pointer target — a 12px `xsm` box inside 8px of padding is a
28px target, which is how the smallest checkbox clears WCAG 2.5.8 without growing. */
--gog-control-checkbox-padding: var(--gog-space-8);
--gog-field-xsm-padding-y: var(--gog-space-4);
--gog-field-xsm-padding-x: var(--gog-space-8);
--gog-field-sm-padding-y: var(--gog-space-8);
--gog-field-sm-padding-x: var(--gog-space-16);
--gog-field-lg-padding-y: var(--gog-space-16);
--gog-field-lg-padding-x: var(--gog-space-32);
--gog-field-slg-padding-y: var(--gog-space-20);
--gog-field-slg-padding-x: var(--gog-space-40);
--gog-field-float-label-over-gap: var(--gog-space-8);
--gog-toast-stack-padding: var(--gog-space-16);
/* L9 (docs/component-geometry.md, "D7 — taken"): the message wraps, so its cap is a measure —
53ch at --gog-toast-message-font-size (14px), the nearest whole character to today's 400px so
this changes robustness to a font-size change, not the pixels anyone sees today. L8's viewport
exception is layered on top: the margin reads --gog-toast-stack-padding above, the container's
own edge inset, rather than a new number. */
--gog-toast-max-width: min(53ch, calc(100vw - var(--gog-toast-stack-padding) * 2));
--gog-field-xsm-icon-offset: var(--gog-space-8);
--gog-field-sm-icon-offset: var(--gog-space-8);
--gog-field-lg-icon-offset: var(--gog-space-16);
--gog-field-slg-icon-offset: var(--gog-space-20);
--gog-control-icon-offset: var(--gog-space-12);
--gog-elevated-surface-color: var(--gog-surface-color);
--gog-panel-radius: calc(var(--gog-radius) + 8px);
--gog-field-xsm-font-size: var(--gog-text-xs);
--gog-field-sm-font-size: var(--gog-text-sm);
/* The only field metric that is a type size; the rest of this block is geometry. It lives
here rather than with them because it reads a token, and a derived value declared on the
literals-only `:root` freezes to that scope's scale (rule C). */
--gog-field-slg-font-size: var(--gog-text-slg);
/* Leading for the three kinds of text every field renders, declared once and aliased by each
component the way the padding and float-label tiers above already are. A block that sets a
font size sets its leading (law 4): inheriting it while changing the size moves the ratio
silently, which is the thing the law guards. Roles, from
`docs/component-geometry.md` — the value in the field itself is one UI line whose box is the
row height; a label and an error message may both wrap beside their control. */
--gog-field-line-height: var(--gog-line-height-normal);
--gog-field-label-line-height: var(--gog-line-height-snug);
--gog-field-error-line-height: var(--gog-line-height-snug);
--gog-field-md-padding-y: var(--gog-control-padding-y);
--gog-field-md-padding-x: var(--gog-control-padding-x);
/* offset + glyph + offset — see the icon-chrome comment in the literal block above. */
--gog-field-xsm-icon-inset: calc(
var(--gog-field-xsm-icon-offset) * 2 + var(--gog-field-icon-glyph-xsm)
);
--gog-field-sm-icon-inset: calc(
var(--gog-field-sm-icon-offset) * 2 + var(--gog-field-icon-glyph-sm)
);
--gog-field-md-icon-inset: calc(
var(--gog-field-md-icon-offset) * 2 + var(--gog-field-icon-glyph)
);
--gog-field-lg-icon-inset: calc(
var(--gog-field-lg-icon-offset) * 2 + var(--gog-field-icon-glyph)
);
--gog-field-slg-icon-inset: calc(
var(--gog-field-slg-icon-offset) * 2 + var(--gog-field-icon-glyph)
);
--gog-field-md-font-size: var(--gog-text-md);
--gog-field-md-icon-offset: var(--gog-control-icon-offset);
--gog-field-lg-font-size: var(--gog-text-lg);
/* ══════════════════════════════════════════════════════════════════════════════
COMPONENT TOKENS
Everything below is what an individual component paints with. Override a block
to restyle just that component; the values themselves all derive from the
foundation tokens above, so a palette swap carries through for free.
══════════════════════════════════════════════════════════════════════════════ */
/* ── Accordion ─────────────────────────────────────────────────────────────── */
--gog-accordion-font-family: var(--gog-font-heading);
--gog-accordion-body-font-family: var(--gog-font-body);
--gog-accordion-border-color: var(--gog-accent-dim);
--gog-accordion-border-width: var(--gog-control-border-width);
--gog-accordion-border-style: var(--gog-control-border-style);
--gog-accordion-text-color: var(--gog-text-color);
--gog-accordion-accent-color: var(--gog-accent-color);
--gog-accordion-hover-bg: var(--gog-hover-color);
/* The header's label stays body text while hovered or held, and the lift is carried by the
background alone. It turned `--gog-accordion-accent-color` until 21.9.0, which is the accent
— on an accent-tinted strip that measured 3.61:1 in light, 3.79:1 in one-light and 4.09:1 in
ledger, and worse again once the press deepened the tint. Same trade as the ghost button's
hover, and made for the same reason: the accent is not a text colour on a ground that is
itself tinted with the accent. */
--gog-accordion-hover-color: var(--gog-accordion-text-color);
--gog-accordion-press-bg: var(--gog-border-color);
/* Its own token. The header's `:focus-visible` outline read `--gog-accordion-hover-ring`, so a
hover-weight colour was doing focus duty and failed 3:1 in all eleven themes. */
--gog-accordion-focus-ring-color: var(--gog-accent-color);
--gog-accordion-focus-ring-width: var(--gog-focus-ring-width);
--gog-accordion-body-color: var(--gog-text-color);
--gog-accordion-body-line-height: var(--gog-line-height-loose);
--gog-accordion-header-text-transform: var(--gog-text-transform);
--gog-accordion-header-gap: var(--gog-space-12);
--gog-accordion-disabled-opacity: var(--gog-disabled-opacity);
--gog-accordion-transition-duration: var(--gog-duration-base);
--gog-accordion-body-transition-duration: var(--gog-duration-slow);
--gog-accordion-chevron-transition-duration: var(--gog-duration-slow);
--gog-accordion-body-lift: -2px;
/* Flat by default — corner rounding is a look, not a given; consumers who want it
opt in per-instance or theme-wide by overriding these two. */
--gog-accordion-radius: 0px;
--gog-accordion-body-radius: 0px;
/* The header carries its own ground and the body does not. Both were `transparent` until
21.7.1, which made every open item one continuous band: header and content painted the
surrounding surface, and the only thing between two open items was a hairline in the accent
colour. With several open at once nobody could tell where one ended and the next began.
Only the header changed. The body stays transparent on purpose, so an accordion dropped on
a coloured surface still sits on that colour rather than punching a hole in it. */
--gog-accordion-header-bg: var(--gog-hover-color);
--gog-accordion-body-bg: transparent;
/* Per-size metrics. `lg` is the default size. */
--gog-accordion-xsm-padding-y: var(--gog-space-4);
--gog-accordion-xsm-padding-x: var(--gog-space-8);
--gog-accordion-xsm-font-size: var(--gog-text-xs);
/* The header label is one UI line whose box is the row height (law 4, role ui-line). */
--gog-accordion-line-height: var(--gog-line-height-normal);
--gog-accordion-xsm-letter-spacing: 0.2px;
--gog-accordion-xsm-content-gap: var(--gog-space-4);
--gog-accordion-xsm-body-font-size: var(--gog-text-xs);
--gog-accordion-xsm-body-line-height: var(--gog-line-height-relaxed);
--gog-accordion-xsm-body-padding-top: var(--gog-space-4);
--gog-accordion-xsm-body-padding-bottom: var(--gog-space-8);
--gog-accordion-xsm-chevron-size: 1.4em;
/* The chevron is a ratio of the header's own type, not a px ladder of its own. It had been
10/12/14/16/18px of glyph basis inside an 11/13/15/18/20px box, beside a label in rem -- so
raising the browser's text size grew the label and left the chevron where it was, and the
box/label ratio drifted 0.92 to 1.29 across the five sizes.
Two bugs came out of writing it as a ratio. The box was *smaller than its glyph at every
size*: `gog-icon` renders at `--gog-icon-size: 1.2em` of this font size, so the mark was
12/14.4/16.8/19.2/21.6px inside a box of 11/13/15/18/20 and overflowed it everywhere. And
the five sizes had five ratios where they needed one.
`1em` makes this the em basis rather than the glyph size, so the mark is 1.2em of the header
and the 1.4em box surrounds it. All five steps hold the same ratio and still render five
different sizes, because the header's type differs -- the tokens stay per-size so an override
keeps working. */
--gog-accordion-xsm-chevron-font-size: 1em;
/* A glyph in its own box: leading would push it off the centre it is placed on. */
--gog-accordion-chevron-line-height: var(--gog-line-height-none);
--gog-accordion-sm-padding-y: var(--gog-space-8);
--gog-accordion-sm-padding-x: var(--gog-space-16);
--gog-accordion-sm-font-size: var(--gog-text-xs);
--gog-accordion-sm-letter-spacing: 0.4px;
--gog-accordion-sm-content-gap: var(--gog-space-4);
--gog-accordion-sm-body-font-size: var(--gog-text-xs);
--gog-accordion-sm-body-line-height: var(--gog-accordion-body-line-height);
--gog-accordion-sm-body-padding-top: var(--gog-space-8);
--gog-accordion-sm-body-padding-bottom: var(--gog-space-8);
--gog-accordion-sm-chevron-size: 1.4em;
--gog-accordion-sm-chevron-font-size: 1em;
--gog-accordion-md-padding-y: var(--gog-space-12);
--gog-accordion-md-padding-x: var(--gog-space-24);
--gog-accordion-md-font-size: var(--gog-text-xs);
--gog-accordion-md-letter-spacing: 0.8px;
--gog-accordion-md-content-gap: var(--gog-space-4);
--gog-accordion-md-body-font-size: var(--gog-text-sm);
--gog-accordion-md-body-line-height: var(--gog-accordion-body-line-height);
--gog-accordion-md-body-padding-top: var(--gog-space-8);
--gog-accordion-md-body-padding-bottom: var(--gog-space-12);
--gog-accordion-md-chevron-size: 1.4em;
--gog-accordion-md-chevron-font-size: 1em;
--gog-accordion-lg-padding-y: var(--gog-space-16);
--gog-accordion-lg-padding-x: var(--gog-space-32);
--gog-accordion-lg-font-size: var(--gog-text-sm);
--gog-accordion-lg-letter-spacing: 0.8px;
--gog-accordion-lg-content-gap: var(--gog-space-4);
--gog-accordion-lg-body-font-size: var(--gog-text-md);
--gog-accordion-lg-body-line-height: var(--gog-accordion-body-line-height);
--gog-accordion-lg-body-padding-top: var(--gog-space-12);
--gog-accordion-lg-body-padding-bottom: var(--gog-space-16);
--gog-accordion-lg-chevron-size: 1.4em;
--gog-accordion-lg-chevron-font-size: 1em;
--gog-accordion-slg-padding-y: var(--gog-space-20);
--gog-accordion-slg-padding-x: var(--gog-space-40);
--gog-accordion-slg-font-size: var(--gog-text-md);
--gog-accordion-slg-letter-spacing: 0.8px;
--gog-accordion-slg-content-gap: var(--gog-space-4);
--gog-accordion-slg-body-font-size: var(--gog-text-lg);
--gog-accordion-slg-body-line-height: var(--gog-accordion-body-line-height);
--gog-accordion-slg-body-padding-top: var(--gog-space-16);
--gog-accordion-slg-body-padding-bottom: var(--gog-space-20);
--gog-accordion-slg-chevron-size: 1.4em;
--gog-accordion-slg-chevron-font-size: 1em;
/* ── Alert ─────────────────────────────────────────────────────────────────
A persistent, in-flow message. The severity is carried by a leading edge and the icon over
the ordinary surface, not by a tinted fill, and that is forced rather than chosen: the
library ships no per-status tint (`--gog-accent-pale` exists, `--gog-success-pale` does not),
and inventing one here would make the alert the twelfth place a theme restates its red.
`gog-toast` reached the same shape for the same reason. See `docs/alert.md`.
The five severity tokens below derive from the status colours rather than repeating them,
which is what lets a theme retune its red once. */
--gog-alert-bg: var(--gog-surface-color);
--gog-alert-color: var(--gog-text-color);
--gog-alert-heading-color: var(--gog-text-color);
--gog-alert-font-family: var(--gog-font-body);
--gog-alert-border-color: var(--gog-border-color);
--gog-alert-border-width: var(--gog-panel-border-width);
--gog-alert-border-style: var(--gog-panel-border-style);
/* The leading edge, which is the whole of the severity signal. Wider than the hairline around
it so it reads as a mark rather than as an uneven border — the control border tier doubled,
derived so a theme that thickens its controls thickens this with them. */
--gog-alert-edge-width: calc(var(--gog-control-border-width) * 2);
--gog-alert-radius: var(--gog-radius);
--gog-alert-padding-y: var(--gog-space-12);
--gog-alert-padding-x: var(--gog-space-24);
--gog-alert-gap: var(--gog-space-12);
/* Between the heading and the body — the tightest step on the scale, because they are one
block of text rather than two things in a row. */
--gog-alert-main-gap: var(--gog-space-4);
--gog-alert-icon-font-size: var(--gog-text-md);
/* A glyph in its own box: leading would push it off the centre it is placed on. */
--gog-alert-icon-line-height: var(--gog-line-height-none);
--gog-alert-heading-font-size: var(--gog-text-md);
--gog-alert-heading-font-weight: var(--gog-font-weight-semibold);
--gog-alert-heading-line-height: var(--gog-line-height-snug);
--gog-alert-body-font-size: var(--gog-text-sm);
--gog-alert-body-line-height: var(--gog-line-height-relaxed);
--gog-alert-accent-color: var(--gog-accent-color);
--gog-alert-success-color: var(--gog-success-color);
--gog-alert-danger-color: var(--gog-danger-color);
--gog-alert-warning-color: var(--gog-warning-color);
--gog-alert-info-color: var(--gog-info-color);
/* ── Collapsible ───────────────────────────────────────────────────────────
No portal, no owned markup — see utilities.css for the actual `.gog-collapsible__*`
rules (they style content this component's consumer projects, which sits outside
`gog-collapsible`'s own view and can't be reached by its scoped stylesheet). */
--gog-collapsible-transition-duration: var(--gog-duration-slow);
/* The panel's natural height, so an open panel never truncates whatever it holds. This was
a fixed `480px` cap, which bought the CSS-only transition an animatable target but paid
for it by silently clipping any taller content — `overflow: hidden` means no scrollbar
and no other sign that the rest of the panel is missing. `max-content` still animates,
via `interpolate-size: allow-keywords` on the content element (see utilities.css); where
that is unsupported the panel snaps open instead of easing, which is the right way round
for the trade — losing an animation is visible and harmless, losing content is neither.
Set a length here to cap a particular panel on purpose; it will clip, as before. */
--gog-collapsible-max-height: max-content;
--gog-collapsible-disabled-opacity: var(--gog-disabled-opacity);
/* ── Button ────────────────────────────────────────────────────────────────
`--gog-button-bg`, `--gog-button-color`, `--gog-button-border`, `--gog-button-shadow`,
`--gog-button-hover-bg`, `--gog-button-hover-shadow`, `--gog-button-padding` and
`--gog-button-font-size` are intentionally NOT declared — they are the per-instance
escape hatch the variant/size classes fall back through. */
--gog-button-xsm-padding: var(--gog-space-4) var(--gog-space-8);
--gog-button-sm-padding: var(--gog-space-8) var(--gog-space-16);
--gog-button-md-padding: var(--gog-space-12) var(--gog-space-24);
--gog-button-lg-padding: var(--gog-space-16) var(--gog-space-32);
--gog-button-slg-padding: var(--gog-space-20) var(--gog-space-40);
--gog-button-xsm-font-size: var(--gog-text-xs);
--gog-button-sm-font-size: var(--gog-text-sm);
--gog-button-md-font-size: var(--gog-text-md);
--gog-button-lg-font-size: var(--gog-text-lg);
--gog-button-slg-font-size: var(--gog-text-slg);
--gog-button-font-family: var(--gog-font-heading);
--gog-button-font-weight: var(--gog-font-weight-heavy);
--gog-button-letter-spacing: var(--gog-letter-spacing);
--gog-button-text-transform: var(--gog-text-transform);
--gog-button-line-height: var(--gog-line-height-none);
--gog-button-gap: var(--gog-space-sm);
--gog-button-radius: var(--gog-radius);
--gog-button-border-width: var(--gog-control-border-width);
--gog-button-border-style: var(--gog-control-border-style);
--gog-button-transition-duration: var(--gog-duration-base);
--gog-button-focus-ring-width: var(--gog-focus-ring-width);
/* Its own colour. The ring read `--gog-button-variant-hover-bg` -- a *hover* fill doing focus
duty, the same defect eight other indicators had fixed in 21.12.0, and hidden here because
the value arrives through the variant layer rather than from a token this sweep could read.
It passed on `primary` and `secondary`, whose hover fill is a saturated accent, and failed
wherever the hover fill is a wash: `ghost` at 1.07-1.16:1 and the severity `outline`
combinations at 1.79-2.65:1, across four themes.
One colour, not one per variant. A focus ring's job is to be visible against the page the
button sits on, which does not change with the button's fill -- and the ring already sits a
pixel further out than the foundation's so it reads as separate even on a filled accent
button. That is the answer the other fourteen rings in the library already give. */
--gog-button-focus-ring-color: var(--gog-accent-color);
/* One pixel further out than the foundation ring: a filled surface needs the extra air for
the ring to read as separate from the fill. Written as the foundation plus that pixel
rather than a flat 3px, so a theme that moves the ring moves this with it. */
--gog-button-focus-ring-offset: calc(var(--gog-focus-ring-offset) + 1px);
/* Shipped since before the press had a colour, and left spelled `active` on purpose: renaming
a token consumers already override needs a deprecation cycle, and this is a patch. The state
it names is the same one `--gog-button-press-*` paints. */
--gog-button-active-scale: 0.97;
--gog-button-disabled-opacity: var(--gog-disabled-opacity);
--gog-button-loading-opacity: 0.7;
--gog-button-spinner-max-size: 70%;
--gog-button-primary-bg: var(--gog-accent-color);
--gog-button-primary-color: var(--gog-accent-text-color, var(--gog-primary-color));
--gog-button-primary-border: transparent;
--gog-button-primary-shadow: none;
--gog-button-primary-hover-bg: var(--gog-accent-bright);
--gog-button-primary-hover-color: var(--gog-button-primary-color);
--gog-button-primary-hover-shadow: 0 0 16px var(--gog-accent-pale);
/* The label's colour, not the page's. `--gog-text-color` is the colour of text on the page
background, and a filled button is not the page background — on the dark theme that put pale
parchment on bright amber, which read as a washed-out spinner beside a near-black label. */
--gog-button-primary-spinner-color: var(--gog-button-primary-color);
--gog-button-secondary-bg: var(--gog-secondary-color);
--gog-button-secondary-color: var(--gog-accent-text-color, var(--gog-primary-color));
--gog-button-secondary-border: transparent;
--gog-button-secondary-shadow: none;
--gog-button-secondary-hover-bg: var(--gog-accent-color);
--gog-button-secondary-hover-color: var(--gog-button-secondary-color);
--gog-button-secondary-hover-shadow: none;
/* Same reasoning as primary: the other filled variant, the same mismatch. */
--gog-button-secondary-spinner-color: var(--gog-button-secondary-color);
--gog-button-outline-bg: transparent;
--gog-button-outline-color: var(--gog-accent-color);
--gog-button-outline-border: var(--gog-accent-color);
--gog-button-outline-shadow: none;
--gog-button-outline-hover-bg: var(--gog-accent-color);
/* The label sits on the accent fill once the button is hovered, so it takes the token that
means "text on an accent fill" — the same one the two filled variants use. It read
`--gog-primary-color` until 21.9.0, which is the colour of text on the *page*, and the
result failed WCAG AA in all 11 shipped themes: 1.11:1 in one-dark, 1.41:1 in dark, 3.65:1
in light at best. It was invisible to `check:contrast` because that script had no pair for
this label, the same way it had none for the hover fill until 2026-08-29. It has both now. */
--gog-button-outline-hover-color: var(--gog-accent-text-color, var(--gog-primary-color));
--gog-button-outline-hover-shadow: none;
--gog-button-outline-spinner-color: var(--gog-accent-color);
--gog-button-ghost-bg: transparent;
--gog-button-ghost-color: var(--gog-accent-color);
--gog-button-ghost-border: transparent;
--gog-button-ghost-shadow: none;
--gog-button-ghost-hover-bg: var(--gog-hover-color);
/* The label leaves the accent while the ground is tinted, and that is the only thing that
works here. Ghost's resting label *is* `--gog-accent-color`, and its hover tints the ground
with the same accent, so the two walk toward each other: measured across all 11 themes, the
label fell under 4.5:1 in `light` (3.94), `primeng` (4.18) and `one-light` (4.22). No ground
fixes it — a half-strength wash, a neutral `--gog-hover-color`, a text scrim and an
accent-dim wash were all measured, and `light` fails every one of them, because
`--gog-accent-color` as *text* on that theme's own background is 4.60:1 with no headroom to
spend. Moving the label to `--gog-text-color` clears 5.29:1 at worst (one-dark) and leaves
the ground exactly as it was, so the hover stays the subtle wash this variant is documented
to have. The press then goes the other way and fills — see `-press-bg` below. */
--gog-button-ghost-hover-color: var(--gog-text-color);
--gog-button-ghost-hover-shadow: none;
--gog-button-ghost-spinner-color: var(--gog-accent-color);
/* The held state, and the reason it is a colour rather than only the `--gog-button-active-scale`
it used to be: `prefers-reduced-motion` switches that transform off, which left a button with
no press feedback at all for the readers most likely to need it. A colour change is a state,
not a movement — reduced motion keeps it and only drops the scale, and with transitions off it
lands instantly. See docs/feedback-triage.md's closing section: reduced motion must remove the
animation, not the information.
Each variant goes one step *deeper* than its own hover, so pressing is distinguishable while
hovering, which is the normal case for a pointer. `--gog-accent-dim` is that step for the
three accent-carrying variants; ghost has no fill of its own to deepen, so it takes a
stronger wash of the same tint its hover uses (see the @supports block at the end of this
file for the mixed value and why the flat one above it is not a fallback but the value). */
/* The *toggle* state — `aria-pressed="true"`, a button that stays on — as an inset ring rather
than a fill. A fill cannot carry it: every other state already owns the background, so a
toggled button that is also hovered or held would lose the one thing saying it is on. A ring
composes with all of them, and it is the same reasoning that made `gog-button-toggle-group`'s
selected option a fill: there, nothing else was competing for the background.
The ring takes the colour that is guaranteed to read on its own variant — the label colour on
the filled two, the accent on the transparent two — so both are pairs `check:contrast`
already gates. While toggled, this replaces the variant's `box-shadow`, which costs
`primary` its hover glow: the ring is state and the glow is decoration, and a `box-shadow`
list cannot hold `none` as a layer, so keeping both was not on offer. */
--gog-button-toggled-ring-width: 2px;
--gog-button-primary-toggled-shadow: inset 0 0 0 var(--gog-button-toggled-ring-width)
var(--gog-accent-text-color, var(--gog-primary-color));
--gog-button-secondary-toggled-shadow: var(--gog-button-primary-toggled-shadow);
--gog-button-outline-toggled-shadow: inset 0 0 0 var(--gog-button-toggled-ring-width)
var(--gog-accent-color);
--gog-button-ghost-toggled-shadow: var(--gog-button-outline-toggled-shadow);
--gog-button-primary-press-bg: var(--gog-accent-dim);
--gog-button-primary-press-color: var(--gog-button-primary-color);
--gog-button-secondary-press-bg: var(--gog-accent-dim);
--gog-button-secondary-press-color: var(--gog-button-secondary-color);
--gog-button-outline-press-bg: var(--gog-accent-dim);
--gog-button-outline-press-color: var(--gog-button-outline-hover-color);
/* Ghost presses to the same deep fill as outline, rather than to a wash like every other
surface in this file. Measured across all 11 themes: a wash cannot work here, because this
button's *label* is the accent, so tinting its ground with the accent walks the two together
— a 24% wash put the label under 4.5:1 in seven themes, and `--gog-accent-pale` was either
no better or invisible against the hover. A filled press moves the label to
`--gog-accent-text-color` instead, which is the pair `check:contrast` already gates, so no
future theme can quietly break it. The other eight surfaces keep their washes: their labels
are body text, and their worst case across the 11 is 4.80:1. */
--gog-button-ghost-press-bg: var(--gog-accent-dim);
--gog-button-ghost-press-color: var(--gog-accent-text-color, var(--gog-primary-color));
/* ── Button severity ─────────────────────────────────────────────────────────
`severity` is orthogonal to `variant`: a destructive action can be a filled button, an
outlined one or a ghost, and it is still destructive. So this is not a fifth variant — it
re-points the *ingredients* the four variants are built from, and the shape rules in
`styles/button.css` apply them per variant. Four severities x six ingredients rather than
four x four variants x eleven properties, which is what a fifth-variant reading would have
cost.
`-fill` and `-on-fill` are the filled pair, and `-on-fill` is `--gog-<status>-text-color`
rather than `--gog-accent-text-color`: see that block near the top of this file for why one
label does not read on every status.
`-ink` is the label a *transparent* variant paints, and it is not the raw status colour. As
text on the page, the raw hue clears 4.5:1 in only five of the eleven themes — `primeng`'s
amber manages 2.05:1 — so it is mixed toward the theme's own ink until it does. The 50% is
measured rather than chosen: `material`'s amber is the binding case and needs the hue below
54%, so 50 clears every theme with a little headroom. It costs saturation on the themes that
never needed it; a theme that wants the colour back overrides `--gog-button-<status>-ink`
directly, which is one token rather than a dial nobody would find. Mixing toward `--gog-text-color` rather than a
fixed black is what makes one number work on light and dark alike — the ink is dark on one
and light on the other, and both directions move *away* from the ground.
The hover and press fills move the same way, one small step and one larger, so a severity
button's states step the way an accent one's do. Moving toward the ink also moves away from
`-on-fill` in the seven themes where that is the accent's white-or-near-black, so the label
gets easier rather than harder; in the four where `-on-fill` *is* the ink, the rest state
starts at 6.44:1 or better and a 24% step cannot spend that. The flat values here are what a
browser without `color-mix()` renders — no step, the same graceful nothing the ghost button
degrades to — and the mixed ones are in the @supports block at the end of this file. */
--gog-button-success-fill: var(--gog-success-color);
--gog-button-success-on-fill: var(--gog-success-text-color);
--gog-button-success-fill-hover: var(--gog-success-color);
--gog-button-success-fill-press: var(--gog-success-color);
--gog-button-success-ink: var(--gog-success-color);
--gog-button-success-wash: transparent;
--gog-button-danger-fill: var(--gog-danger-color);
--gog-button-danger-on-fill: var(--gog-danger-text-color);
--gog-button-danger-fill-hover: var(--gog-danger-color);
--gog-button-danger-fill-press: var(--gog-danger-color);
--gog-button-danger-ink: var(--gog-danger-color);
--gog-button-danger-wash: transparent;
--gog-button-warning-fill: var(--gog-warning-color);
--gog-button-warning-on-fill: var(--gog-warning-text-color);
--gog-button-warning-fill-hover: var(--gog-warning-color);
--gog-button-warning-fill-press: var(--gog-warning-color);
--gog-button-warning-ink: var(--gog-warning-color);
--gog-button-warning-wash: transparent;
--gog-button-info-fill: var(--gog-info-color);
--gog-button-info-on-fill: var(--gog-info-text-color);
--gog-button-info-fill-hover: var(--gog-info-color);
--gog-button-info-fill-press: var(--gog-info-color);
--gog-button-info-ink: var(--gog-info-color);
--gog-button-info-wash: transparent;
/* ── Button toggle group ───────────────────────────────────────────────────
`--gog-button-toggle-bg`, `-color`, `-padding` and `-font-size` are intentionally NOT
declared — they are the per-instance escape hatch the size classes fall back through.
Padding/font-size reuse the `--gog-button-<size>-*` scale so a toggle group and a
`<gog-button>` at the same `size` line up in a toolbar. */
--gog-button-toggle-font-family: var(--gog-font-heading);
--gog-button-toggle-font-weight: var(--gog-font-weight-bold);
--gog-button-toggle-letter-spacing: 0.5px;
--gog-button-toggle-text-transform: var(--gog-text-transform);
--gog-button-toggle-line-height: var(--gog-line-height-none);
--gog-button-toggle-gap: var(--gog-space-sm);
--gog-button-toggle-icon-size: 1.1em;
--gog-button-toggle-radius: var(--gog-radius);
--gog-button-toggle-border-width: var(--gog-control-border-width);
--gog-button-toggle-border-style: var(--gog-control-border-style);
--gog-button-toggle-border-color: var(--gog-control-boundary-color);
--gog-button-toggle-rest-bg: transparent;
--gog-button-toggle-rest-color: var(--gog-text-color);
--gog-button-toggle-hover-bg: var(--gog-hover-color);
--gog-button-toggle-press-bg: var(--gog-border-color);
--gog-button-toggle-hover-color: var(--gog-text-color);
--gog-button-toggle-selected-bg: var(--gog-accent-color);
--gog-button-toggle-selected-color: var(--gog-accent-text-color, var(--gog-primary-color));
--gog-button-toggle-selected-border-color: var(--gog-accent-color);
/* A selected option is already filled with the accent, so its press deepens the fill the way
the filled button variants do rather than washing over it. */
--gog-button-toggle-selected-press-bg: var(--gog-accent-dim);
--gog-button-toggle-separated-gap: var(--gog-space-sm);
--gog-button-toggle-transition-duration: var(--gog-duration-base);
--gog-button-toggle-disabled-opacity: var(--gog-disabled-opacity);
--gog-button-toggle-focus-ring-width: var(--gog-focus-ring-width);
--gog-button-toggle-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-button-toggle-focus-ring-color: var(--gog-accent-color);
/* ── Calendar (the month grid inside gog-datepicker, and gog-calendar on its own) ── */
--gog-calendar-font-family: var(--gog-font-body);
--gog-calendar-color: var(--gog-text-color);
/* Caps the host at its month grid instead of letting the header spread to the container.
`100%` restores the pre-21.5.0 full-width behaviour. */
--gog-calendar-max-width: max-content;
--gog-calendar-padding: var(--gog-space-12);
--gog-calendar-header-gap: var(--gog-space-4);
--gog-calendar-header-margin: var(--gog-space-8);
--gog-calendar-months-gap: var(--gog-space-16);
--gog-calendar-title-color: var(--gog-text-color);
--gog-calendar-title-font-weight: var(--gog-font-weight-bold);
--gog-calendar-nav-size: 28px;
--gog-calendar-nav-radius: calc(var(--gog-radius) - 2px);
--gog-calendar-nav-bg: transparent;
--gog-calendar-nav-color: var(--gog-muted-text-color);
--gog-calendar-nav-hover-bg: var(--gog-hover-color);
--gog-calendar-nav-hover-color: var(--gog-text-color);
--gog-calendar-nav-icon-size: 0.8rem;
/* Pulls the two chevrons of a year step together so they read as one control. */
--gog-calendar-nav-icon-overlap: -0.35em;
--gog-calendar-weekday-padding: var(--gog-space-4) 0;
--gog-calendar-weekday-color: var(--gog-muted-text-color);
--gog-calendar-weekday-font-size: var(--gog-text-xs);
--gog-calendar-weekday-line-height: var(--gog-line-height-none);
--gog-calendar-weekday-font-weight: var(--gog-font-weight-semibold);
--gog-calendar-weekday-text-transform: var(--gog-text-transform);
--gog-calendar-day-radius: calc(var(--gog-radius) - 2px);
--gog-calendar-day-border-width: var(--gog-border-width);
--gog-calendar-day-border-style: var(--gog-border-style);
--gog-calendar-day-rest-bg: transparent;
--gog-calendar-day-rest-color: var(--gog-text-color);
--gog-calendar-day-hover-bg: var(--gog-hover-color);
--gog-calendar-day-outside-color: var(--gog-muted-text-color);
--gog-calendar-today-border-color: var(--gog-accent-color);
--gog-calendar-today-font-weight: var(--gog-font-weight-bold);
--gog-calendar-selected-bg: var(--gog-accent-color);
--gog-calendar-selected-color: var(--gog-accent-text-color, var(--gog-primary-color));
--gog-calendar-selected-font-weight: var(--gog-font-weight-bold);
/* The wash between the two ends of a range: same hue, low enough to read as a band rather
than as a second selection. */
--gog-calendar-range-bg: var(--gog-accent-pale);
--gog-calendar-range-color: var(--gog-text-color);
--gog-calendar-disabled-opacity: var(--gog-disabled-opacity);
--gog-calendar-transition-duration: var(--gog-duration-fast);
--gog-calendar-focus-ring-width: var(--gog-focus-ring-width);
/* Inset rather than outset: the month grid packs its cells edge to edge, so an outward ring
would sit on top of the neighbouring day. Negated from the foundation so a theme still
controls how far it sits from the cell edge. */
--gog-calendar-focus-ring-offset: calc(var(--gog-focus-ring-offset) * -1);
--gog-calendar-focus-ring-color: var(--gog-accent-color);
--gog-calendar-divider-width: 1px;
--gog-calendar-divider-style: solid;
--gog-calendar-divider-color: var(--gog-border-color);
--gog-calendar-time-gap: var(--gog-space-8);
--gog-calendar-time-margin: var(--gog-space-12);
--gog-calendar-time-input-width: 3.5rem;
--gog-calendar-time-input-padding: var(--gog-space-4) var(--gog-space-8);
--gog-calendar-time-input-bg: var(--gog-background-color);
--gog-calendar-action-padding: var(--gog-space-4) var(--gog-space-8);
--gog-calendar-footer-gap: var(--gog-space-8);
--gog-calendar-xsm-font-size: var(--gog-text-xs);
--gog-calendar-xsm-day-size: 24px;
--gog-calendar-sm-font-size: var(--gog-text-sm);
--gog-calendar-sm-day-size: 28px;
--gog-calendar-md-font-size: var(--gog-text-sm);
--gog-calendar-md-day-size: 34px;
--gog-calendar-lg-font-size: var(--gog-text-md);
--gog-calendar-lg-day-size: 40px;
--gog-calendar-slg-font-size: var(--gog-text-lg);
--gog-calendar-line-height: var(--gog-line-height-normal);
--gog-calendar-slg-day-size: 46px;
/* ── Card ──────────────────────────────────────────────────────────────────
`--gog-card-bg`, `--gog-card-border-color`, `--gog-card-shadow`, `--gog-card-padding-y`,
`--gog-card-padding-x` and `--gog-card-gap` are intentionally NOT declared — they are the
per-instance escape hatch the variant and size classes fall back through. */
--gog-card-font-family: var(--gog-font-body);
--gog-card-color: var(--gog-text-color);
--gog-card-radius: var(--gog-radius);
--gog-card-border-width: var(--gog-panel-border-width);
--gog-card-border-style: var(--gog-panel-border-style);
--gog-card-transition-duration: var(--gog-duration-base);
--gog-card-heading-color: var(--gog-text-color);
--gog-card-heading-font-family: var(--gog-font-heading);
--gog-card-heading-font-size: var(--gog-text-lg);
--gog-card-heading-font-weight: var(--gog-font-weight-semibold);
--gog-card-heading-line-height: var(--gog-line-height-snug);
--gog-card-outlined-bg: var(--gog-surface-color);
--gog-card-outlined-border-color: var(--gog-border-color);
--gog-card-outlined-shadow: none;
--gog-card-elevated-bg: var(--gog-elevated-surface-color);
--gog-card-elevated-border-color: transparent;
/* The shared surface shadow, so a card sits at the same elevation as a dialog or a
dropdown panel instead of inventing a second house style for "raised". */
--gog-card-elevated-shadow: var(--gog-elevation-highlight), var(--gog-elevation-2);
--gog-card-filled-bg: var(--gog-accent-pale);
--gog-card-filled-border-color: transparent;
--gog-card-filled-shadow: none;
/* Hover and focus only ever show on a card that holds a `gogCardLink`. */
--gog-card-hover-border-color: var(--gog-accent-dim);
--gog-card-hover-shadow: var(--gog-panel-shadow);
--gog-card-focus-ring: var(--gog-accent-color);
--gog-card-focus-ring-width: var(--gog-focus-ring-width);
--gog-card-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-card-disabled-opacity: var(--gog-disabled-opacity);
--gog-card-footer-border-color: var(--gog-border-color);
--gog-card-footer-gap: var(--gog-space-sm);
--gog-card-footer-padding-top: var(--gog-space-sm);
--gog-card-xsm-padding-y: var(--gog-space-8);
--gog-card-xsm-padding-x: var(--gog-space-12);
--gog-card-xsm-gap: var(--gog-space-8);
--gog-card-sm-padding-y: var(--gog-space-12);
--gog-card-sm-padding-x: var(--gog-space-16);
--gog-card-sm-gap: var(--gog-space-sm);
--gog-card-md-padding-y: var(--gog-space-md);
--gog-card-md-padding-x: var(--gog-space-20);
--gog-card-md-gap: var(--gog-space-12);
--gog-card-lg-padding-y: var(--gog-space-20);
--gog-card-lg-padding-x: var(--gog-space-lg);
--gog-card-lg-gap: var(--gog-space-16);
--gog-card-slg-padding-y: var(--gog-space-28);
--gog-card-slg-padding-x: var(--gog-space-32);
--gog-card-slg-gap: var(--gog-space-md);
/* ── Checkbox ──────────────────────────────────────────────────────────────
Box/label/icon size and padding come from the `--gog-control-checkbox-*` scale;
checkbox.component.ts maps the `size` input onto the host. */
--gog-checkbox-font-family: var(--gog-font-body);
--gog-checkbox-gap: var(--gog-space-12);
--gog-checkbox-radius: var(--gog-radius);
--gog-checkbox-border-width: var(--gog-control-border-width);
--gog-checkbox-border-style: var(--gog-control-border-style);
--gog-checkbox-border-color: var(--gog-accent-dim);
--gog-checkbox-bg: var(--gog-surface-color);
--gog-checkbox-checked-bg: var(--gog-accent-color);
--gog-checkbox-checked-border: var(--gog-accent-color);
--gog-checkbox-icon-color: var(--gog-accent-text-color, var(--gog-primary-color));
/* A glyph in its own box: role label-none, so the box is the glyph and not the font. */
--gog-checkbox-icon-line-height: var(--gog-line-height-none);
--gog-checkbox-label-color: var(--gog-muted-text-color);
--gog-checkbox-label-line-height: var(--gog-line-height-snug);
/* The accent, not `--gog-accent-pale`. This outline is the *only* thing marking focus on this
control, and a pale wash cannot carry that: measured 1.38:1 against the light page, against
the 3:1 WCAG 2.4.11 and 1.4.11 both require. Fourteen of the library's focus rings already
read `--gog-accent-color`; these were the outliers, found by the boundary sweep in 21.12.0. */
--gog-checkbox-focus-ring: var(--gog-accent-color);
--gog-checkbox-focus-ring-width: var(--gog-focus-ring-width);
--gog-checkbox-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-checkbox-disabled-opacity: var(--gog-disabled-opacity);
--gog-checkbox-transition-duration: var(--gog-duration-base);
--gog-checkbox-dash-width-ratio: 0.45;
--gog-checkbox-dash-height: 2px;
--gog-checkbox-dash-radius: 999px;
/* ── Radio group ───────────────────────────────────────────────────────────
Box/label size reuse the `--gog-control-checkbox-*` scale (see Checkbox above);
radio-group.component.ts maps the `size` input onto the host the same way. */
--gog-radio-font-family: var(--gog-font-body);
--gog-radio-group-gap: var(--gog-space-12);
--gog-radio-group-label-size: var(--gog-text-sm);
--gog-radio-group-label-color: var(--gog-muted-text-color);
--gog-radio-group-option-gap: var(--gog-space-8);
--gog-radio-group-option-gap-horizontal: var(--gog-space-20);
--gog-radio-gap: var(--gog-space-12);
--gog-radio-border-width: var(--gog-control-border-width);
--gog-radio-border-style: var(--gog-control-border-style);
--gog-radio-border-color: var(--gog-accent-dim);
--gog-radio-bg: var(--gog-surface-color);
--gog-radio-checked-bg: var(--gog-surface-color);
--gog-radio-checked-border: var(--gog-accent-color);
--gog-radio-dot-color: var(--gog-accent-color);
--gog-radio-dot-size-ratio: 0.45;
--gog-radio-label-color: var(--gog-muted-text-color);
--gog-radio-label-line-height: var(--gog-line-height-snug);
/* The accent, not `--gog-accent-pale`. This outline is the *only* thing marking focus on this
control, and a pale wash cannot carry that: measured 1.38:1 against the light page, against
the 3:1 WCAG 2.4.11 and 1.4.11 both require. Fourteen of the library's focus rings already
read `--gog-accent-color`; these were the outliers, found by the boundary sweep in 21.12.0. */
--gog-radio-focus-ring: var(--gog-accent-color);
--gog-radio-focus-ring-width: var(--gog-focus-ring-width);
--gog-radio-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-radio-disabled-opacity: var(--gog-disabled-opacity);
--gog-radio-transition-duration: var(--gog-duration-base);
--gog-radio-error-font-size: var(--gog-text-xs);
--gog-radio-error-line-height: var(--gog-field-error-line-height);
--gog-radio-error-color: var(--gog-danger-color);
/* ── Chip ──────────────────────────────────────────────────────────────────
`--gog-chip-*` size tokens below are the per-size scale; the unsuffixed
`--gog-chip-font-size`/`-padding-*`/`-gap`/`-avatar-size`/`-icon-size`/
`-remove-size` are left undeclared as the per-instance escape hatch. */
--gog-chip-font-family: inherit;
--gog-chip-bg: var(--gog-surface-color);
--gog-chip-hover-bg: var(--gog-hover-color);
--gog-chip-press-bg: var(--gog-border-color);
--gog-chip-border: var(--gog-control-boundary-color);
--gog-chip-border-width: var(--gog-border-width);
--gog-chip-border-style: var(--gog-border-style);
--gog-chip-color: var(--gog-text-color);
--gog-chip-font-weight: var(--gog-font-weight-medium);
--gog-chip-line-height: var(--gog-line-height-tight);
--gog-chip-radius: max(var(--gog-radius), 2px);
--gog-chip-pill-radius: 9999px;
--gog-chip-remove-color: var(--gog-muted-text-color);
--gog-chip-remove-hover-color: var(--gog-text-color);
/* The ring around the remove mark, as a ratio of the mark itself -- so `1` is the box the
glyph occupies and anything above it is padding. It multiplied the button's *font-size*
until 21.13.0, which is not the same thing: `gog-icon` draws at `--gog-icon-size` (1.2em) of
that font-size, so a value of 1.1 produced a box 9% narrower than its own contents. A
consumer who had overridden this gets a larger box than before at the same number; the
number now means what the name says. */
--gog-chip-remove-scale: 1;
--gog-chip-avatar-inset-ratio: 0.9;
--gog-chip-remove-inset-ratio: 0.85;
--gog-chip-disabled-opacity: var(--gog-disabled-opacity);
/* A selected filter chip (`[(selected)]`, 21.9.0). An inset ring for the reason
`--gog-button-primary-toggled-shadow` gives: hover and press own the background, and a
selected chip has to stay selected while it is also hovered or held. The accent, so it is
the same pair the focus ring is already gated on — and unlike the button there is only one
chip variant, so one token covers it. Override this token on the host to restyle a single
chip. */
--gog-chip-selected-ring-width: 2px;
--gog-chip-selected-shadow: inset 0 0 0 var(--gog-chip-selected-ring-width)
var(--gog-accent-color);
/* The chip had a focus-ring width and offset but no colour, so `chip.component.scss` reached
for `--gog-chip-border` — the decorative hairline, 1.18:1 in `primeng`. A focus indicator
needs a colour of its own. */
--gog-chip-focus-ring-color: var(--gog-accent-color);
--gog-chip-focus-ring-width: 2px;
--gog-chip-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-chip-xsm-font-size: var(--gog-text-2xs);
--gog-chip-xsm-padding-block: var(--gog-space-4);
--gog-chip-xsm-padding-inline: var(--gog-space-8);
--gog-chip-xsm-gap: var(--gog-space-4);
/* The avatar and the icon are ratios of the chip's own type, not px ladders of their own.
The icon already was one and nobody had written it down: 11/12/14/16/18px of glyph beside a
label of exactly 11/12/14/16/18px, five sizes holding 1.00 five times by hand. `1em` states
it, and it changes nothing rendered -- but it means an override of one size's font-size now
carries the icon with it, which the rem ladder did not.
The avatar had no rule at all: 14/16/20/24/28px against that same type is 1.27, 1.33, 1.43,
1.50, 1.56 -- five opinions about one relationship, drifting monotonically, which is what a
value picked by eye per size looks like. 1.5em is the ratio `lg` already held, and it keeps
the intent the rest of the component is built around: the avatar is larger than the label
and hugs the chip's leading edge, which is what `--gog-chip-avatar-inset-ratio` exists for.
A chip with an avatar is still taller than one without, but now by one constant ratio
instead of a gap that grew 0.8px to 6.4px across the five sizes.
The remove button's glyph is the third of the same family and now the same kind of rule:
1.125em, one number where there were five. Those five were 1.091, 1.167, 1.143, 1.125 and
1.111 of the label -- non-monotonic and inside a 7% band, which is a px ladder converted to
rem rather than five judgements. 1.125 is the ratio `lg` already held, the same way 1.5 was
the avatar's, and it keeps what all five values agreed on: the mark a reader can press
reads a shade heavier than the one that only decorates. No size moves by more than half a
pixel. The painted box is `--gog-chip-remove-scale` of the *mark* -- see chip.component.scss,
which had to stop writing that multiplication against this token's own em basis. */
--gog-chip-xsm-avatar-size: 1.5em;
--gog-chip-xsm-icon-size: 1em;
--gog-chip-xsm-remove-size: 1.125em;
--gog-chip-sm-font-size: var(--gog-text-xs);
--gog-chip-sm-padding-block: var(--gog-space-4);
--gog-chip-sm-padding-inline: var(--gog-space-8);
--gog-chip-sm-gap: var(--gog-space-8);
--gog-chip-sm-avatar-size: 1.5em;
--gog-chip-sm-icon-size: 1em;
--gog-chip-sm-remove-size: 1.125em;
--gog-chip-md-font-size: var(--gog-text-sm);
--gog-chip-md-padding-block: var(--gog-space-8);
--gog-chip-md-padding-inline: var(--gog-space-16);
--gog-chip-md-gap: var(--gog-space-8);
--gog-chip-md-avatar-size: 1.5em;
--gog-chip-md-icon-size: 1em;
--gog-chip-md-remove-size: 1.125em;
--gog-chip-lg-font-size: var(--gog-text-md);
--gog-chip-lg-padding-block: var(--gog-space-12);
--gog-chip-lg-padding-inline: var(--gog-space-24);
--gog-chip-lg-gap: var(--gog-space-12);
--gog-chip-lg-avatar-size: 1.5em;
--gog-chip-lg-icon-size: 1em;
--gog-chip-lg-remove-size: 1.125em;
--gog-chip-slg-font-size: var(--gog-text-lg);
--gog-chip-slg-padding-block: var(--gog-space-12);
--gog-chip-slg-padding-inline: var(--gog-space-24);
--gog-chip-slg-gap: var(--gog-space-12);
--gog-chip-slg-avatar-size: 1.5em;
--gog-chip-slg-icon-size: 1em;
--gog-chip-slg-remove-size: 1.125em;
/* ── Dialog ────────────────────────────────────────────────────────────────── */
--gog-dialog-font-family: var(--gog-font-heading);
/* Deliberately a flat value rather than a palette derivation: the scrim has to read
the same over any page content. Restate it per theme if a lighter wash suits. */
--gog-dialog-backdrop-bg: rgba(10, 8, 3, 0.72);
--gog-dialog-backdrop-blur: 2px;
--gog-dialog-backdrop-padding: var(--gog-space-lg);
--gog-dialog-backdrop-fade-duration: var(--gog-duration-base);
--gog-dialog-enter-duration: var(--gog-duration-slow);
--gog-dialog-enter-distance: -12px;
--gog-dialog-bg: var(--gog-surface-color);
--gog-dialog-color: var(--gog-text-color);
--gog-dialog-border: var(--gog-border-color);
--gog-dialog-border-width: var(--gog-panel-border-width);
--gog-dialog-border-style: var(--gog-panel-border-style);
--gog-dialog-radius: var(--gog-radius);
--gog-dialog-min-width: 320px;
--gog-dialog-max-height: 90vh;
--gog-dialog-header-padding: var(--gog-space-16) var(--gog-space-20) var(--gog-space-16);
--gog-dialog-header-gap: var(--gog-space-12);
--gog-dialog-header-border-color: var(--gog-border-color);
/* `.gog-dialog__title` is the library's only <h2>; before this it rendered at the browser's
default 24px bold rather than a stated size. --gog-text-xl is exactly today's rendered size,
so this states an accident as a declaration rather than changing anything visible. `snug`
(1.3) is law 4's `heading` role (docs/component-geometry.md, D4). */
--gog-dialog-title-font-size: var(--gog-text-xl);
--gog-dialog-title-line-height: var(--gog-line-height-snug);
--gog-dialog-body-padding: var(--gog-space-20);
--gog-dialog-body-max-height: calc(var(--gog-dialog-max-height) - 60px);
--gog-dialog-close-size: 2rem;
--gog-dialog-close-font-size: var(--gog-text-sm);
--gog-dialog-close-line-height: var(--gog-line-height-none);
--gog-dialog-close-color: var(--gog-muted-text-color);
--gog-dialog-close-hover-color: var(--gog-text-color);
--gog-dialog-close-hover-bg: var(--gog-hover-color);
--gog-dialog-close-hover-border: var(--gog-border-color);
--gog-dialog-close-focus-ring: var(--gog-accent-color);
--gog-dialog-close-focus-ring-width: var(--gog-focus-ring-width);
--gog-dialog-close-focus-ring-offset: var(--gog-focus-ring-offset);
/* Confirmation dialog */
--gog-confirmation-dialog-gap: var(--gog-space-12);
--gog-confirmation-dialog-min-width: 320px;
/* The title and description carried dead utility classes (`heading-md` / `body-sm`) with no
CSS rule anywhere in the library, so both rendered at whatever the browser inherited rather
than a step of the type scale (docs/backlog.md, fixed here). `lg` for the title rather than
`md`: the dead class named `md`, but it never ran, so it is not evidence of intent — 18.72px
is what actually rendered, and --gog-text-lg (18px) is the nearest step to that, so this
states what shipped rather than silently shrinking every confirmation dialog. The description
takes `sm`, the size every other muted secondary line in the library already uses. */
--gog-confirmation-dialog-title-font-size: var(--gog-text-lg);
--gog-confirmation-dialog-title-line-height: var(--gog-line-height-snug);
--gog-confirmation-dialog-description-font-size: var(--gog-text-sm);
--gog-confirmation-dialog-description-line-height: var(--gog-line-height-relaxed);
/* L9 (docs/component-geometry.md, "D7 — taken"): the description wraps, so its cap is a
measure — 51ch at 16px, the nearest whole character to today's 440px, so this changes
robustness to a font-size change, not the pixels anyone sees today. The 16px is
`.confirm-dialog`'s own inherited size (it declares no font-size of its own; see
confirmation-dialog.component.scss), not the description's — the description now reads
--gog-confirmation-dialog-description-font-size (14px, fixed above), but a `ch` cap resolves
against the element `max-width` is declared on, never a descendant's, so that change does not
move this number. What it changes is the *measure* the 440px produces against a 14px
description: 439.9px ÷ (0.5391 × 14px) ≈ 58ch by hand (scripts/survey-measure.mjs's own
`chCount` line is a tautology for this token — it resolves against `.confirm-dialog`'s 16px,
not the description's font; see that script's reason string for the full account), still
inside L9's 45–75 band, so no token value here needs to change.
L8's viewport clamp is deliberately NOT here, unlike the other three overlays: this renders
inside .gog-dialog__panel, which already caps itself at 90vw (an inline style in
dialog.component.html), and .gog-dialog__body spends --gog-dialog-body-padding a side inside
that. The width available here is therefore `0.9 * 100vw - 40px`, tighter than any
`100vw - margin` clamp at every viewport above 80px, so a second clamp on the child could
never bind. An inert declaration is the thing this repo keeps finding rather than shipping. */
--gog-confirmation-dialog-max-width: 51ch;
--gog-confirmation-dialog-color: var(--gog-text-color);
--gog-confirmation-dialog-description-color: var(--gog-muted-text-color);
--gog-confirmation-dialog-actions-gap: var(--gog-space-sm);
--gog-confirmation-dialog-actions-offset: var(--gog-space-sm);
/* ── Autocomplete ──────────────────────────────────────────────────────────
A combobox whose trigger is a real text input. Padding/font-size reuse the shared
`--gog-field-<size>-*` scale, so it lines up with `gog-inputfield` and `gog-select` in a
form. `--gog-autocomplete-bg`, `-color`, `-font-size`, `-padding-x` and `-padding-y` are
intentionally NOT declared — they are the per-instance escape hatch the size classes fall
back through. */
--gog-autocomplete-font-family: var(--gog-font-body);
--gog-autocomplete-label-font-family: var(--gog-font-heading);
--gog-autocomplete-gap: var(--gog-space-4);
--gog-autocomplete-label-color: var(--gog-accent-color);
--gog-autocomplete-label-font-size: var(--gog-text-sm);
--gog-autocomplete-label-line-height: var(--gog-field-label-line-height);
--gog-autocomplete-label-font-weight: var(--gog-font-weight-semibold);
--gog-autocomplete-label-letter-spacing: var(--gog-letter-spacing);
--gog-autocomplete-label-text-transform: var(--gog-text-transform);
--gog-autocomplete-field-bg: var(--gog-surface-color);
--gog-autocomplete-text-color: var(--gog-text-color);
--gog-autocomplete-placeholder-color: var(--gog-muted-text-color);
--gog-autocomplete-border-width: var(--gog-control-border-width);
--gog-autocomplete-border-style: var(--gog-control-border-style);
--gog-autocomplete-border-color: var(--gog-accent-dim);
--gog-autocomplete-hover-border-color: var(--gog-accent-color);
--gog-autocomplete-radius: var(--gog-radius);
--gog-autocomplete-line-height: var(--gog-line-height-normal);
--gog-autocomplete-transition-duration: var(--gog-duration-base);
--gog-autocomplete-disabled-opacity: var(--gog-disabled-opacity);
--gog-autocomplete-focus-ring-width: var(--gog-focus-ring-width);
--gog-autocomplete-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-autocomplete-focus-ring-color: var(--gog-accent-color);
--gog-autocomplete-error-color: var(--gog-danger-color);
--gog-autocomplete-error-border-color: var(--gog-danger-color);
--gog-autocomplete-error-font-family: var(--gog-font-body);
--gog-autocomplete-error-font-size: var(--gog-text-xs);
--gog-autocomplete-error-line-height: var(--gog-field-error-line-height);
/* Floor for an auto-width field, so [fullWidth]="false" cannot collapse it to its chrome. */
--gog-autocomplete-min-width: 120px;
/* Trailing chrome: spinner and clear button, clear outermost — the arrangement the other
dropdowns settled on, so all of them line up in a form. */
--gog-autocomplete-actions-inset: var(--gog-control-icon-offset);
--gog-autocomplete-actions-gap: var(--gog-space-8);
/* Right padding on the input, reserving room for the actions above. */
--gog-autocomplete-actions-reserve: 40px;
--gog-autocomplete-clear-color: var(--gog-autocomplete-placeholder-color);
--gog-autocomplete-clear-hover-color: var(--gog-autocomplete-label-color);
--gog-autocomplete-clear-icon-ratio: var(--gog-control-clear-icon-ratio);
--gog-autocomplete-spinner-size: 0.875rem;
/* Panel */
--gog-autocomplete-panel-bg: var(--gog-surface-color);
--gog-autocomplete-panel-shadow: var(--gog-panel-shadow);
--gog-autocomplete-panel-border-width: var(--gog-panel-border-width);
--gog-autocomplete-panel-border-style: var(--gog-panel-border-style);
--gog-autocomplete-panel-border-color: var(--gog-border-color);
--gog-autocomplete-panel-radius: var(--gog-radius);
--gog-autocomplete-panel-gap: var(--gog-space-4);
--gog-autocomplete-panel-max-height: 260px;
/* Ceiling for a content-sized panel, so one very long option cannot span the viewport. */
--gog-autocomplete-panel-max-width: 420px;
--gog-autocomplete-options-padding: var(--gog-space-4);
--gog-autocomplete-option-padding: var(--gog-space-8) var(--gog-space-16);
/* Concentric with the panel: the option row is inset by the list's own padding, so its corner
is the panel's corner minus that distance. Written as the two tokens rather than as
`calc(var(--gog-radius) - 4px)`, which was right only at `--gog-density: 1` -- the padding
scales with density and a restated `4px` does not. */
--gog-autocomplete-option-radius: max(
0px,
calc(var(--gog-autocomplete-panel-radius) - var(--gog-autocomplete-options-padding))
);
/* The gap *inside* a row -- icon to label. Not the gap between rows; see the select's own
note above the same token. */
--gog-autocomplete-option-gap: var(--gog-space-12);
--gog-autocomplete-option-color: var(--gog-text-color);
--gog-autocomplete-option-hover-bg: var(--gog-hover-color);
--gog-autocomplete-option-press-bg: var(--gog-border-color);
--gog-autocomplete-option-hover-color: var(--gog-text-color);
--gog-autocomplete-option-selected-bg: var(--gog-accent-pale);
/* Body text, not the accent. The selected row is the one option that carries a tint *and* a
coloured label, and the accent on that tint measured 4.12:1 in light — `--gog-accent-dim` is
worse again (3.77:1 in one-dark). `gog-select` gets away with an accent label because its
selected option has no tint behind it. The tint stays as the marker, alongside
`aria-selected`. */
--gog-autocomplete-option-selected-color: var(--gog-text-color);
/* The row height the panel's up/down placement math starts from. **A seed, not a claim**: the
component measures a real row one frame after the panel renders and re-places if this
disagreed, so this value only governs the very first open of an instance.
It used to say "an estimate ... no effect unless the JS reads it", and the JS did read it,
for a layout decision. Measured against a rendered row it is wrong in all eleven shipped
themes -- low in ten, by up to 8.38px -- and no static value can be right, since the row is
padding plus leading plus border and a theme or `--gog-density` moves every term. Overriding
this is still worth doing if your rows are very unusual: it buys the first frame. */
--gog-autocomplete-option-height: 36px;
--gog-autocomplete-empty-color: var(--gog-autocomplete-placeholder-color);
--gog-autocomplete-empty-font-size: var(--gog-text-sm);
--gog-autocomplete-empty-line-height: var(--gog-line-height-normal);
--gog-autocomplete-float-label-reserve: var(--gog-field-float-label-reserve);
--gog-autocomplete-float-label-in-top: var(--gog-field-float-label-in-top);
--gog-autocomplete-float-label-over-gap: var(--gog-field-float-label-over-gap);
--gog-autocomplete-float-label-over-reserve: var(--gog-field-float-label-over-reserve);
/* ── Badge (the `gogBadge` directive; its classes live in utilities.css) ───── */
--gog-badge-font-family: var(--gog-font-body);
--gog-badge-font-size: var(--gog-text-xs);
--gog-badge-font-weight: var(--gog-font-weight-semibold);
--gog-badge-line-height: var(--gog-line-height-none);
/* Min-width *and* height: a one-digit badge stays a circle, a three-digit one grows
sideways only. */
--gog-badge-size: 1.25rem;
--gog-badge-dot-size: 0.5rem;
--gog-badge-padding-inline: var(--gog-space-4);
--gog-badge-radius: 999px;
/* How far the badge hangs outside its host's corner. `space-8` rather than the `space-6` it
was: every off-grid step this library had sat exactly halfway between two grid steps, so the
4px grid made the tie-break a real decision, and it rounds up (docs/component-geometry.md,
D3b). Here that is also the better answer on its own terms — a 20px badge hanging 8px out
clears the host's corner radius at `--gog-radius: 8px`, which 6px did not quite do. */
--gog-badge-offset: var(--gog-space-8);
--gog-badge-border-width: 0;
--gog-badge-border-style: var(--gog-border-style);
--gog-badge-border-color: transparent;
/* Above the host's own chrome but below any overlay panel (--gog-dropdown-z is 300). */
/* Each label is its status's own "text on this fill" token, which flips with the theme — a red
badge reads white on light and near-black on dark. It read `--gog-accent-text-color` for all
four until 21.9.0, on the assumption that one label works on every fill; four themes proved
otherwise, `material`'s amber under white at 1.97:1 the worst of them. See the
`--gog-<status>-text-color` block near the top of this file. */
--gog-badge-success-bg: var(--gog-success-color);
--gog-badge-success-color: var(--gog-success-text-color);
--gog-badge-danger-bg: var(--gog-danger-color);
--gog-badge-danger-color: var(--gog-danger-text-color);
--gog-badge-warning-bg: var(--gog-warning-color);
--gog-badge-warning-color: var(--gog-warning-text-color);
--gog-badge-info-bg: var(--gog-info-color);
--gog-badge-info-color: var(--gog-info-text-color);
/* ── Datepicker (the field; the grid inside it is themed by --gog-calendar-*) ───
`--gog-datepicker-bg`, `-color`, `-font-size`, `-padding-x` and `-padding-y` are
intentionally NOT declared — they are the per-instance escape hatch the size classes fall
back through. */
--gog-datepicker-font-family: var(--gog-font-body);
--gog-datepicker-label-font-family: var(--gog-font-heading);
--gog-datepicker-gap: var(--gog-space-4);
--gog-datepicker-label-color: var(--gog-accent-color);
--gog-datepicker-label-font-size: var(--gog-text-sm);
--gog-datepicker-label-line-height: var(--gog-field-label-line-height);
--gog-datepicker-label-letter-spacing: var(--gog-letter-spacing);
--gog-datepicker-label-text-transform: var(--gog-text-transform);
--gog-datepicker-field-bg: var(--gog-surface-color);
--gog-datepicker-text-color: var(--gog-text-color);
--gog-datepicker-placeholder-color: var(--gog-muted-text-color);
--gog-datepicker-border-width: var(--gog-control-border-width);
--gog-datepicker-border-style: var(--gog-control-border-style);
--gog-datepicker-border-color: var(--gog-accent-dim);
--gog-datepicker-hover-border-color: var(--gog-accent-color);
--gog-datepicker-radius: var(--gog-radius);
--gog-datepicker-line-height: var(--gog-line-height-normal);
--gog-datepicker-transition-duration: var(--gog-duration-base);
--gog-datepicker-disabled-opacity: var(--gog-disabled-opacity);
--gog-datepicker-focus-ring-width: var(--gog-focus-ring-width);
--gog-datepicker-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-datepicker-focus-ring-color: var(--gog-accent-color);
--gog-datepicker-error-color: var(--gog-danger-color);
--gog-datepicker-error-border-color: var(--gog-danger-color);
--gog-datepicker-error-font-family: var(--gog-font-body);
--gog-datepicker-error-font-size: var(--gog-text-xs);
--gog-datepicker-error-line-height: var(--gog-field-error-line-height);
--gog-datepicker-min-width: 150px;
--gog-datepicker-actions-inset: var(--gog-control-icon-offset);
--gog-datepicker-actions-gap: var(--gog-space-8);
/* Right padding on the input, reserving room for the calendar and clear buttons. */
--gog-datepicker-actions-reserve: 40px;
--gog-datepicker-icon-color: var(--gog-accent-color);
--gog-datepicker-icon-hover-color: var(--gog-accent-bright);
--gog-datepicker-toggle-icon-size: 1rem;
--gog-datepicker-clear-color: var(--gog-datepicker-placeholder-color);
--gog-datepicker-clear-icon-ratio: var(--gog-control-clear-icon-ratio);
--gog-datepicker-panel-bg: var(--gog-surface-color);
--gog-datepicker-panel-shadow: var(--gog-panel-shadow);
--gog-datepicker-panel-border-width: var(--gog-panel-border-width);
--gog-datepicker-panel-border-style: var(--gog-panel-border-style);
--gog-datepicker-panel-border-color: var(--gog-border-color);
--gog-datepicker-panel-radius: var(--gog-radius);
--gog-datepicker-panel-gap: var(--gog-space-4);
/* The dropdown surface. Inline mode is `gog-calendar` itself, so it sizes from
`--gog-calendar-max-width` rather than from this. */
--gog-datepicker-panel-width: max-content;
--gog-datepicker-float-label-reserve: var(--gog-field-float-label-reserve);
--gog-datepicker-float-label-in-top: var(--gog-field-float-label-in-top);
--gog-datepicker-float-label-over-gap: var(--gog-field-float-label-over-gap);
--gog-datepicker-float-label-over-reserve: var(--gog-field-float-label-over-reserve);
/* ── Divider ───────────────────────────────────────────────────────────────── */
--gog-divider-line-color: var(--gog-border-color);
--gog-divider-line-thickness: 1px;
/* The variant classes map onto these, so a theme can decide what "dashed" looks like
rather than the value being frozen into the component's stylesheet. */
--gog-divider-solid-style: solid;
--gog-divider-dashed-style: dashed;
--gog-divider-dotted-style: dotted;
--gog-divider-block-spacing: var(--gog-space-md);
--gog-divider-inline-spacing: var(--gog-space-md);
--gog-divider-inset-size: var(--gog-space-lg);
/* Floor for a vertical divider with nothing to stretch to — e.g. between two inline
buttons. In a flex/grid row it stretches to the row instead. */
--gog-divider-vertical-length: 1.5em;
--gog-divider-label-gap: var(--gog-space-sm);
--gog-divider-label-color: var(--gog-muted-text-color);
--gog-divider-label-font-family: var(--gog-font-body);
--gog-divider-label-font-size: var(--gog-text-sm);
--gog-divider-label-font-weight: var(--gog-font-weight-medium);
--gog-divider-label-line-height: var(--gog-line-height-normal);
/* ── Icon ──────────────────────────────────────────────────────────────────── */
--gog-icon-fallback-size: 1em;
/* ── Input field ───────────────────────────────────────────────────────────── */
--gog-input-font-family: var(--gog-font-body);
--gog-input-label-font-family: var(--gog-font-heading);
--gog-input-gap: var(--gog-space-4);
--gog-input-label-color: var(--gog-accent-color);
--gog-input-label-font-size: var(--gog-text-sm);
--gog-input-label-line-height: var(--gog-field-label-line-height);
--gog-input-label-letter-spacing: var(--gog-letter-spacing);
--gog-input-label-text-transform: var(--gog-text-transform);
--gog-input-field-bg: var(--gog-surface-color);
--gog-input-field-border: var(--gog-accent-dim);
--gog-input-field-border-width: var(--gog-control-border-width);
--gog-input-field-border-style: var(--gog-control-border-style);
--gog-input-radius: var(--gog-radius);
--gog-input-field-color: var(--gog-text-color);
--gog-input-placeholder-color: var(--gog-muted-text-color);
--gog-input-focus-border: var(--gog-accent-color);
--gog-input-focus-ring: var(--gog-accent-pale);
--gog-input-focus-glow: 0 0 8px var(--gog-input-focus-ring);
--gog-input-focus-ring-width: var(--gog-focus-ring-width);
--gog-input-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-input-error-color: var(--gog-danger-color);
--gog-input-error-font-size: var(--gog-text-xs);
--gog-input-error-line-height: var(--gog-field-error-line-height);
/* Extra space above the error line, *on top of* the host's own `--gog-input-gap`, which
already separates every child of the field. It shipped as `2px` and put this field's error
6px under it while `gog-select`, `gog-autocomplete` and `gog-datepicker` — same gap, no
offset — sat at 4px; in one form the six did not line up. Zero by default since 21.9.0, so
one mechanism spaces the error line everywhere. Set it if you want this field's error
pushed further than the rest. */
--gog-input-error-offset: 0px;
--gog-input-icon-color: var(--gog-muted-text-color);
--gog-input-icon-line-height: var(--gog-line-height-none);
--gog-input-icon-hover-color: var(--gog-accent-color);
--gog-input-icon-action-radius: calc(var(--gog-radius) - 4px);
--gog-input-icon-focus-ring-width: 2px;
/* Number field's spin buttons — a subtle fill on hover, since they sit flush against the
field's own border rather than floating with their own padding like the other icons. */
--gog-input-spin-hover-bg: var(--gog-hover-color);
--gog-input-disabled-opacity: var(--gog-disabled-opacity);
--gog-input-transition-duration: var(--gog-duration-base);
/* Float label — also used by gog-textarea, which shares the --gog-input-* block. */
/* Clear button — only rendered once the field has text, see `clearable`.
A quarter of the corner radius rather than a flat `2px`, which is what this was until
21.9.0: at the default `--gog-radius: 8px` it computes to the same 2px, so nothing moves in
any shipped theme, but a theme that rounds its corners now rounds this button too. The
literal was invisible to `check-tokens` rule G by design — that rule flags a literal only
when its value *equals* a character token's current one, so a pill's `999px` is correctly
left alone and a small arbitrary number like this one is correctly not detectable. The two
sibling controls below carry the same fix.
`gog-toast` and `gog-accordion` keep their flat `0px` on purpose: those are a chosen shape,
not a number that forgot where it came from. */
--gog-input-clear-radius: calc(var(--gog-radius) / 4);
--gog-input-clear-line-height: var(--gog-line-height-none);
--gog-input-clear-icon-ratio: var(--gog-control-clear-icon-ratio);
/*
The textarea's clear button gets a full-size glyph. The 0.7 ratio above suits the dense
single-line trigger of a dropdown; on a large multi-line box it reads as a speck.
*/
--gog-textarea-clear-icon-ratio: 1;
/* The field is the one place in the library that renders a paragraph the consumer typed:
role prose. */
--gog-textarea-line-height: var(--gog-line-height-relaxed);
/* Custom resize grip — see the `::-webkit-resizer` comment in textarea.component.scss for
why this replaces rather than restyles the native glyph. Colour follows the field's own
border by default, not a fixed muted grey, so it reads as part of the field rather than a
mismatched accent. */
--gog-textarea-resize-grip-size: 11px;
--gog-textarea-resize-grip-color: var(--gog-input-field-border);
--gog-textarea-resize-grip-opacity: 0.8;
--gog-textarea-resize-grip-stripe-width: 1.5px;
/* The three hairlines of the resize grip and the gap between them: a length inside one painted
mark, not spacing between two things, so it is off the 4px grid on purpose (OPTICAL_CHROME in
check-geometry.mjs). At 4px the three stripes would be a 20px block in the corner of every
textarea instead of a 9px hint. */
--gog-textarea-resize-grip-stripe-gap: 2px;
--gog-textarea-resize-grip-offset: var(--gog-space-4);
/*
Both default to 0 and are overwritten per instance, as an inline style on the field, from
the component's own ResizeObserver — they close the gap that opens once the field has been
dragged narrower/shorter than its container. Declared here rather than left to a `var()`
fallback so the grip's resting geometry is discoverable in this file like everything else;
an inline style outranks this declaration, so the per-instance override still wins.
*/
--gog-textarea-resize-inset-right: 0px;
--gog-textarea-resize-inset-bottom: 0px;
--gog-input-clear-inset: var(--gog-space-8);
/*
Width of one stepper button, and so of the whole stepper column. Scales with the field's
own font size rather than being a fixed px value, so it stays proportional across the five
sizes. Read in two places — the buttons themselves, and the offset that moves the clear
button clear of them on a clearable number field — which is why it is a token rather than
the same `calc()` written twice.
*/
--gog-input-spin-width: calc(
var(--gog-input-size-font-size, var(--gog-field-md-font-size)) * 1.35
);
--gog-input-float-label-reserve: var(--gog-field-float-label-reserve);
--gog-input-float-label-in-top: var(--gog-field-float-label-in-top);
--gog-input-float-label-over-gap: var(--gog-field-float-label-over-gap);
--gog-input-float-label-over-reserve: var(--gog-field-float-label-over-reserve);
/* ── Multiselect ───────────────────────────────────────────────────────────── */
--gog-multiselect-font-family: var(--gog-font-body);
--gog-multiselect-label-font-family: var(--gog-font-heading);
--gog-multiselect-gap: var(--gog-space-4);
/* The gap *between* rows -- the only one of the three lists that declares one. The inside
of a row is `--gog-multiselect-option-gap-inline`. */
--gog-multiselect-option-gap: var(--gog-space-4);
--gog-multiselect-options-padding: var(--gog-space-4);
--gog-multiselect-label-color: var(--gog-accent-color);
--gog-multiselect-label-font-size: var(--gog-text-sm);
--gog-multiselect-label-line-height: var(--gog-field-label-line-height);
--gog-multiselect-label-letter-spacing: var(--gog-letter-spacing);
--gog-multiselect-label-text-transform: var(--gog-text-transform);
--gog-multiselect-field-bg: var(--gog-surface-color);
--gog-multiselect-field-border: var(--gog-accent-dim);
--gog-multiselect-field-border-width: var(--gog-control-border-width);
--gog-multiselect-field-border-style: var(--gog-control-border-style);
--gog-multiselect-radius: var(--gog-radius);
--gog-multiselect-field-color: var(--gog-text-color);
--gog-multiselect-value-color: var(--gog-text-color);
--gog-multiselect-placeholder-color: var(--gog-muted-text-color);
--gog-multiselect-focus-border: var(--gog-accent-color);
/* The accent, not `--gog-accent-pale`. This outline is the *only* thing marking focus on this
control, and a pale wash cannot carry that: measured 1.38:1 against the light page, against
the 3:1 WCAG 2.4.11 and 1.4.11 both require. Fourteen of the library's focus rings already
read `--gog-accent-color`; these were the outliers, found by the boundary sweep in 21.12.0. */
--gog-multiselect-focus-ring: var(--gog-accent-color);
--gog-multiselect-focus-glow: 0 0 8px var(--gog-multiselect-focus-ring);
--gog-multiselect-focus-ring-width: var(--gog-focus-ring-width);
--gog-multiselect-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-multiselect-error-color: var(--gog-danger-color);
--gog-multiselect-error-font-size: var(--gog-text-xs);
--gog-multiselect-error-line-height: var(--gog-field-error-line-height);
/* Zero by default since 21.9.0 — see `--gog-input-error-offset` for why. */
--gog-multiselect-error-offset: 0px;
--gog-multiselect-border-color: var(--gog-accent-color);
--gog-multiselect-panel-bg: var(--gog-surface-color);
--gog-multiselect-panel-border: var(--gog-accent-color);
--gog-multiselect-panel-shadow: var(--gog-panel-shadow);
/* The panel's own corner, and the reason it is not `--gog-multiselect-radius`: that token
shapes the *field*, and it shaped this box too until this release. One token painting two
boxes meant a consumer rounding the field into a pill rounded the dropdown into one as well,
and the two radii below derive from whatever it is, so the filter and the option rows
followed. Same default, so nothing moves; `gog-autocomplete` and `gog-datepicker` already
declared this token and this is the pair that did not. */
--gog-multiselect-panel-radius: var(--gog-radius);
--gog-multiselect-panel-max-height: 260px;
/* `--gog-multiselect-panel-offset` until 21.13.0; the old name stopped resolving in 21.14.0. */
--gog-multiselect-panel-gap: var(--gog-space-4);
--gog-multiselect-option-hover-bg: var(--gog-hover-color);
--gog-multiselect-option-press-bg: var(--gog-border-color);
--gog-multiselect-option-color: var(--gog-text-color);
--gog-multiselect-option-gap-inline: var(--gog-space-12);
/* The row height the panel's up/down placement math starts from. **A seed, not a claim**: the
component measures a real row one frame after the panel renders and re-places if this
disagreed, so this value only governs the very first open of an instance.
It used to say "an estimate ... no effect unless the JS reads it", and the JS did read it,
for a layout decision. Measured against a rendered row it is wrong in all eleven shipped
themes -- low in ten, by up to 8.38px -- and no static value can be right, since the row is
padding plus leading plus border and a theme or `--gog-density` moves every term. Overriding
this is still worth doing if your rows are very unusual: it buys the first frame. */
--gog-multiselect-option-height: 40px;
/* Concentric with the panel, which paints `--gog-multiselect-panel-radius` and insets its rows
by the list padding, so the row's corner is that radius minus that padding. It had subtracted
2px against 4px of padding, and a restated literal also stops being true once density moves. */
--gog-multiselect-option-radius: max(
0px,
calc(var(--gog-multiselect-panel-radius) - var(--gog-multiselect-options-padding))
);
--gog-multiselect-option-disabled-opacity: var(--gog-disabled-opacity);
--gog-multiselect-option-transition-duration: var(--gog-duration-fast);
--gog-multiselect-checkbox-border: var(--gog-accent-dim);
--gog-multiselect-checkbox-checked-bg: var(--gog-accent-color);
--gog-multiselect-controls-gap: var(--gog-space-4);
--gog-multiselect-controls-padding: var(--gog-space-8) var(--gog-space-12);
--gog-multiselect-actions-gap: var(--gog-space-8);
--gog-multiselect-filter-padding: var(--gog-space-8);
--gog-multiselect-filter-input-padding-y: var(--gog-space-8);
--gog-multiselect-filter-input-padding-x: var(--gog-space-16);
--gog-multiselect-filter-input-bg: var(--gog-background-color);
--gog-multiselect-filter-input-color: var(--gog-multiselect-field-color);
--gog-multiselect-filter-input-border: var(--gog-multiselect-field-border);
/* Concentric with the panel, and the concentric answer here is a square corner. The filter is
inset by `--gog-multiselect-filter-padding`, which equals the panel's radius -- and where the
inset equals the radius, the inner box's corner point lands exactly on the centre of the
outer arc, so a right angle is equidistant from the whole curve. It is the only shape that
keeps the gap constant, not a value clamped to zero for want of a better one. */
--gog-multiselect-filter-input-radius: max(
0px,
calc(var(--gog-multiselect-panel-radius) - var(--gog-multiselect-filter-padding))
);
--gog-multiselect-filter-border-width: var(--gog-panel-border-width);
--gog-multiselect-filter-border-style: var(--gog-panel-border-style);
--gog-multiselect-filter-border-color: var(--gog-border-color);
--gog-multiselect-filter-empty-padding: var(--gog-space-12);
--gog-multiselect-filter-empty-color: var(--gog-multiselect-placeholder-color);
/* Matches --gog-select-chevron-inset; see the note there. */
/* "+N" badge shown when the selection does not fit on one line. */
--gog-multiselect-overflow-color: var(--gog-multiselect-placeholder-color);
--gog-multiselect-overflow-font-size: var(--gog-text-sm);
/* It sits on the field values own baseline (align-self: baseline, 21.7.2), so it takes the
field text leading rather than a mark leading. */
--gog-multiselect-overflow-line-height: var(--gog-field-line-height);
--gog-multiselect-overflow-gap: var(--gog-space-8);
--gog-multiselect-min-width: 120px;
--gog-multiselect-panel-max-width: 420px;
--gog-multiselect-actions-inset: var(--gog-control-icon-offset);
/* A quarter of the corner radius — see `--gog-input-clear-radius` for why. */
--gog-multiselect-clear-radius: calc(var(--gog-radius) / 4);
--gog-multiselect-clear-line-height: var(--gog-line-height-none);
--gog-multiselect-disabled-opacity: var(--gog-disabled-opacity);
--gog-multiselect-transition-duration: var(--gog-duration-base);
--gog-multiselect-float-label-reserve: var(--gog-field-float-label-reserve);
--gog-multiselect-float-label-in-top: var(--gog-field-float-label-in-top);
--gog-multiselect-float-label-over-gap: var(--gog-field-float-label-over-gap);
--gog-multiselect-float-label-over-reserve: var(--gog-field-float-label-over-reserve);
--gog-multiselect-arrow-transition-duration: var(--gog-duration-slow);
/* Icon geometry, expressed as a ratio of the control's font size. */
--gog-multiselect-clear-icon-ratio: var(--gog-control-clear-icon-ratio);
--gog-multiselect-arrow-icon-ratio: 0.875;
--gog-multiselect-mark-size-ratio: 1.2375;
--gog-multiselect-mark-icon-ratio: 1.125;
/* ── Menu ──────────────────────────────────────────────────────────────────
The command menu opened by `[gogMenuTrigger]`. Metrics follow the dropdown panel's, so a
menu and a select opened from the same toolbar read as the same surface. */
--gog-menu-z: var(--gog-dropdown-z);
--gog-menu-bg: var(--gog-surface-color);
--gog-menu-border-color: var(--gog-border-color);
--gog-menu-border-width: var(--gog-control-border-width);
--gog-menu-border-style: var(--gog-control-border-style);
--gog-menu-radius: var(--gog-panel-radius);
/* Step 3, with the dropdown panels it belongs beside — not step 5. This aliased
`--gog-dialog-shadow` until 21.12.0, so a dropdown menu carried a modal's elevation. */
--gog-menu-shadow: var(--gog-panel-shadow);
--gog-menu-font-family: var(--gog-font-body);
--gog-menu-padding: var(--gog-space-4);
--gog-menu-gap: var(--gog-space-4);
/* Gap between the trigger and the panel, matching the four other components that place one.
Read by `menu.component.ts`, not by CSS -- a menu panel is positioned in script. */
--gog-menu-panel-gap: var(--gog-space-4);
--gog-menu-min-width: 180px;
/* L8's viewport exception (docs/component-geometry.md, "D7 — taken"): a menu portals into
<body> and floats over the viewport, not a container. Its items do not wrap (L9 does not
apply — the width stays in px), but L8 still does: no edge-inset token exists on this
component today, so the margin reads the scale directly. */
--gog-menu-max-width: min(320px, calc(100vw - var(--gog-space-16) * 2));
--gog-menu-max-height: 320px;
--gog-menu-transition-duration: var(--gog-duration-base);
--gog-menu-focus-ring: var(--gog-accent-color);
--gog-menu-focus-ring-width: var(--gog-focus-ring-width);
--gog-menu-item-color: var(--gog-text-color);
--gog-menu-item-hover-bg: var(--gog-hover-color);
/* The held state, same idea as the button's: one step past this surface's own hover, as a
colour rather than a movement, so `prefers-reduced-motion` cannot take it away. The flat
value here is what a browser without `color-mix()` gets; the tinted one is in the @supports
block at the end of the file. */
--gog-menu-item-press-bg: var(--gog-border-color);
--gog-menu-item-hover-color: var(--gog-text-color);
--gog-menu-item-font-size: var(--gog-text-sm);
--gog-menu-item-padding: var(--gog-space-8) var(--gog-space-16);
/* Concentric with the panel, which paints `--gog-panel-radius` (8px larger than the base) and
insets its items by `--gog-menu-padding`. Repeating the base radius here made the first and
last items visibly squarer than the corner they sit in. */
--gog-menu-item-radius: max(0px, calc(var(--gog-menu-radius) - var(--gog-menu-padding)));
--gog-menu-item-gap: var(--gog-space-sm);
--gog-menu-item-disabled-opacity: var(--gog-disabled-opacity);
--gog-menu-item-disabled-color: var(--gog-muted-text-color);
--gog-menu-item-line-height: var(--gog-line-height-normal);
--gog-menu-item-icon-size: 1em;
/* ── Paginator ─────────────────────────────────────────────────────────────── */
--gog-paginator-gap: var(--gog-space-4);
--gog-paginator-ellipsis-color: var(--gog-muted-text-color);
--gog-paginator-ellipsis-font-size: var(--gog-text-sm);
--gog-paginator-ellipsis-line-height: var(--gog-line-height-none);
--gog-paginator-ellipsis-font-family: var(--gog-font-body);
/* Enough for a three-digit page size plus the chevron, so the row doesn't shift on change. */
--gog-paginator-page-size-min-width: 5rem;
--gog-paginator-ellipsis-min-width: 32px;
/* ── Panel ─────────────────────────────────────────────────────────────────
The `gog-panel` component, which shares its prefix with the foundation surface tier
above (`--gog-panel-radius`, `--gog-panel-shadow`, `--gog-panel-border-width`,
`--gog-panel-border-style`) deliberately: a panel is the surface those describe, and a
theme that sets a house radius for raised surfaces should get it here too.
`--gog-panel-bg`, `--gog-panel-border-color`, `--gog-panel-padding-y`,
`--gog-panel-padding-x` and `--gog-panel-gap` are intentionally NOT declared — the
per-instance escape hatch. There is no `--gog-panel-*-shadow` twin of that hatch for the
elevated variant: it reads `--gog-panel-shadow` from a declaration the component makes on
its own host, so setting that token on one panel already changes only that panel. */
--gog-panel-font-family: var(--gog-font-body);
--gog-panel-color: var(--gog-text-color);
--gog-panel-transition-duration: var(--gog-duration-base);
--gog-panel-heading-color: var(--gog-text-color);
--gog-panel-heading-font-family: var(--gog-font-heading);
--gog-panel-heading-font-size: var(--gog-text-xl);
--gog-panel-heading-font-weight: var(--gog-font-weight-semibold);
/* Role heading, the same step the card heading takes. It had been 1.25 -- the one leading in
the library outside the scale, which runs 1.2 then 1.3 with nothing between. Two headings
four steps apart differing by 0.05 is two people picking a nice number, not the inverse
relationship law 4 describes; that one holds across the roles, where it is real. */
--gog-panel-heading-line-height: var(--gog-line-height-snug);
--gog-panel-outlined-bg: var(--gog-surface-color);
--gog-panel-outlined-border-color: var(--gog-border-color);
--gog-panel-outlined-shadow: none;
--gog-panel-elevated-bg: var(--gog-elevated-surface-color);
--gog-panel-elevated-border-color: transparent;
--gog-panel-filled-bg: var(--gog-accent-pale);
--gog-panel-filled-border-color: transparent;
--gog-panel-filled-shadow: none;
--gog-panel-header-gap: var(--gog-space-sm);
--gog-panel-toggle-size: 2rem;
--gog-panel-toggle-radius: var(--gog-radius);
--gog-panel-toggle-color: var(--gog-muted-text-color);
--gog-panel-toggle-hover-bg: var(--gog-hover-color);
--gog-panel-chevron-size: 1rem;
--gog-panel-focus-ring: var(--gog-accent-color);
--gog-panel-focus-ring-width: var(--gog-focus-ring-width);
--gog-panel-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-panel-disabled-opacity: var(--gog-disabled-opacity);
--gog-panel-footer-border-color: var(--gog-border-color);
--gog-panel-footer-gap: var(--gog-space-sm);
--gog-panel-footer-padding-top: var(--gog-space-sm);
--gog-panel-xsm-padding-y: var(--gog-space-12);
--gog-panel-xsm-padding-x: var(--gog-space-12);
--gog-panel-xsm-gap: var(--gog-space-sm);
--gog-panel-sm-padding-y: var(--gog-space-16);
--gog-panel-sm-padding-x: var(--gog-space-md);
--gog-panel-sm-gap: var(--gog-space-12);
--gog-panel-md-padding-y: var(--gog-space-20);
--gog-panel-md-padding-x: var(--gog-space-20);
--gog-panel-md-gap: var(--gog-space-12);
--gog-panel-lg-padding-y: var(--gog-space-lg);
--gog-panel-lg-padding-x: var(--gog-space-28);
--gog-panel-lg-gap: var(--gog-space-md);
--gog-panel-slg-padding-y: var(--gog-space-32);
--gog-panel-slg-padding-x: var(--gog-space-32);
--gog-panel-slg-gap: var(--gog-space-20);
/* ── Progressbar ──────────────────────────────────────────────────────────── */
--gog-progressbar-track-base-bg: var(--gog-border-color);
--gog-progressbar-radius: 999px;
--gog-progressbar-transition-duration: var(--gog-duration-slow);
--gog-progressbar-xsm-height: 2px;
--gog-progressbar-sm-height: 4px;
--gog-progressbar-md-height: 6px;
--gog-progressbar-lg-height: 10px;
--gog-progressbar-slg-height: 14px;
--gog-progressbar-value-gap: var(--gog-space-sm);
--gog-progressbar-value-min-width: 3ch;
--gog-progressbar-value-color: var(--gog-muted-text-color);
--gog-progressbar-value-font-family: var(--gog-font-body);
--gog-progressbar-value-font-size: var(--gog-text-sm);
--gog-progressbar-value-line-height: var(--gog-line-height-none);
--gog-progressbar-indeterminate-duration: 1.6s;
--gog-progressbar-indeterminate-easing: cubic-bezier(0.65, 0.05, 0.36, 1);
/* The reduced-motion stand-in for the indeterminate animation. */
--gog-progressbar-stripe-size: 6px;
--gog-progressbar-stripe-color: var(--gog-surface-color);
/* The two hairlines that mark where the fill ends, and the reason they are two.
WCAG 1.4.11 wants 3:1 for the part of a graphic that carries its meaning, and here that is
the boundary — `showValue` is `false` by default, so nothing else states the value. The fill
cannot carry it against the track: measured across the whole `--gog-text-color`-to-
`--gog-border-color` axis, no single track colour clears 3:1 against all five fills in any
theme but `primeng`, because the fills straddle mid-luminance and a track dark enough for the
amber warning lands on the blue info (`docs/backlog.md` has the table).
A marker can, but not in one tone either: `--gog-surface-color` alone is 1.79:1 on
`material`'s warning fill, `--gog-text-color` alone is 1.06:1 on `one-dark`'s success. As a
pair they always work — the ink line is 3.25:1 to 9.57:1 against the track in all eleven
themes, and whichever tone a fill sits close to, the other one does not. `check:contrast`
gates both halves. */
--gog-progressbar-edge-width: 1px;
--gog-progressbar-edge-color: var(--gog-text-color);
--gog-progressbar-edge-backing-color: var(--gog-surface-color);
/* The buffer tier is the same hue at low opacity, so it reads as "ahead of the fill"
rather than as a second, competing colour. */
--gog-progressbar-accent-bg: var(--gog-accent-color);
--gog-progressbar-accent-buffer-bg: var(--gog-accent-pale);
--gog-progressbar-success-bg: var(--gog-success-color);
--gog-progressbar-success-buffer-bg: var(--gog-border-color);
--gog-progressbar-danger-bg: var(--gog-danger-color);
--gog-progressbar-danger-buffer-bg: var(--gog-border-color);
--gog-progressbar-warning-bg: var(--gog-warning-color);
--gog-progressbar-warning-buffer-bg: var(--gog-border-color);
--gog-progressbar-info-bg: var(--gog-info-color);
--gog-progressbar-info-buffer-bg: var(--gog-border-color);
/* ── Ripple (the `gogRipple` directive; its classes live in ripple.css) ────
`currentColor` rather than a fixed colour on purpose: the wash then reads as the host's
own foreground, so one value works on a filled button and on a ghost one without a
per-variant tier. The property is inherited, so `--gog-ripple-color` set anywhere above
the host reaches it — which is the per-instance override, no undeclared tier needed. */
--gog-ripple-color: currentColor;
--gog-ripple-opacity: 0.16;
/* Longer than any other motion in the library, deliberately: a ripple held to the house 0.2s
is over before the eye has followed it across the surface. Still expressed in the
foundation scale, so setting the durations to 0s still flattens it theme-wide. */
--gog-ripple-enter-duration: calc(var(--gog-duration-slow) * 2);
--gog-ripple-exit-duration: var(--gog-duration-slow);
--gog-ripple-easing: var(--gog-easing);
/* ── Scroll ────────────────────────────────────────────────────────────────── */
--gog-scroll-track-bg: transparent;
--gog-scroll-track-radius: var(--gog-radius);
--gog-scroll-thumb-bg: var(--gog-accent-dim);
--gog-scroll-thumb-hover-bg: var(--gog-accent-color);
--gog-scroll-thumb-active-bg: var(--gog-accent-bright);
/* Concentric with the track: the thumb is inset on every side by `--gog-scroll-thumb-inset`,
so its corner is the track's minus that. Both radii exceed half the thumb's width at either
track size (10px and 6px, less 2x2 of inset), so this changes no rendered pixel today -- it
is here so that a theme raising `--gog-radius` on a wide scroller keeps the two curves
parallel instead of letting the thumb match the track it sits inside. */
--gog-scroll-thumb-radius: max(
0px,
calc(var(--gog-scroll-track-radius) - var(--gog-scroll-thumb-inset))
);
/* The thumb's clearance inside its own track, off the 4px grid for the same reason
`--gog-toggle-thumb-inset` is: a length inside a single painted mark defines that mark's
shape rather than spacing two things apart, and 4px on a thin scrollbar would leave a thumb
barely wider than the hairline it rides in. Listed in OPTICAL_CHROME. */
--gog-scroll-thumb-inset: 2px;
--gog-scroll-corner-bg: transparent;
--gog-scroll-fade-duration: var(--gog-duration-base);
--gog-scroll-focus-ring: var(--gog-accent-color);
--gog-scroll-focus-ring-width: var(--gog-focus-ring-width);
/* Per-size pair for the two-tier `--gog-scroll-track-width`/`-thumb-min-size` chains
that scroll.component.scss's `.gog-scroll--thin` modifier switches between. `normal`
is the unmarked default, mirroring --gog-table-lg-*. */
--gog-scroll-normal-track-width: 10px;
--gog-scroll-thin-track-width: 6px;
--gog-scroll-normal-thumb-min-size: 32px;
--gog-scroll-thin-thumb-min-size: 24px;
/* Invisible pointer-target padding around the thumb (see .gog-scroll__thumb::before) — the
`thin` variant gets more of it since its 6px track leaves the least visible thumb to aim
at; both land the effective hit width in the ~22-24px range generally recommended for a
comfortable pointer target. */
--gog-scroll-normal-thumb-hit-padding: var(--gog-space-8);
--gog-scroll-thin-thumb-hit-padding: var(--gog-space-8);
/* ── Select ────────────────────────────────────────────────────────────────── */
--gog-select-font-family: var(--gog-font-body);
--gog-select-label-font-family: var(--gog-font-heading);
--gog-select-gap: var(--gog-space-4);
--gog-select-label-color: var(--gog-accent-color);
--gog-select-label-font-size: var(--gog-text-sm);
--gog-select-label-line-height: var(--gog-field-label-line-height);
--gog-select-label-letter-spacing: var(--gog-letter-spacing);
--gog-select-label-text-transform: var(--gog-text-transform);
--gog-select-field-bg: var(--gog-surface-color);
--gog-select-field-border: var(--gog-accent-dim);
--gog-select-field-border-width: var(--gog-control-border-width);
--gog-select-field-border-style: var(--gog-control-border-style);
--gog-select-radius: var(--gog-radius);
--gog-select-field-color: var(--gog-text-color);
--gog-select-placeholder-color: var(--gog-muted-text-color);
--gog-select-focus-border: var(--gog-accent-color);
--gog-select-focus-ring: var(--gog-accent-pale);
--gog-select-focus-glow: 0 0 8px var(--gog-select-focus-ring);
--gog-select-focus-ring-width: var(--gog-focus-ring-width);
--gog-select-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-select-error-color: var(--gog-danger-color);
--gog-select-error-font-size: var(--gog-text-xs);
--gog-select-error-line-height: var(--gog-field-error-line-height);
--gog-select-chevron-color: var(--gog-accent-color);
/*
Distance from the trigger's right edge to the trailing chrome, matching the leading icon
inset on gog-inputfield so a select, a multiselect and an input line up in one form. It is
applied as the trigger's `padding-right`, and the chevron sits inside that padding — so this
is the gap itself, not the gap plus the chevron. It used to be 40px, which double-counted
and put the chevron 42px from the edge.
*/
--gog-select-chevron-inset: var(--gog-control-icon-offset);
/* Floor for an auto-width trigger, so [fullWidth]="false" cannot collapse it to the chevron. */
--gog-select-min-width: 120px;
/* Ceiling for a content-sized panel, so one very long option cannot span the viewport. */
--gog-select-panel-max-width: 420px;
/* Filter box — only rendered when `filter` is on. */
--gog-select-filter-padding: var(--gog-space-8);
--gog-select-filter-input-padding-y: var(--gog-space-8);
--gog-select-filter-input-padding-x: var(--gog-space-16);
--gog-select-filter-input-bg: var(--gog-background-color);
--gog-select-filter-input-color: var(--gog-select-field-color);
--gog-select-filter-input-border: var(--gog-select-field-border);
/* Concentric with the panel, and the concentric answer here is a square corner. The filter is
inset by `--gog-select-filter-padding`, which equals the panel's radius -- and where the inset
equals the radius, the inner box's corner point lands exactly on the centre of the outer arc,
so a right angle is equidistant from the whole curve. The same case as the multiselect's. */
--gog-select-filter-input-radius: max(
0px,
calc(var(--gog-select-panel-radius) - var(--gog-select-filter-padding))
);
--gog-select-filter-border-width: var(--gog-panel-border-width);
--gog-select-filter-border-style: var(--gog-panel-border-style);
--gog-select-filter-border-color: var(--gog-select-option-border-color, var(--gog-border-color));
--gog-select-filter-empty-padding: var(--gog-space-12);
--gog-select-filter-empty-color: var(--gog-select-placeholder-color);
/* Clear button — only rendered once a value is selected, see `clearable`. */
/* A quarter of the corner radius — see `--gog-input-clear-radius` for why. */
--gog-select-clear-radius: calc(var(--gog-radius) / 4);
--gog-select-clear-line-height: var(--gog-line-height-none);
--gog-select-clear-icon-ratio: var(--gog-control-clear-icon-ratio);
--gog-select-clear-gap: var(--gog-space-8);
--gog-select-clear-color: var(--gog-select-placeholder-color);
--gog-select-clear-hover-color: var(--gog-select-label-color);
--gog-select-control-gap: var(--gog-space-12);
--gog-select-panel-bg: var(--gog-surface-color);
--gog-select-panel-shadow: var(--gog-panel-shadow);
--gog-select-panel-max-height: 260px;
/* `--gog-select-panel-offset` until 21.13.0; the old name stopped resolving in 21.14.0. */
--gog-select-panel-gap: var(--gog-space-4);
/* The panel's own corner, and the reason it is not `--gog-select-radius`: that token shapes the
*field*, and it shaped this box too until this release. One token painting two boxes meant a
consumer rounding the field into a pill rounded the dropdown into one as well, and the filter
radius below derives from whatever it is, so that followed too. Same default, so nothing
moves; `gog-autocomplete` and `gog-datepicker` already declared this token and this is the
pair that did not. */
--gog-select-panel-radius: var(--gog-radius);
/* The list's own gutter, so the rows sit inside the panel rather than bleeding to its border.
`gog-autocomplete` and `gog-multiselect` both inset theirs by this amount; this panel had no
interior at all, which is why its first and last rows were square inside a rounded corner --
the same defect `--gog-menu-item-radius` records for the menu. */
--gog-select-options-padding: var(--gog-space-4);
--gog-select-option-hover-bg: var(--gog-hover-color);
--gog-select-option-press-bg: var(--gog-border-color);
--gog-select-option-selected-color: var(--gog-accent-color);
--gog-select-option-color: var(--gog-text-color);
/* The gap *inside* a row -- check mark to label. Not the gap between rows: the options
container declares none, and the placement estimate measures the container rather than
reading this, which it used to do on the strength of the name alone. */
--gog-select-option-gap: var(--gog-space-12);
/* Concentric with the panel, which insets its rows by the list padding above. Derived rather
than restated, so it stays true once `--gog-density` moves the padding. */
--gog-select-option-radius: max(
0px,
calc(var(--gog-select-panel-radius) - var(--gog-select-options-padding))
);
/* The row height the panel's up/down placement math starts from. **A seed, not a claim**: the
component measures a real row one frame after the panel renders and re-places if this
disagreed, so this value only governs the very first open of an instance.
It used to say "an estimate ... no effect unless the JS reads it", and the JS did read it,
for a layout decision. Measured against a rendered row it is wrong in all eleven shipped
themes -- low in ten, by up to 8.38px -- and no static value can be right, since the row is
padding plus leading plus border and a theme or `--gog-density` moves every term. Overriding
this is still worth doing if your rows are very unusual: it buys the first frame. */
--gog-select-option-height: 40px;
--gog-select-option-disabled-opacity: var(--gog-disabled-opacity);
--gog-select-option-transition-duration: var(--gog-duration-fast);
/* Icon geometry, expressed as a ratio of the control's font size. */
--gog-select-chevron-icon-ratio: 0.875;
--gog-select-mark-size-ratio: 1.125;
--gog-select-mark-icon-ratio: 0.875;
--gog-select-disabled-opacity: var(--gog-disabled-opacity);
--gog-select-transition-duration: var(--gog-duration-base);
--gog-select-float-label-reserve: var(--gog-field-float-label-reserve);
--gog-select-float-label-in-top: var(--gog-field-float-label-in-top);
--gog-select-float-label-over-gap: var(--gog-field-float-label-over-gap);
--gog-select-float-label-over-reserve: var(--gog-field-float-label-over-reserve);
/* ── Skeleton ─────────────────────────────────────────────────────────────── */
--gog-skeleton-base: var(--gog-hover-color);
--gog-skeleton-shine: var(--gog-surface-color);
--gog-skeleton-radius: var(--gog-radius);
--gog-skeleton-square-radius: 0px;
--gog-skeleton-line-radius: calc(var(--gog-skeleton-radius) / 2);
--gog-skeleton-line-gap: var(--gog-space-sm);
--gog-skeleton-short-line-width: 60%;
--gog-skeleton-pulse-duration: 1.6s;
--gog-skeleton-pulse-min-opacity: 0.5;
--gog-skeleton-wave-duration: 1.6s;
--gog-skeleton-line-height-xsm: 8px;
--gog-skeleton-line-height-sm: 10px;
--gog-skeleton-line-height-md: 14px;
--gog-skeleton-line-height-lg: 18px;
--gog-skeleton-line-height-slg: 24px;
--gog-skeleton-circle-size-xsm: 24px;
--gog-skeleton-circle-size-sm: 32px;
--gog-skeleton-circle-size-md: 48px;
--gog-skeleton-circle-size-lg: 64px;
--gog-skeleton-circle-size-slg: 96px;
--gog-skeleton-rect-height-xsm: 40px;
--gog-skeleton-rect-height-sm: 64px;
--gog-skeleton-rect-height-md: 120px;
--gog-skeleton-rect-height-lg: 200px;
--gog-skeleton-rect-height-slg: 320px;
/* ── Slider ───────────────────────────────────────────────────────────────── */
--gog-slider-auto-width: 240px;
/* Length (height) of a vertical slider's track — the counterpart to
--gog-slider-auto-width, which only sizes the horizontal case. */
--gog-slider-vertical-length: 160px;
--gog-slider-label-font-family: var(--gog-font-heading);
--gog-slider-value-font-family: var(--gog-font-mono);
--gog-slider-error-font-family: var(--gog-font-body);
--gog-slider-gap: var(--gog-space-8);
--gog-slider-label-color: var(--gog-accent-color);
--gog-slider-label-font-size: var(--gog-text-sm);
--gog-slider-label-line-height: var(--gog-field-label-line-height);
--gog-slider-label-letter-spacing: var(--gog-letter-spacing);
--gog-slider-label-text-transform: var(--gog-text-transform);
--gog-slider-value-color: var(--gog-accent-color);
--gog-slider-value-font-size: var(--gog-text-sm);
--gog-slider-value-line-height: var(--gog-line-height-none);
--gog-slider-value-min-width: 40px;
--gog-slider-track-height: 4px;
--gog-slider-track-area-height: 20px;
--gog-slider-track-radius: 0px;
/*
* Deliberately NOT an accent-* token: --gog-accent-dim sits on the same hue ramp as
* --gog-slider-fill-bg (--gog-accent-color), so at a 4px track height the two used to
* read as one blob rather than "recessed groove + accent fill" — same problem in both
* themes, since the whole accent ramp is one hue. Mixing --gog-text-color into
* --gog-border-color instead gives a desaturated, theme-adaptive groove: it darkens
* toward black in the light theme (text-color is near-black there) and lightens toward
* parchment in the dark theme (text-color is near-white there), landing at a neutral
* warm gray in both — always visibly distinct from the saturated accent fill, and always
* legible against its own theme's surface.
*/
--gog-slider-track-bg: var(--gog-border-color);
--gog-slider-track-border-width: var(--gog-border-width);
--gog-slider-track-border-style: var(--gog-border-style);
/* Transparent by default — same opt-in convention as --gog-button-primary-border: the
width/style are always in the box model, but invisible until a theme sets a color. */
--gog-slider-track-border-color: transparent;
/* Bound via `background` (not `background-color`) in slider.component.scss, so this
also accepts a gradient (e.g. `linear-gradient(...)`) for the fill style, not just a
solid color. */
--gog-slider-fill-bg: var(--gog-accent-color);
--gog-slider-thumb-size: 16px;
--gog-slider-thumb-bg: var(--gog-accent-color);
--gog-slider-thumb-border: var(--gog-background-color);
--gog-slider-thumb-border-width: var(--gog-control-border-width);
--gog-slider-thumb-radius: 50%;
/* A colour, not a shadow: the thumb's glow ring composes it as
`0 0 var(--gog-slider-thumb-glow-size) <this>`. It was `--gog-slider-thumb-shadow` until
21.13.0, the only token of the 31 the elevation audit classified whose name was simply
wrong; the old name stopped resolving in 21.14.0. */
--gog-slider-thumb-glow-color: var(--gog-accent-pale);
--gog-slider-thumb-glow-size: 6px;
--gog-slider-focus-ring: var(--gog-accent-pale);
--gog-slider-focus-ring-width: var(--gog-focus-ring-width);
--gog-slider-range-color: var(--gog-muted-text-color);
--gog-slider-range-font-size: var(--gog-text-xs);
--gog-slider-range-line-height: var(--gog-line-height-none);
--gog-slider-error-color: var(--gog-danger-color);
--gog-slider-error-font-size: var(--gog-text-xs);
--gog-slider-error-line-height: var(--gog-field-error-line-height);
--gog-slider-disabled-opacity: var(--gog-disabled-opacity);
/* ── Spinner ──────────────────────────────────────────────────────────────── */
--gog-spinner-rune-font-family: var(--gog-font-heading);
--gog-spinner-track-color: var(--gog-accent-dim);
--gog-spinner-arc-outer-color: var(--gog-accent-color);
--gog-spinner-arc-inner-color: var(--gog-accent-bright);
--gog-spinner-diamond-color: var(--gog-accent-bright);
--gog-spinner-rune-color: var(--gog-accent-bright);
--gog-spinner-glow-color: var(--gog-accent-color);
--gog-spinner-track-opacity: 0.35;
--gog-spinner-arc-inner-opacity: 0.75;
--gog-spinner-diamond-opacity: 0.85;
--gog-spinner-arc-outer-pulse-opacity: 0.8;
--gog-spinner-arc-inner-pulse-opacity: 0.45;
--gog-spinner-rune-pulse-opacity: 0.4;
--gog-spinner-arc-outer-dash: 100 63;
--gog-spinner-arc-inner-dash: 35 78;
--gog-spinner-arc-inner-stroke-compact: 1;
--gog-spinner-spin-duration: 1.4s;
--gog-spinner-spin-slow-duration: 2s;
--gog-spinner-ticks-duration: 6s;
--gog-spinner-pulse-duration: 2.8s;
--gog-spinner-ring-duration: 1s;
--gog-spinner-ring-padding: 16%;
--gog-spinner-arc-outer-glow: 5px;
--gog-spinner-arc-inner-glow: 4px;
--gog-spinner-diamond-glow: 3px;
--gog-spinner-rune-glow: 6px;
--gog-spinner-ring-glow: 5px;
--gog-spinner-overlay-blur: 3px;
--gog-spinner-overlay-fade-duration: var(--gog-duration-slow);
/* ── Table ────────────────────────────────────────────────────────────────── */
--gog-table-font-family: var(--gog-font-body);
--gog-table-header-font-family: var(--gog-font-heading);
--gog-table-numeric-font-family: var(--gog-font-mono);
--gog-table-gap: var(--gog-space-12);
--gog-table-border-color: var(--gog-accent-dim);
--gog-table-border-width: var(--gog-control-border-width);
--gog-table-border-style: var(--gog-border-style);
--gog-table-row-border-width: var(--gog-border-width);
/* The selection column is sized to its checkbox and never grows with content. */
--gog-table-select-col-width: 44px;
--gog-table-surface: var(--gog-surface-color);
/* The header needs its own ground, not the table's. It used to paint `--gog-table-surface`,
which is the same colour the body paints, so on a scrolling table with a sticky header the
column names slid over rows of identical background and the only thing separating them was
the accent colour and the caps — legible on a light theme, not on a dark one. */
--gog-table-header-bg: var(--gog-hover-color);
--gog-table-text-color: var(--gog-text-color);
--gog-table-accent-color: var(--gog-accent-color);
--gog-table-accent-bright: var(--gog-accent-bright);
--gog-table-hover-bg: var(--gog-accent-pale);
/* Only an `interactiveRows` row presses; a plain row is not a control and takes no state
beyond hover. Same value the three option lists use, for the same reason. */
--gog-table-row-press-bg: var(--gog-border-color);
/* Selected rows keep this tint through hover, so hovering one never reads as clearing it. */
--gog-table-selected-bg: var(--gog-accent-pale);
--gog-table-muted-color: var(--gog-muted-text-color);
--gog-table-focus-ring: var(--gog-accent-color);
--gog-table-focus-ring-width: var(--gog-focus-ring-width);
--gog-table-header-letter-spacing: var(--gog-letter-spacing);
--gog-table-header-text-transform: var(--gog-text-transform);
--gog-table-num-col-width: 48px;
--gog-table-th-inner-gap: var(--gog-space-8);
--gog-table-sort-icon-size: 0.9em;
--gog-table-sort-icon-width: 1.1em;
--gog-table-sort-icon-opacity: 0.6;
--gog-table-empty-padding: var(--gog-space-24) var(--gog-space-16);
--gog-table-empty-font-size: var(--gog-text-md);
--gog-table-empty-line-height: var(--gog-line-height-normal);
--gog-table-loading-padding: var(--gog-space-32) var(--gog-space-16);
--gog-table-loading-opacity: 0.5;
--gog-table-row-transition-duration: var(--gog-duration-fast);
--gog-table-footer-gap: var(--gog-space-sm);
--gog-table-footer-min-height: 32px;
--gog-table-total-font-size: var(--gog-text-xs);
--gog-table-total-line-height: var(--gog-line-height-normal);
--gog-table-total-letter-spacing: 0.5px;
--gog-table-total-text-transform: var(--gog-text-transform);
--gog-table-num-font-size: var(--gog-text-xs);
--gog-table-num-line-height: var(--gog-line-height-normal);
--gog-table-padding-h: var(--gog-space-16);
--gog-table-xsm-padding-v: var(--gog-space-4);
--gog-table-xsm-th-font-size: var(--gog-text-xs);
--gog-table-xsm-td-font-size: var(--gog-text-xs);
--gog-table-sm-padding-v: var(--gog-space-4);
--gog-table-sm-th-font-size: var(--gog-text-xs);
--gog-table-sm-td-font-size: var(--gog-text-xs);
--gog-table-md-padding-v: var(--gog-space-8);
--gog-table-md-th-font-size: var(--gog-text-xs);
--gog-table-md-td-font-size: var(--gog-text-sm);
--gog-table-lg-padding-v: var(--gog-space-12);
--gog-table-lg-th-font-size: var(--gog-text-sm);
--gog-table-lg-td-font-size: var(--gog-text-md);
--gog-table-slg-padding-v: var(--gog-space-16);
--gog-table-slg-th-font-size: var(--gog-text-md);
--gog-table-slg-td-font-size: var(--gog-text-lg);
/* One value for every size step: the role picks the leading and the size does not (D4). */
--gog-table-td-line-height: var(--gog-line-height-normal);
--gog-table-th-line-height: var(--gog-line-height-normal);
/* ── Tabs ──────────────────────────────────────────────────────────────────
`--gog-tabs-tab-bg`, `-tab-color`, `-tab-padding` and `-tab-font-size` are intentionally
NOT declared — they are the per-instance escape hatch the size classes fall back through.
`--gog-tabs-indicator-offset` / `-length` are written as inline styles from the measured
header geometry, so they are not declared either. */
--gog-tabs-font-family: var(--gog-font-heading);
--gog-tabs-font-weight: var(--gog-font-weight-bold);
--gog-tabs-letter-spacing: 0.4px;
--gog-tabs-text-transform: none;
--gog-tabs-line-height: var(--gog-line-height-tight);
--gog-tabs-gap: 0px;
--gog-tabs-tab-gap: var(--gog-space-sm);
--gog-tabs-icon-size: 1.1em;
--gog-tabs-rest-bg: transparent;
--gog-tabs-rest-color: var(--gog-muted-text-color);
--gog-tabs-hover-color: var(--gog-text-color);
/* Tabs paint no background at rest and none on hover — the press is the only one they get,
which is why this token has no hover counterpart to step past. */
--gog-tabs-press-bg: var(--gog-border-color);
/* A resting tab's label is deliberately muted, and muted text has no contrast headroom to
spend on a tinted ground: on the press wash it fell to 3.24:1 in one-dark and under 4.5 in
six other themes. The press takes the full text colour instead — which is also what pressing
a tab is about to make it. */
--gog-tabs-press-color: var(--gog-text-color);
--gog-tabs-active-color: var(--gog-accent-color);
--gog-tabs-header-border-width: var(--gog-border-width);
--gog-tabs-header-border-style: var(--gog-border-style);
--gog-tabs-header-border-color: var(--gog-border-color);
--gog-tabs-indicator-color: var(--gog-accent-color);
--gog-tabs-indicator-thickness: 2px;
--gog-tabs-indicator-radius: 999px;
--gog-tabs-transition-duration: var(--gog-duration-base);
--gog-tabs-disabled-opacity: var(--gog-disabled-opacity);
--gog-tabs-focus-ring-width: var(--gog-focus-ring-width);
/* Inset, for the same reason as the calendar cell: tabs sit shoulder to shoulder. */
--gog-tabs-focus-ring-offset: calc(var(--gog-focus-ring-offset) * -1);
--gog-tabs-focus-ring-color: var(--gog-accent-color);
--gog-tabs-panel-padding: var(--gog-space-md);
--gog-tabs-panel-color: var(--gog-text-color);
--gog-tabs-xsm-padding: var(--gog-space-8) var(--gog-space-16);
--gog-tabs-xsm-font-size: var(--gog-text-xs);
--gog-tabs-sm-padding: var(--gog-space-8) var(--gog-space-16);
--gog-tabs-sm-font-size: var(--gog-text-sm);
--gog-tabs-md-padding: var(--gog-space-12) var(--gog-space-24);
--gog-tabs-md-font-size: var(--gog-text-md);
--gog-tabs-lg-padding: var(--gog-space-16) var(--gog-space-32);
--gog-tabs-lg-font-size: var(--gog-text-lg);
--gog-tabs-slg-padding: var(--gog-space-20) var(--gog-space-40);
--gog-tabs-slg-font-size: var(--gog-text-xl);
/* ── Tag ──────────────────────────────────────────────────────────────────
Like the button, the unsuffixed `--gog-tag-bg`/`-border`/`-color`/`-font-size`
and friends stay undeclared so variant and size classes can fall through them. */
--gog-tag-font-family: inherit;
--gog-tag-default-color: var(--gog-info-color, var(--gog-muted-text-color));
--gog-tag-success-color: var(--gog-success-color);
--gog-tag-danger-color: var(--gog-danger-color);
--gog-tag-warning-color: var(--gog-warning-color);
--gog-tag-info-color: var(--gog-info-color);
--gog-tag-bg-mix: 10%;
/* The label is the status hue mixed **halfway toward the page's ink**, and both halves of that
changed in 21.10.0. It was 82% of the hue mixed toward literal `black`, which is a light-theme
assumption twice over: on a dark theme it darkened a label that already sat on a dark ground
(one-dark's danger tag read 3.11:1), and on a light one 18% of black is not enough to bring a
bright hue down to text contrast (material's warning, 2.49:1; primeng's success, 3.06:1).
Eleven of the 55 shipped combinations were under WCAG AA and nothing had ever measured them —
a tag's colours reach the DOM through `--gog-tag-variant-color`, which `check:contrast` could
not follow until the same release taught it to.
`--gog-text-color` rather than `black` makes the mix follow the theme, and 50% rather than 82%
is the same ratio, and the same argument, as `--gog-button-<status>-ink`: as body text the raw
status hue clears AA in only a handful of themes. The worst pair is now 4.67:1. */
--gog-tag-color-mix: 50%;
--gog-tag-bg-base: var(--gog-surface-color);
--gog-tag-color-base: var(--gog-text-color);
--gog-tag-border-width: var(--gog-border-width);
--gog-tag-border-style: var(--gog-border-style);
--gog-tag-inner-border-width: var(--gog-border-width);
--gog-tag-font-weight: var(--gog-font-weight-semibold);
--gog-tag-line-height: var(--gog-line-height-none);
--gog-tag-radius: max(var(--gog-radius), 2px);
--gog-tag-pill-radius: 9999px;
--gog-tag-xsm-font-size: var(--gog-text-2xs);
--gog-tag-xsm-padding-block: var(--gog-space-4);
--gog-tag-xsm-padding-inline: var(--gog-space-8);
--gog-tag-xsm-gap: var(--gog-space-4);
--gog-tag-xsm-icon-size: 0.6875rem;
--gog-tag-sm-font-size: var(--gog-text-xs);
--gog-tag-sm-padding-block: var(--gog-space-4);
--gog-tag-sm-padding-inline: var(--gog-space-8);
--gog-tag-sm-gap: var(--gog-space-4);
--gog-tag-sm-icon-size: 0.75rem;
--gog-tag-md-font-size: var(--gog-text-sm);
--gog-tag-md-padding-block: var(--gog-space-8);
--gog-tag-md-padding-inline: var(--gog-space-16);
--gog-tag-md-gap: var(--gog-space-8);
--gog-tag-md-icon-size: 0.875rem;
--gog-tag-lg-font-size: var(--gog-text-md);
--gog-tag-lg-padding-block: var(--gog-space-8);
--gog-tag-lg-padding-inline: var(--gog-space-16);
--gog-tag-lg-gap: var(--gog-space-8);
--gog-tag-lg-icon-size: 1rem;
--gog-tag-slg-font-size: var(--gog-text-lg);
--gog-tag-slg-padding-block: var(--gog-space-12);
--gog-tag-slg-padding-inline: var(--gog-space-24);
--gog-tag-slg-gap: var(--gog-space-12);
--gog-tag-slg-icon-size: 1.125rem;
/* ── Toast ────────────────────────────────────────────────────────────────── */
--gog-toast-font-family: var(--gog-font-body);
--gog-toast-bg: var(--gog-surface-color);
--gog-toast-color: var(--gog-text-color);
--gog-toast-border: var(--gog-accent-color);
--gog-toast-icon-color: var(--gog-accent-color);
/* Each type reads its own role. Two of the four did not until 21.13.0: `warning` read
`--gog-accent-bright` and `info` read `--gog-accent-color`, which is also what a *typeless*
toast paints -- so an info toast was pixel-identical to a plain one, and a warning toast was
the same hue a shade brighter. This colour is the whole signal: it paints the leading stripe,
the icon and the countdown bar (see toast.component.scss's `--toast-border`). Three of the
five states were the accent. */
--gog-toast-success-color: var(--gog-success-color);
--gog-toast-error-color: var(--gog-danger-color);
--gog-toast-warning-color: var(--gog-warning-color);
--gog-toast-info-color: var(--gog-info-color);
--gog-toast-accent-width: 4px;
--gog-toast-padding: var(--gog-space-12) var(--gog-space-16);
--gog-toast-radius: 0px;
--gog-toast-content-gap: var(--gog-space-12);
--gog-toast-main-gap: var(--gog-space-sm);
--gog-toast-actions-gap: var(--gog-space-8);
--gog-toast-message-font-size: var(--gog-text-sm);
--gog-toast-message-line-height: var(--gog-line-height-relaxed);
--gog-toast-icon-size: 1rem;
--gog-toast-icon-line-height: var(--gog-line-height-normal);
--gog-toast-action-padding: var(--gog-space-4) var(--gog-space-8);
--gog-toast-action-font-size: var(--gog-text-xs);
--gog-toast-action-line-height: var(--gog-line-height-none);
--gog-toast-close-padding: var(--gog-space-4) var(--gog-space-8);
--gog-toast-close-font-size: var(--gog-text-xs);
--gog-toast-close-line-height: var(--gog-line-height-none);
--gog-toast-progress-height: 3px;
--gog-toast-progress-opacity: 30%;
--gog-toast-transition-duration: 0.25s;
/* Card-stack geometry */
--gog-toast-stack-peek: 14px;
--gog-toast-stack-scale-step: 0.06;
--gog-toast-stack-expanded-gap: 84px;
--gog-toast-stack-min-opacity: 0.4;
--gog-toast-stack-opacity-step: 0.18;
--gog-toast-stack-max-depth: 6;
/* ── Toggle ───────────────────────────────────────────────────────────────────
A switch, not a checkbox: it announces as "switch, on". The outer label size reuses
the `--gog-control-checkbox-*` scale so a toggle and a checkbox in the same form read
at the same weight; the track/thumb geometry is its own, since a switch is wider than
it is tall. */
--gog-toggle-font-family: var(--gog-font-body);
--gog-toggle-gap: var(--gog-space-sm);
--gog-toggle-radius: 999px;
--gog-toggle-border-width: var(--gog-border-width);
--gog-toggle-border-style: var(--gog-border-style);
--gog-toggle-border-color: var(--gog-control-boundary-color);
--gog-toggle-on-border-color: var(--gog-accent-color);
--gog-toggle-track-off-bg: var(--gog-border-color);
--gog-toggle-track-on-bg: var(--gog-accent-color);
--gog-toggle-thumb-off-bg: var(--gog-surface-color);
--gog-toggle-thumb-on-bg: var(--gog-accent-text-color, var(--gog-primary-color));
/* The thumb's clearance inside its own track, and off the 4px grid on purpose: at 2px the
thumb is 83% of a 24px track, which is what makes a switch read as a switch, and 4px would
take it to 67%. A length inside a single painted mark is not spacing between two things —
`check-geometry.mjs` lists it in OPTICAL_CHROME with that reason. */
--gog-toggle-thumb-inset: 2px;
--gog-toggle-transition-duration: var(--gog-duration-base);
--gog-toggle-disabled-opacity: var(--gog-disabled-opacity);
--gog-toggle-label-color: var(--gog-text-color);
--gog-toggle-label-line-height: var(--gog-line-height-normal);
--gog-toggle-focus-ring-width: var(--gog-focus-ring-width);
--gog-toggle-focus-ring-offset: var(--gog-focus-ring-offset);
--gog-toggle-focus-ring-color: var(--gog-accent-color);
/* In-track on/off wording */
--gog-toggle-state-color: var(--gog-accent-text-color, var(--gog-primary-color));
--gog-toggle-state-font-weight: var(--gog-font-weight-semibold);
--gog-toggle-state-letter-spacing: 0.04em;
--gog-toggle-state-padding-inline: var(--gog-space-4);
--gog-toggle-state-offset: var(--gog-space-8);
/* Gap between the wording and the thumb parked at the opposite end. The clearance itself
(thumb size + this) is computed in the component stylesheet, not here: a `var(` to a
size-class token is substituted where it is *declared*, so doing that calc on :root would
freeze it to the md thumb and stop it scaling with `size`. */
--gog-toggle-state-thumb-gap: var(--gog-space-8);
--gog-toggle-xsm-track-width: 24px;
--gog-toggle-xsm-track-height: 14px;
--gog-toggle-xsm-thumb-size: 10px;
--gog-toggle-xsm-label-size: var(--gog-control-checkbox-label-size-xsm);
--gog-toggle-xsm-state-font-size: 0.5rem;
--gog-toggle-sm-track-width: 32px;
--gog-toggle-sm-track-height: 18px;
--gog-toggle-sm-thumb-size: 14px;
--gog-toggle-sm-label-size: var(--gog-control-checkbox-label-size-sm);
--gog-toggle-sm-state-font-size: 0.5625rem;
--gog-toggle-md-track-width: 44px;
--gog-toggle-md-track-height: 24px;
--gog-toggle-md-thumb-size: 18px;
--gog-toggle-md-label-size: var(--gog-control-checkbox-label-size-md);
--gog-toggle-md-state-font-size: 0.625rem;
--gog-toggle-lg-track-width: 56px;
--gog-toggle-lg-track-height: 32px;
--gog-toggle-lg-thumb-size: 26px;
--gog-toggle-lg-label-size: var(--gog-control-checkbox-label-size-lg);
--gog-toggle-lg-state-font-size: var(--gog-text-xs);
--gog-toggle-slg-track-width: 68px;
--gog-toggle-slg-track-height: 40px;
--gog-toggle-slg-thumb-size: 34px;
--gog-toggle-slg-label-size: var(--gog-control-checkbox-label-size-slg);
--gog-toggle-slg-state-font-size: 0.8125rem;
--gog-toggle-state-line-height: var(--gog-line-height-none);
/* ── Tooltip ──────────────────────────────────────────────────────────────── */
--gog-tooltip-font-family: var(--gog-font-body);
--gog-tooltip-font-size: var(--gog-text-xs);
--gog-tooltip-line-height: var(--gog-line-height-normal);
--gog-tooltip-padding: var(--gog-space-8) var(--gog-space-12);
--gog-tooltip-radius: var(--gog-radius);
/* L9 (docs/component-geometry.md, "D7 — taken"): the bubble wraps, so its cap is a measure —
43ch at --gog-tooltip-font-size (12px), the nearest whole character to today's 280px so this
changes robustness to a font-size change, not the pixels anyone sees today. It sits under
Bringhurst's 45ch floor even so; widening it is a pixel decision this law does not make (see
"D7 — taken"). L8's viewport exception is layered on top: no edge-inset token exists on this
component today, so the margin reads the scale directly. */
--gog-tooltip-max-width: min(43ch, calc(100vw - var(--gog-space-16) * 2));
/* Caps the gog-scroll wrapping the bubble's content — see tooltip-bubble.component.html.
A cap, not a fixed height: shorter content stays exactly as tall as it needs to be, this
only stops something unusually long (a multi-paragraph TemplateRef) from growing to
cover most of the viewport. */
--gog-tooltip-max-height: 220px;
/* Same "floating panel" recipe as gog-dialog's panel and gog-select's dropdown — a
surface-colored box with a plain (not accent) border and the shared panel shadow —
rather than an inverted dark/light bubble, so it reads as part of this site instead of
a generic dark tooltip dropped on top of it. */
--gog-tooltip-bg: var(--gog-surface-color);
--gog-tooltip-color: var(--gog-text-color);
--gog-tooltip-border-width: var(--gog-panel-border-width);
--gog-tooltip-border-style: var(--gog-panel-border-style);
--gog-tooltip-border-color: var(--gog-border-color);
--gog-tooltip-shadow: var(--gog-panel-shadow);
--gog-tooltip-arrow-size: 5px;
/* Space kept between the trigger and the bubble. Read by the directive itself (not just
CSS) to feed the placement math — see `readPxToken` in `tooltip.directive.ts`. */
--gog-tooltip-gap: var(--gog-space-8);
--gog-tooltip-transition-duration: var(--gog-duration-fast);
}
/* theme-starter:derived-end */