Color combinations

The deep-accent palette and the named (background, foreground) tuples that drive every themed component.

Palette

Defined in src/variables/_color.scss as $palette. Five deep accents (sage, moss, emerald, amber, coral) plus white / black. The functional accents (sage, moss, amber, coral) clear WCAG 2.2 AAA body text against white (≥ 7:1) and WCAG 1.4.11 (≥ 3:1) against the white page. emerald is the brand green from the Krysalicss logo and pairs with white text at ~4.1:1 (AA non-text only); using it for primary trades AAA body for brand fidelity. The semantic-state combinations (success, warning, danger) all stay on AAA-tuned accents.

sage
#1a6347
moss
#525a22
emerald
#2a8d69
amber
#7a4f10
coral
#8c351a
white
#ffffff
black
#27282b

Combinations

Defined as $combinations in the same file. Each tuple is (background, foreground). The first entry: default: is treated specially as the value applied to components without a .is-* modifier.

LabelBackgroundForegroundDrives
default white (#ffffff) black (#27282b) --kc-default-bg, --kc-default-fg
primary emerald (#2a8d69) white (#ffffff) --kc-primary-bg, --kc-primary-fg
warning amber (#7a4f10) white (#ffffff) --kc-warning-bg, --kc-warning-fg
danger coral (#8c351a) white (#ffffff) --kc-danger-bg, --kc-danger-fg
success moss (#525a22) white (#ffffff) --kc-success-bg, --kc-success-fg

Override

Replace the whole map at the framework entry. Component plugins iterate $combinations at compile time, so adding or renaming entries propagates to every themed component automatically.

app.scss
@use '@adnap/krysalicss' with (
  $color-combinations: (
    default: (#ffffff, #1a1a1a),
    primary: (#5b21b6, #ffffff),
    warning: (#f59e0b, #1a1a1a),
    danger:  (#dc2626, #ffffff),
    success: (#16a34a, #ffffff),
  ),
);
Adding combinations. Add a new tuple: for example info: (#0ea5e9, #ffffff): and .button.is-info and .card.is-info compile out automatically. The combination's tokens become --kc-info-bg / --kc-info-fg; themes must define them or the framework's hardcoded fallback applies.
Don't rely on colour alone. The combination classes communicate state through colour (.is-danger, .is-warning, .is-success). WCAG 1.4.1 (Use of Colour) requires a second cue so users with colour-vision differences, monochrome displays, or forced-colours mode get the same information. Pair state-coloured components with at least one of:
  • a leading icon (<svg aria-hidden="true">…</svg> plus a visible label);
  • a textual prefix: "Error: …", "Warning: …", "Success: …": that works without the colour;
  • for live state changes, an aria-live="polite" (or "assertive" for blocking errors) region announcing the new state.
The framework ships no built-in icons or auto-prefixed state text on the combination classes themselves; component scope is "themed surface", not "alert pattern". Use the helper/state hook below or bring your own.
Trade-off: --kc-danger-bg on dark card surfaces. The danger-tinted invalid border (#a2481a in the dark theme) clears WCAG 1.4.11 (3:1) against the page background but sits at ~2.74:1 against the dark --kc-card-bg (#1b1e22). The framework accepts this gap because the invalid state is never conveyed by colour alone: the helper/state hook prepends a "✕ " glyph to the field's label whenever the control matches :user-invalid or carries aria-invalid="true", so 1.4.1 (Use of Colour) is satisfied regardless. Tightening --kc-danger-bg to clear 3:1 on every conceivable surface would unwind the a11y palette work that locked button / alert / badge .is-danger text contrast at AA. If your design uses --kc-danger-bg as the sole cue on a card-tinted surface, override the token at consumer level.
State-icon hook: helper/state. The opt-in helper/state module emits a [data-state]::before rule for the three colour-coded states: "✓ " for success, "⚠ " for warning, "✕ " for danger. The neutral combinations (default, primary) carry no inherent state semantic so no rule is emitted for them: pure bytes saved. Use the hook on any element by adding a matching data-state:
<span data-state="success">Saved</span>
Each rule's content reads from --kc-state-icon-{label} with the default glyph as the var() fallback: set the custom property at any scope (theme, root, component) to override; set it to "" to drop the icon. Add a glyph for a neutral combination by overriding the helper's $icons map at consumer level. Disable the helper output entirely via $feature-list if you don't use it.

Where they're consumed

  • Button: every variant emits one rule per combination.
  • Card: same iteration applied to .card.is-{label}.