KCDS foundations · Source archive

Versions & changelog

Current foundations release: v1.18.0 · 2 October 2026. Release entries come from the supplied foundations archive. Website updates are recorded separately.

Portal · 1 October 2026

Added News, release history, design decisions, and full-content search. Improved loading, theme contrast, and mobile navigation. These website changes do not represent a new foundations release.

[1.18.0] — 2026-10-02


Minor (ADR 037 records why not MAJOR — no token renamed, no selector changed, tokens.json
untouched). DRI decision of 2 October 2026 on organization branding, taken against the shipped
User Directory → Branding page.

Changed — rules

- Organization branding is one platform setting and reaches every product (ADR 037).
Configured once in User Directory → Branding (name, logo, favicon, brand colour, font,
languages, time zone, date format); once configured it applies in all KC products — legacy,
KC Native in every suite, internal/admin — and every email. The per-product entitlement rule
of ADR 016 ("the brief decides; silence is mode 1") is superseded; de-branding (mode 3) is the
only product-level question left.
- The tenant colour replaces the whole suite chain, not the primary-action set. Every token the
category selector sets — primary + hover/active/fill/tint, on-primary, on-primary-tint,
text-accent, text-link, border-focus — resolves to the tenant chain; no suite colour stays
visible on a branded surface, the Pattern B sub-name and the email source-product label
included. data-kcds-product-category stays set as the fallback and audit hook. The internal
orange is displaced the same way. Widens ADR 029.
- Tenant logo in every logo slot (headers, brand block + drawer, sign-in, product switcher,
email header card); tenant favicon in every product; organization name replaces the
"KnowledgeCity" line of the brand block and is the email sender name; tenant font replaces
Lato as the Latin face in weights 400/700 only.

Changed — files

- 02-cross-cutting/tenant-theming.md rewritten around the setting: the settings inventory as
shipped, the modes as a consequence of configuration, "What the brand colour repaints", slots,
typography, contrast validation now covering derived text-link. The per-product status
snapshot and the PD-53 depth tiers are removed (retired, not stale — see ADR 037).
- 01-foundations/colors.md → Tier 3: "What changes per tenant" is the full chain; derivation
gains tenant-text-link and tenant-on-primary-tint; resolved note updated.
- 10-email/email.md → "Branded organizations — the tenant colour takes the category row".
- 01-foundations/product-accents.md → "Tenant theming — resolved"; 06-components/page-shell.md
→ Element 1 scope and the Pattern B brand-block text; 00-zero-rules/one-system-one-language.md,
00-zero-rules/quick-lookup.md (rule 4, lookup table), SKILL.md (hard rule 1, §3, product
styles) synced; 04-product-context/products/kc-comply.md tenant-theming line corrected.

Known, not changed

- Dark mode for tenant colours stays open (the Branding page preview is light only).
- GC-38 (--kcds-tenant-* family absent) keeps its Medium tier; re-tiering is a quality-release
decision.
- kc-ds-mobile adopts ADR 037 in its own release.
- Custom domain, login-page background/welcome message, colour-mode default and email-from are
no longer listed as tenant settings — they are not on the Branding page; product- or
infrastructure-level until User Directory carries them.
- The Branding page copy "newer apps keep their own built-in color" contradicts the decision —
product copy, recorded in ADR 037 for the product owner.

[1.17.0] — 2026-09-30

Minor (ADR 036 records why not MAJOR). Ticket PD-464. Nine text-role values change, one token
is added, and the contrast check becomes a blocking gate. Every text role now clears 4.5:1 on every
plane its theme declares, not only on white.

Changed — token values (tokens.json, tokens.css, colors.md, canonicals)

  • Light text-secondary #737373 → #696969 (was 4.40:1 on surface-canvas, 4.10:1 on hover).
  • Light status-success green-700 #00A01A → #007C14; status-error red-500 #F03E3E → #D11010; status-warning orange-500 #FF881A → #A95100; status-neutral gray-600 #74838A → #5F6B71. All four failed on white (3.47 / 3.84 / 2.39 / 3.92:1). -fill, -bg, -border and -on-tint are unchanged; solid fills keep the bright hue.
  • Light text-link Learn #D63F13 → #C33911, Grow #0A8558 → #09774F, Hire #6A5DF8 → #5D4EF7. Comply stays blue-500. primary and the ramps are unchanged.
  • Legacy :root text-link orange-500 (2.39:1) → orange-700, matching internal (ADR 033).
  • Dark text-tertiary #74808A → #8A949D — closes the dark half of F-075.

Added

  • --kcds-color-text-accent — accent-hued text that is not a link, in every category and theme.
  • build-tokens.py --check contrast gate: every text role × every plane × theme × category, resolved from tokens.css; blocks under 4.5:1 outside one named exception (orange-700 as text in the orange chain, ADR 012 / ADR 033). Run against v1.16.0 it reports 342 blocking pairs.
  • L-24 (mechanical-lint.md v1.4): no color: var(--kcds-color-primary | accent-N).
  • F-103 in the failure catalogue; F-075 marked closed.
  • colors.md → "Text roles clear AA on every plane" (plane set, method, table, exception, and why surface-canvas = surface-subtle in light is intentional).

Fixed — canonical references (A-02 drift)

  • 19 of 20 canonicals inlined the pre-ADR 018 light text tiers (gray-500 #9A9A9A 2.81:1, gray-600 #74838A); re-synced to tokens.css together with the ADR 036 values.
  • 14 canonicals had no dark text-link, so dark links inherited the light orange; several dark :root blocks lacked the dark status -bg, status-info/success/warning or ai-suggestion values and rendered the light ones in dark; authoring-shell.html rendered a light tint and #9A2D0E on-tint text in dark. All added.
  • 97 declarations in 17 canonicals painted text or icons with --kcds-color-primary (.sidenav__brandsub, active tabs, breadcrumb hovers, section icons…). Repointed by role: 44 → text-accent, 38 → on-primary-tint (element on primary-tint / -fill), 15 → text-link. The same pattern is fixed in the specs in page-shell.md, actions.md, data-display.md, rating.md, page-archetypes.md, responsive.md, text-overflow.md and colors.md.

Documentation

  • colors.md: the ADR 034 claim that the base status token "is correct on the canvas" and the August claim that dark "was already compliant" are corrected in place with dated notes; a stale "text-secondary is for large text only" line is struck.
  • product-accents.md → v0.17; quick-lookup.md, typography.md, iconography.md, navigation.md, feedback.md, 06-components/README.md, audit-and-refactor-protocol.md synced. SKILL.md hard rule 2 gains the accent-text clause.

Known, not changed

  • Orange-700 as text in legacy / internal stays the ADR 012 exception (4.15 / 3.58 / 3.42:1) — a brand decision.
  • Light text-secondary is lighter than text-tertiary (inverted since ADR 018) — a ramp decision.
  • product-accents.md → "Text on accent tints" (text-primary on tints) and the on-primary-tint pattern overlap; to be reconciled separately.
  • K2 still ships retired thrive / perform / platform category aliases in kcds.css (library side).
[1.16.0] — 2026-09-23

Minor. One token value changes: dark --kcds-color-status-info-bg is re-derived from the
current blue-500. Everything else is the v1.15.2 patch content, shipped together.

Changed

  • Dark status-info-bg: rgba(50, 157, 255, 0.15) → rgba(21, 103, 210, 0.15). The old value was a 15% wash of the pre-v1.13.0 blue #329DFF; every other dark status -bg is its family's *current* base at 15%, and light status-info moved to #1567D2 in ADR 032. The dark --kcds-blue-50 alias carried the same stale wash and moves with it. Dark info text #60A5FA is unchanged and measures 5.87:1 on the new wash (was 5.32:1). Updated in tokens.json, tokens.css, colors.md and the 14 canonicals that inline the dark status block. ADR 032 is amended with the reasoning and with why this ships as MINOR rather than MAJOR.
  • 06-components/inputs.md F-079 note dates its #329DFF example as the pre-v1.13.0 Grow blue rather than presenting it as a current value.
[1.15.2] — 2026-09-23

Patch. No token value changes and no rule changes. A colour audit of the whole bundle — every
hex in prose against tokens.json, every stated contrast ratio recomputed, every canonical's
inlined chains against tokens.css — found the suite accents clean and eight documentation
defects, all older than v1.15.0. All eight are fixed here. build-tokens.py --check prose warnings
go from 11 to 1 (the kcds-tenant-* empty family, which is a design decision, not a drift).

Fixed

  • colors.md → "Color — Text" showed the pre-v1.6.0 tiers. text-secondary as gray-500 #9A9A9A (2.81:1) and text-tertiary as gray-600 #74838A (3.92:1) — the exact values ADR 018 replaced with #737373 (4.74:1) and #5E6970 (5.63:1), and which the same file's recalibration table already recorded as fixed. The block now shows the shipped literals.
  • F-075 and its citations asserted the wrong measurement. navigation.md, the F-075 entry and audit-and-refactor-protocol.md step 6 all said text-tertiary #5E6970 is 3.9:1 and that small-text AA is "an open token issue" — 3.9:1 was the old #74838A; #5E6970 is 5.63:1 on white and 5.22:1 on the canvas, so light-theme text-secondary and text-tertiary both clear small-text AA. F-075 is rewritten as symptom-as-filed / resolution / rule-today; the open half of PD-280 is scoped to dark text-tertiary #74808A at 4.20:1 on the surface, which is real.
  • The orange ramp was documented at its pre-v1.6.0 values in four places. colors.md primitive table (50–400), the email.md legacy row, the tenant-override example, the primary-tint peach literals in navigation.md and page-shell.md, and — the part that renders — the inlined --kcds-orange-* primitives in all 18 canonicals that carry them, three of them at all eight stops. Every one now matches tokens.json (#FFF1E4 #FFE5CD #FFD4AD #FFBF83 #FFA551). detail-record-shell.html also carried a literal status-warning-bg: #FFEDDC; it is #FFF1E4. These were the five PROSE DIVERGENCE warnings A-03 has printed since 1.6.0.
  • Two dark-theme figures were wrong since ADR 032. Learn 500 on the #181D22 surface is 3.70:1, not 4.00; Comply is 3.15:1, not 3.20. Corrected in tokens.json $note, tokens.css, product-accents.md and colors.md. Both still clear the 3:1 non-text floor.
  • The dark "Contrast vs tint-on-dark" table measured different things per row. The legacy row was on the 10% tint (8.04:1); the four suite rows were on the bare surface (7.44 / 7.32 / 7.81 / 7.93) under the same heading. The table now has three explicit columns — 10% tint, 20% fill, bare surface — with the fill named as the binding number (6.69 / 6.23 / 6.11 / 6.33 / 6.42, all AA). Matching comments in tokens.css and colors.md say the same.
  • Legacy dark on-primary-tint #FFB060 was understated at "5.25:1+"; it is 8.04:1 on the tint, 6.69:1 on the fill.
  • Five documented tokens that never existed are removed: green-400, green-600, red-100, red-200, red-400 — documented in colors.md with hex values, defined in neither tokens.json nor tokens.css, so a var() on any of them resolved to nothing (the GC-38 class inside the foundations). Each ramp now states its three defined stops and where the intermediate need is actually met. The red-tint AA callout that cited red-100 now cites the real light and dark status-error-bg with recomputed figures (3.47:1 / 3.83:1).
  • Every canonical still inlined the pre-ADR-032 blue primitives — --kcds-blue-50: #E4F5FF and --kcds-blue-500: #329DFF (authoring-shell.html also blue-100: #C7E2FF). The v1.13.0 re-colour rewrote the Comply *chain* in the canonicals as literals but left the blue *ramp* behind, so status-info — which reads var(--kcds-blue-500) — rendered the old info blue in all 20 references while tokens.css says #1567D2 on #E3EDFA. Realigned in all 20. This is the A-02 canonical-drift class; a primitive-level comparison of every canonical against tokens.css now reports zero light-theme mismatches.
  • Rounded figures made exact where a rounded value could be misread as a different one: #9A9A9A 2.9 → 2.81, #74838A 3.9 → 3.92, #737373 4.7 → 4.74, #5E6970 5.6 → 5.63, and orange-700 on the corrected orange-50 tint 3.63 → 3.74.
[1.15.1] — 2026-09-23

Patch. No token changes and no rule changes. A post-release audit of the v1.15.0 product/suite
map against the KC product navigation found the categories clean — every product resolves to the
same suite in every file — and surfaced six documentation defects, one from this release and five
older. All six are fixed here. No ADR: nothing decided, only corrected.

Fixed

  • Two files still described the Grow accent as blue, stale since ADR 032 (v1.13.0) re-coloured it to emerald. 06-components/nine-box.md told a builder the 9-box avatar accent was blue; that now names emerald #0A8558 and adds the reminder that the token resolves per category. In 05-quality/maintenance-audits.md the A-01 wording is rephrased so "Comply teal and Grow blue" reads unambiguously as the palette *of PD-294's time*, with the current hues stated after it.
  • A-01 did not cover Hire. The contrast-audit procedure enumerated categories as learn / comply / grow / internal / legacy — hire is added, with a note that any A-01 run recorded before v1.15.0 did not cover it.
  • kc-products.md claimed "all 17 products briefed". Neither part was true: the count predates KC Recruit, and KC Phishing has never had a brief. The status line now names the two products that lack one, and the four "17 products" claims elsewhere are replaced with the counts the router can actually support — 14 public products across four suites, 6 internal tools.
  • KC Phishing has a [NEEDS BRIEF] entry in products/kc-comply.md, carrying only what is settled (suite, category value, slug, tenant-theming status, email literals) and an explicit instruction not to infer its behaviour from KC Safety or KC Docs.
  • New product names were not findable in the briefs. Every brief was written under the old name, so a reader arriving from the accent table with "KC Map" or "KC Studio" found nothing. Brief headings now carry both spellings (## KC Map (Competency Builder) — full brief), so either greps, and kc-products.md gains a name-resolution table mapping every current name, former name and legacy slug to its brief and section.
  • 187 legacy product names replaced across the zero-rules, foundations, cross-cutting, quality and component files, plus the KC-prefixed ones in the briefs: Marketplace → KC Library, Skills Assessment Engine → KC Skills, Talent Assessment → KC Talent, Course Authoring Tool → KC Studio, Competency Builder → KC Map, Employee Onboarding / KC Onboarding → KC Onboard, Training Needs Analysis → KC TNA, Incident Management → KC Safety. Generic uses of the words ("marketplaces and catalogs", "Marketplace Journey Templates", the Competency Map Builder inside TMS) are untouched, and the alias columns keep the old names on purpose. Catalogued failures keep their historical product naming so F-NNN traceability holds; F-026 now states the current name alongside it.
  • SKILL.md's description lists the current product names, with the former names kept after them so a request phrased either way still routes to the skill.

Known gap — recorded, not closed

  • No canonical reference is captured on the hire category. Every other category has at least one; Hire has none, and v1.15.0 put KC Talent into the self-audit-protocol.md test matrix without one existing. Both files now say what to do meanwhile: build Hire surfaces from pipeline-kanban.html / detail-record-shell.html / wizard-shell.html with data-kcds-product-category="hire" — every canonical already carries the full hire chain in both themes — and do not re-tag an existing canonical, which would make its chrome disagree with its own content and header (the drift A-02 exists to catch). The reference worth capturing first is a KC Recruit candidate pipeline, where the periwinkle / AI-violet adjacency has to be demonstrated rather than described.
[1.15.0] — 2026-09-23

Minor. Adds a fourth product suite, Hire, on periwinkle #6A5DF8. No existing token
changes value and no token is renamed, but two live products change accent: KC Onboard
leaves Comply and KC Talent leaves Grow. ADR 035.

Added

  • Hire suite — periwinkle #6A5DF8. hire joins learn / comply / grow as a data-kcds-product-category value (internal is still not a suite). Products: KC Recruit (new domain), KC Onboard (was Comply) and KC Talent (was Grow). A Hire product sets the attribute and every component reading --kcds-color-primary or --kcds-color-accent-N re-colours without edits — no selector or contract change.
  • --kcds-periwinkle-50…700, the eleventh colour ramp: #EDECFE #DEDBFD #C9C5FC #AFA8FB #8E84FA #6A5DF8 #5A4FD3 #4C43B3. Generated from the 500 by the published method (white-mix 0.88 / 0.78 / 0.64 / 0.46 / 0.24, black-mix 0.15 / 0.28) with no hand-tuning at any stop — the first ramp added since the method was recorded in v0.15.
  • Light and dark hire chains. Light: primary 500, hover 600, active 700, fill 100, tint 50, on-primary white, on-tint and link 700 / 500. Dark: primary holds #6A5DF8 (3.66:1 on the dark surface), hover #796DF9, active #5A4FD3, fill and tint periwinkle at 20% / 10%, link and on-tint periwinkle-300 #AFA8FB (7.93:1).
  • A pre-release threshold for any future suite accent, in product-accents.md → "How the ramp is derived": white on 500 ≥ 4.5:1, 700 on 50 ≥ 4.5:1, 500 on the dark surface ≥ 3:1. Applied twice by judgement — Grow in 1.13.0, Hire here — and now written down.
  • 04-product-context/products/kc-hire.md, split out of kc-talent-performance.md.

Changed

  • KC Onboard: Comply blue #1567D2 → Hire periwinkle #6A5DF8. Onboarding is the end of the hiring pipeline, not a compliance obligation. Compliance *training* delivered during onboarding is still KC Docs / KC Safety and keeps Comply blue.
  • KC Talent: Grow emerald #0A8558 → Hire periwinkle #6A5DF8. KC Performance stays Grow — the two were only on one accent because ADR 014 collapsed Thrive into Grow. Talent Assessment scores candidates; Performance measures people already employed.
  • The accent ships as #6A5DF8, not the #7961FF first set by the DRI. White on #7961FF measured 4.23:1 — above the 3:1 UI floor, below normal-text AA, and a primary button carries normal-weight small text. It was also an outlier at L 69% (others 46 / 45 / 28) and S 100% (others 82–86). Corrected before release rather than carried as a second ADR 012-style exception — the PD-294 move, repeated. #7961FF is not a KCDS value. Rejected alternatives are recorded in product-accents.md so they are not re-derived: #5664F8 (hue 235, 31° from AI-violet, reads as blue) and #6752D9 (the literal ramp-step deepening, S 64, 3.06:1 on dark).
  • L-07 enumerates eleven colour ramps (was ten): periwinkle added. Per ADR 031, an L-07 pass recorded before this release is not evidence for the periwinkle case.
  • product-accents.md → v0.16. The update-protocol line "never invent a fourth suite accent" is replaced: the prohibition is on a *product team* inventing a suite, not on the system growing. Adding one is a DRI decision with a named cost.

Notes

  • ADR 014 is superseded on one point only. It removed the Thrive suite because a suite of two products did not earn an accent *and* because indigo sat 23° from AI-violet #8543DA. The first objection is answered — Hire is three products with a distinct business meaning. The second is not: periwinkle sits 21° from AI-violet, the closest any suite accent has sat to a system colour. It is accepted with a mandatory treatment rule — inside a Hire surface an AI marker always carries the AI icon and the violet tint badge, never a bare violet dot or a violet-only fill — and re-hueing AI-violet is an open follow-up owned by the DRI. On the dark surface AI-violet is itself at 3.08:1, so that review is due regardless.
  • The indigo ramp name is not revived: --kcds-indigo-500 meant #4F46E5 for three releases, and reusing it would make every historical grep ambiguous. The retired perform category value is not revived either.
  • Two tenant-visible products change colour. Any screenshot, canonical or brief showing KC Onboard in blue or KC Talent in emerald is stale from this release.
[1.14.0] — 2026-09-17

Minor. Adds an -on-tint text tier to the status, severity and sensitivity families, and
gives the severity and sensitivity families their first machine definitions. No existing token
changes value; no selector or contract changes. ADR 034.

Added

  • -on-tint text tier, 15 tokens — --kcds-color-status-{success,error,warning,info,featured,neutral}-on-tint, --kcds-color-severity-{1..5}-on-tint, --kcds-color-sensitivity-{public,internal,confidential,highly-sensitive}-on-tint. The text and icon colour for anything painted on that family's own tint: badge, chip, alert body, matrix cell, inline pill. Derivation: the family's theme text hue with hue and saturation held, lightness moved in 1% steps — down in light, up in dark — until it clears 4.5:1 against that family's own -bg composited on the theme plane; first clearing step, baked opaque. Clearing 4.5:1 also clears 1.4.11's 3:1, so an icon on the tint takes the same token. Light values move for success (#008616), error (#DB1111), warning (#AE5400), featured (#823FD9), neutral (#667379) and seven of the nine scale steps; status-info, severity-1 and sensitivity-internal already cleared and alias their base. In dark every family already cleared, so each -on-tint resolves to the base — the token still exists there, so a consumer never branches on theme to pick a text colour. The suffix matches --kcds-color-on-primary-tint, which the accent family has carried since the first token release — this extends that pattern to the three families that never had it, rather than introducing a new one.
  • The severity and sensitivity families, defined. Both were documented in colors.md in both themes from v1.0 and defined in neither tokens.json nor tokens.css — nine families with zero machine definitions, our own GC-38 class sitting inside the foundations. Base, -bg and -on-tint are now all three in the pipeline: 27 tokens. The tint is derived as the hue at 10% over white (light, baked opaque) and the dark hue at 15% over surface #181D22 (dark), matching the character of the existing status tints.
  • F-102 — badge/chip painted in its own hue on its own tint, where the hue *is* the signal. Distinct from F-100: an alert can move its text to text-primary because the icon and border carry the signal; a badge cannot, because the colour is the classification.

Changed

  • 01-foundations/colors.md — the on-tint derivation rule sits beside the border derivation rule; the "same-family foreground" rule now names -on-tint instead of "the matching status text token"; the severity block states that the base value is the signal hue and not a text colour on its own tint.
  • F-100's rule — the alert *icon* now takes -on-tint rather than the base hue. Measured on a live DOM, the warning icon on its tint is 2.12:1 and success 2.96:1, both below the 3:1 non-text floor; the body-text half of the rule is unchanged.
  • 05-quality/audit-and-refactor-protocol.md — a library audit mounts the component set and runs the live-DOM checks. Reporting them out of scope is what let this class survive six consecutive audits.

Not changed, deliberately

  • No new gate check. GC-10 already requires the ratio to be computed "resolving alpha compositing against the actual backdrop". The check was correctly specified and was never run, because every K2 audit was a source audit and GC-10 needs a live DOM (ADR 024). The catalogue holds at 29 stable GC checks and 7 GH heuristics.
  • The tints for status are untouched. Deepening them was the alternative that would clear AA without a new tier; it is the largest visible change in every product, to fix a defect that lives in the text.

Migration

Consumers painting a family hue on that family's tint switch to -on-tint; consumers that mixed
their own severity or sensitivity tints switch to -bg and will see a small visible change,
since those tints are now canonical rather than per-consumer. Nothing else moves.

[1.13.0] — 2026-09-10

Minor. All three suite accents change value (ADR 032) and internal/admin tools take the
KC master orange (ADR 033, supersedes ADR 015). The suite *model* — three suites, accent =
suite, internal = not a suite — is untouched; no selector, token name or product
assignment moves. Every component that reads --kcds-color-primary / --kcds-color-accent-N
re-colours without edits.

Changed

  • Learn = vermilion #D63F13 (was the master brand orange #FF881A). White on-primary 4.59:1, link on white 4.59:1 — Learn clears AA on its own, so the ADR 012 white-on-orange exception now covers only the attribute-less legacy :root chain. Learn and status-warning no longer share a hue. New primitive ramp --kcds-vermilion-50…700.
  • Comply = blue #1567D2 (was teal #0A7A7A). The --kcds-blue-* ramp is re-keyed around it (50 #E3EDFA … 700 #0F4A97). White on-primary 5.38:1. **--kcds-teal-* is deleted and added to L-02 as a retired hue. Status-info still reads blue-500, so Comply primary and info share a hex — separated by role (F-068); a dedicated info hue is a follow-up.
  • Grow = emerald #0A8558 (was blue #006CD0). The DRI's first value #0C9D68 measured 3.48:1 with white and was deepened one step before release (the PD-294 move); the ramp --kcds-emerald-50…700 is generated around #0A8558. White on-primary 4.66:1, link 4.66:1, on-primary-tint = emerald-700 #07603F (6.50:1 on emerald-50). Every suite clears AA.
  • internal = KC master orange #FF881A** (ADR 033; was ADR 015 neutral gray #2C3E46 / dark #E8EAED). Same chain as the legacy :root default, light and dark; accent ramp resolves to --kcds-orange-*. White on-primary is the ADR 012 exception, now on legacy and internal; warnings on internal surfaces are differentiated by icon + leading-stripe. The 10-email/ transactional template set (neutral slate) is not re-cut in this release.
  • Dark chains hold the light 500 as primary for all three suites (vermilion 4.00:1, blue 3.20:1, emerald 3.64:1 against #181D22); text-link / on-primary-tint lift to the ramp 300 (#E99780 / #81ADE7 / #7BBDA5, all ≥7:1). Fill/tint = 500 @ 20% / 10%.
  • All 20 canonical references: light + dark category blocks (learn / comply / grow / internal) rewritten with the new values; detail-record-shell.html and upgrade-to-enterprise.html :root overrides moved to orange; embedded teal primitives replaced by vermilion/emerald; authoring-shell.html and tna-interview-agent-authenticated.html :root defaults re-pointed to their suite.
  • product-accents.md → v0.15; colors.md suite tables, category blocks, dark chains, on-primary-tint and canvas-warm tables; quick-lookup.md §C; one-system-one-language.md; SKILL.md §3; mechanical-lint.md L-02 (teal retired) and L-07 (ten ramps: vermilion and emerald added, teal removed); email.md accent table; product briefs (kc-products, kc-learn, kc-grow, tms, ai-teacher, ai-assistant); production-checklist.md.
  • tokens.json / tokens.css / tokens.scss — build-tokens.py --check passes (0 blocking findings; the 11 remaining prose warnings are the pre-existing colors.md Tier-1 divergences on orange/green/red, unchanged by this release).

Filed rather than fixed

  • The canonical references still declare --kcds-blue-50:#E4F5FF; --kcds-blue-500:#329DFF as their local status-info primitives — a pre-existing drift from tokens.json (which had #006CD0 before this release and #1567D2 after). Not touched here; belongs with the status-info hue follow-up above and PD-448.
[1.12.2] — 2026-09-09

Patch. The two open questions from the User Directory re-run (UD-2135) are decided, and
05-quality/mechanical-lint.md goes to v1.3. Both were rule questions rather than pattern
repairs, so both are answered in the rule text, not only in the grep.

Changed

  • L-05 no longer treats a literal inside a var() fallback as a finding. var(--kcds-color-border, #E5E7EB) is a token reference with a fallback — the token exists and is being referenced, which is what the heading means. Matching it made the check unusable: 682 findings versus 2,870 in UD, with the larger number almost entirely fallbacks. The command now strips var() groups before matching, with a nesting-aware sed so that a var(--x, rgb(…)) fallback is removed while a bare rgba() is still found. The drift risk a fallback carries is real and is not dropped — nothing keeps a fallback equal to the token it shadows — but detecting it is a value comparison against tokens.json rather than a grep, so it moves to build-tokens.py (PD-449).
  • L-16: an !important 16px floor in a media query does not clear the check. The floor is gated on viewport width; the defect is gated on the browser. A 1024px tablet in portrait, or a touch laptop, sits outside max-width: 768px and still zooms on focus — the same viewport-versus-device confusion density.md Rule 5 names for hit areas. A floor also hides the real value at the declaration site. The rule now says raise the declarations, and scope a deliberately smaller input with pointer: fine rather than flooring it with a viewport query. UD's 20 findings stand as work.

Filed rather than fixed

  • PD-448 — the colour primitives consumed directly in component rules in the canonical references, which the narrowed L-07 surfaces: background: var(--kcds-gray-200), the course-card cover gradients, the enterprise-modal badge. Choosing the right semantic token per case is design work, not a patch.
  • PD-449 — --kcds-slate-* still declared in 01-foundations/tokens.css and consumed nowhere, while L-02's prose says slate is not a KCDS token; plus the fallback-drift check above. The token source is canonical under ADR 028, so changing it is a release of its own.
[1.12.1] — 2026-09-09

Patch. L-07's widening in v1.12.0 over-corrected and is narrowed again. Reported from the
User Directory re-run (UD-2135), where the widened check produced 85 findings and not one was
real. Two further findings from the same re-run are open questions, not fixes — see below.

Fixed

  • L-07 matches the nine colour ramps by name again, not [a-z]+. var(--kcds-[a-z]+-[0-9]{2,3}) cannot distinguish a colour primitive from a spacing or radius token: --kcds-spacing-16 and --kcds-radius-12 have the same shape and are the opposite of a defect, since L-08 and L-03 require consuming them. In UD the widened pattern reported 71 spacing tokens and 14 radius tokens with zero colour findings. Pattern is now var(--kcds-(gray|orange|teal|blue|green|red|yellow|violet|bronze)-[0-9]{2,3}), which still covers the five ramps the pre-v1.12.0 version omitted. slate stays out on purpose — it is retired, so L-02 owns it. Any L-07 finding recorded against v1.12.0 needs its token family checked before anyone acts on it.
  • 05-quality/mechanical-lint.md → v1.2, and the authoring rule gains the half that was missing: test a new pattern against conformant code that must stay quiet, in the same run as the near-miss. ADR 031 says describe the defect rather than the literal; it did not say a shape always beats an enumeration, and where the defect class is genuinely closed — nine colour ramps, a fixed list of retired values — a wider shape is as wrong as a narrower literal, and worse in practice because a check that fires on correct code teaches people to ignore it.

Reported, not fixed

  • L-05's prose and pattern disagree about var(--token, #hex). The heading says "no bare literals"; a hex inside a var() fallback is a token reference with a fallback, not a bare literal, but the pattern matches it. In UD the two readings are 682 findings versus 2,870, so this decides whether the check is actionable or a wall. Both readings are defensible: a fallback is defensive, and a fallback also drifts silently from the token it shadows. Needs a DRI call, and it is a rule question rather than a pattern repair.
  • L-16 cannot see a documented override. Its UD findings are declarations already neutralised by an !important 16px floor inside a max-width: 768px media query — the rule is satisfied, the grep is not. Either the check needs a documented-floor exception in the shape L-19 uses for minmax(, or the guidance should say raise the declarations rather than floor them. Also a rule question.
  • The slate ramp is still declared in 01-foundations/tokens.css and consumed nowhere, while L-02's prose says slate is not a KCDS token. One of the two is wrong. Not touched here: the token source is canonical under ADR 028, so removing a primitive family from it is a release of its own, not a patch.

Confirmed by the re-run

L-02, L-19 and L-16's sub-1rem half come back clean on kc-user-directory-web@stable. L-19
is the meaningful one — that is the check that went green there with three unbounded tracks
live. L-05's widening produced 150 rgb()/rgba() and 3 hsl() findings that the literal-hex
pattern could not see.

[1.12.0] — 2026-09-08

Two open questions closed and one class of broken check fixed. Minor — new surface (a
date-format rule, a resolved branding scope), nothing existing breaks: the widened lint
patterns report more, they do not change what KCDS considers correct. Rationale in ADR 029
(tenant brand-color scope), ADR 030 (date format), ADR 031 (a check asserts the shape of the
defect). Raised by the User Directory design-conformance work (UD-1670).

The motivating problem in all three cases is the same shape — a question KCDS left open or
answered too narrowly, which products then answered for themselves. Two written specs for
dates inside one product; three written rules for tenant branding with no precedence; a
mechanical check reporting clean on a page that still had the defect.

Added

  • Date format is a tenant setting, Intl is the fallback (ADR 030) — 02-cross-cutting/multilingual.md → "Dates" gains the rule KCDS was missing: the tenant admin picks the format once, every surface formats through it, Intl on the user's locale covers everything until the setting ships, a hardcoded format string is a defect either way, and the setting carries field order only — numerals and calendar still follow the user's language. Same shape as the LMS admin timezone setting. Listed as tenant-configurable in 02-cross-cutting/tenant-theming.md. Resolves UD-1420 vs UD-2034 without either winning.
  • Density pitfall 7 in 02-cross-cutting/density.md — a desktop-only state is not exempt from Rule 5. The gate is pointer type, never viewport and never whether the state exists on mobile: a collapsed side rail that appears only above md is still coarse-pointer on a touch laptop, so 36px is correct at pointer: fine and a finding at pointer: coarse. No rule changed — Rule 5 already said this, and the misreading it names is recurring enough to be written down.
  • Two routing rows in 00-zero-rules/quick-lookup.md for the branding scope and the date rule.

Changed

  • Tenant brand color scope resolved (ADR 029) — 02-cross-cutting/tenant-theming.md replaces its open question with "Tenant brand color — where it lands": one override value per tenant, applying in every product including KC Native, reaching the tenant logo and the primary-action set and nothing else. Chrome stays neutral. On KC Native the tenant primary replaces the suite accent rather than tinting it. The sign-in page is in scope, conditional on the tenant resolving from the domain before authentication. A section on why this does not collide with ADR 015 (internal tools carry no *suite* accent; tenant branding is a different layer). 01-foundations/colors.md → Tier 3 swaps its v0.11 open question for the resolution. This reverses the interim working assumption that KC Native primaries are system-fixed; surfaces built to it are un-themed, not wrong, and pick the tenant color up through the token chain.
  • The two files still asserting the retired assumption are corrected — 00-zero-rules/one-system-one-language.md ("defer until product strategy resolves the open question") and 01-foundations/product-accents.md ("suite primaries are system-fixed, tenant override applies to legacy orange only") now state the resolution and point at the scope section. 05-quality/final-pass-protocol.md picks up the <n>fr wording.
  • Contrast validation gains its precedent — tenant-theming.md now records that neither half of the rule is a new mechanism: the LMS portal theme editor already computes the text color against the chosen background and refuses to save a failing shade. Validate at input, never at render.
  • Five mechanical checks widened (ADR 031), 05-quality/mechanical-lint.md → v1.1. L-19 matched the literal 1fr and passed any line containing minmax( — blind to 2fr / 1.6fr, and masked by a bounded track in a mixed declaration; it now strips bounded tracks and matches any <n>fr. L-16 matched 10–15px when the class is "below 16px" — now covers single-digit px and sub-1rem. L-05 matched a hex while its own prose also named rgb() — now matches the functional notations. L-07 named four primitive ramps out of nine — now matches the primitive shape. L-02 listed some retired category values and not others — now covers slate, single quotes, and any token family carrying a retired hue. The file's closing section gains the authoring rule: write the pattern from the defect, test it against a deliberate near-miss, and treat a widened pattern as voiding that check's history.
  • 02-cross-cutting/responsive.md → "The 1fr gotcha" states the general form: every <n>fr is shorthand for minmax(min-content, <n>fr), so the coefficient is irrelevant and wrapping only the 1fr tracks fixes nothing while reading as fixed. SKILL.md rule 8 and the two quick-lookup.md lines carrying the old wording are synced.

Fixed

  • **80 retired --kcds-slate-* declarations removed from all 20 canonical references — surfaced by the widened L-02. The slate ramp was retired with the Thrive suite (ADR 014) and L-02's own prose says it is not a KCDS token, yet every canonical still declared four slate primitives in :root. Consumed by nothing** — zero var(--kcds-slate-*) references across the bundle — so removal changes no rendering; what it removes is the invitation to reach for a retired ramp because it happened to be declared in the file you copied.
  • 31 unbounded fr tracks in 16 canonical references — found by re-running the corrected L-19 against the bundle's own canonicals. Includes the var(--kc-sidenav-w) 1fr shell grid in eight admin/AI references — the case L-19's own prose names as canonical — and 1.4fr 1fr in five learner-portal references. All are now minmax(0, <n>fr). Desktop rendering is unchanged; the tracks are simply allowed to shrink. The shell-grid snippet in 06-components/page-shell.md is corrected to match.

Voided

  • Every L-02 / L-05 / L-07 / L-16 / L-19 pass recorded before this release, in this bundle and in every repo running the scan. Those runs answered a narrower question than the check now asks, so they are not evidence about the wider class. Re-run them (ADR 031).

Gates

  • A-03 token source sync: pass — 0 blocking machine-file findings; 22 prose warnings carried forward unchanged from v1.11.0 (the --kcds-tenant-* empty family, the orange / teal / blue prose-vs-JSON divergences, five green/red prose orphans). None are touched by this release and each still needs a call on which side is canonical (ADR 028).
  • A-05 reference integrity: one dangling path, pre-existing and forward-looking — 09-changelog/README.md cites 00-zero-rules/update-protocol.md, planned under PD-130. INDEX.md and every mini-TOC regenerated.

Reported, not fixed

  • L-20 matches overflow-x: clip only. overflow-x: hidden on html / body breaks position: sticky the same way and is at least as common in the wild. Widening the check means widening the rule, which is a design call rather than a pattern repair — filed rather than silently changed.
  • The gate check catalogue (GC-NN) was not audited for the ADR 031 class. Those detectors are implemented in Lane C, not as greps in this file; whether any of them assert a literal where the class is wider is open.
[1.11.0] — 2026-09-07

Structural hygiene. No rule, token, or check changed — every design fact in v1.10.0 is
still here, and still says the same thing. What changed is the shape of the bundle: the
files an agent has to load to answer a question, the counts that had drifted out of prose,
and the maintainer surface around a release. This closes the hygiene backlog opened after
the v1.6 wave (PD-283 to PD-290, plus PD-305 / PD-309) and finally lands the product-context
split PD-140 declared done. Rationale in ADR 026 (router pattern, derived facts, generated navigation) and ADR 027 (one release history, one version string).

The motivating problem: 04-product-context/kc-products.md had grown to 4,723 lines, so
"read the product brief" meant loading seventeen briefs to use one. The root README.md
had reached 4,143 lines and still opened with a v1.1.13 status line — nine minor versions
stale — while claiming four suites including Thrive, retired back in ADR 014.

Changed

  • 04-product-context/kc-products.md → router, 4,723 → 172 lines (PD-286, PD-140). It keeps what routes: the KC Native / legacy table, the three-suite map, the how-to-use steps, the product hierarchy, a "Where each brief lives" table, and the update protocol. Every brief moves to 04-product-context/products/, one file per domain or product: four suite-domain files (kc-learn.md, kc-grow.md, kc-talent-performance.md, kc-comply.md) and six internal-tools files (internal-user-directory.md, internal-communication.md, internal-reports.md, internal-course-manager.md, internal-usmp.md, internal-admin-tools.md). The internal-* grouping is a naming convention for the no-accent products, not a suite — there is no Platform suite (ADR 013 / ADR 015). Headings promote one level in each extracted file; brief content is byte-identical otherwise.
  • README.md → maintainer stub, 4,143 → ~150 lines (PD-284). Keeps the semver triggers, release hygiene, packaging rules, release procedure, ownership, and feedback channel. Everything else — v0.x/v1.0/v1.1 release notes, the old roadmap, the agent-capability snapshots — is frozen in the maintainer working repo as kc-design-foundations-README-history.md and is not distributed. It also carried live errors: a four-suite table with Thrive indigo, and "Performance in indigo" prose.
  • README.md states no version number at all (ADR 027). It said "v1.1.13" nine minor versions after that release, because a version written in two places is a version that disagrees with itself and the release protocol's second bump is the one that gets skipped. The version now lives in SKILL.md only, and the release procedure no longer asks for a second bump. Two rules were added to release hygiene at the same time: no living file states a count or ID range owned by another file (PD-285), and the packaged tree is diffed against the repo tree before shipping (PD-286 — the gate against a repackage silently reverting completed work).
  • SKILL.md version paragraph is a router line again. It claimed per-release summaries live in 09-changelog/ and ONLY there, while carrying two of them. They now live there only.
  • Hardcoded counts removed from prose (PD-285). SKILL.md had the catalogue running F-001…F-100 against an actual F-101 in its file map and a fixed count in its quick-start note; 05-quality/failure-catalogue.md still said "48 of them, F-001–F-049" and "80+ failures" against 100 entries; 00-zero-rules/quick-lookup.md carried an F-067–F-099 range in a section heading. Counts and ID ranges that can be derived are no longer written down — the deriving commands live in 05-quality/maintenance-audits.md → A-04, and the rule is now part of release hygiene.
  • 00-zero-rules/decisions/lms-admin-canonical-color.md cited kc-products.md by line number (724, 847, 7–13, 20) — all invalidated by the split. Repointed to files and section headings. Line-number citations are now banned outside INDEX.md (A-05).
  • 05-quality/self-audit-template.md — the report template moves out of audit-reports/ into the block that owns the protocol.
  • Stale Figma provenance removed from five canonical references. Five Pattern A files claimed their header was specified "per KC Figma source" and "verified against canonical Figma screenshot". KC no longer works in Figma, and a provenance claim pointing at a source nobody can open is worse than none: the canonicals now cite the live KC portal surface, which is what they were actually checked against. Figma still appears where it is an *industry* convention being cited as precedent (authoring-canvas dark mode, account menu placement) — that is a design argument, not a stale KC dependency, and it stands.
  • Two dangling paths in 08-canonical-references/README.md pointed at layout.md and UI/components/header-footer.md, files belonging to the superseded kc-lms-portal-design skill and never present in this bundle. Reworded to name that skill without implying a local path (A-05).

Added

  • INDEX.md (root) — generated per-file section and line-range map (PD-283). Jump to a section instead of reading a file. Regenerated on every release; it is the only place in the bundle where line numbers are allowed to appear.
  • 08-canonical-references/INDEX.md — section map for the canonical pages (PD-283). Each canonical is a complete worked page of 1,000–3,000 lines; the map lists its CSS and markup section banners with line ranges so you can open one at the right place.
  • Mini-TOC with line anchors at the top of every file over ~600 lines (PD-289). The 1,100–1,500-line references (colors.md, responsive.md, navigation.md, page-shell.md, page-archetypes.md, data-display.md, failure-catalogue.md and the rest) had no navigation at all.
  • 05-quality/mechanical-lint.md — L-01…L-18 (PD-288). Grep-able pre-delivery assertions, each mapped to the failure it prevents and to the gate check that catches the same class on rendered output. Runs after final-pass-protocol.md, before production-checklist.md, which remains the single pass bar. Explicitly necessary and not sufficient.
  • 01-foundations/build-tokens.py — the token pipeline, recovered and shipped in the bundle (PD-290). The file tokens.scss had claimed since its first release to be "generated by build-tokens.py", while that script existed nowhere in the bundle and had been lost. Rewritten with --check (release gate: name-set and value parity across tokens.json / .css / .scss, one alias hop resolved in each direction, prose tables in colors.md checked against the JSON, empty token families detected) and --generate-scss. Findings are split by meaning: machine-file drift blocks a release, prose divergence and empty families are reported and filed, because resolving those means deciding which side is canonical (ADR 028). tokens.css gains a do-not-edit header naming the JSON as the source. Deliberate-mismatch test performed: injecting one wrong hex into tokens.css fails --check with the exact token named; reverted.
  • 05-quality/maintenance-audits.md — A-01…A-05 (PD-309, PD-290). The recurring audits on the skill itself: contrast audit, canonical drift check, token source sync (tokens.json canonical, .css / .scss generated, name-set and value parity, prose parity), documentation count drift, internal reference integrity. A-03, A-04 and A-05 are release gates and are wired into the release procedure in README.md.

Removed

  • audit-reports/ no longer ships in the .skill bundle (PD-287) — five files, 124 KB of dated session reports and one HTML artefact. The exclusion list is documented in README.md → Packaging. Completed reports live in the maintainer repo; the durable output of an audit is the skill change plus the changelog entry.

Audit results recorded with this release

  • A-03 token source sync: pass on the blocking set, 22 findings reported. tokens.json and tokens.css agree on all 150 names and values. tokens.scss is partial by design — primitives and scale only, since a Sass variable cannot switch on data-kcds-theme — and the procedure asserts parity within each export's scope rather than in bulk, which a naive reading would have flagged as 54 missing names. Fixed: one real gap, $kcds-font-mono absent from the generated SCSS. Reported, not fixed — each needs a decision on which side is canonical, so none was auto-applied:
  • 21 value divergences between the colors.md primitive tables and tokens.json (orange-50…400, teal-50/100/500/700, blue-50/100/500). Two are consequential rather than cosmetic: the prose states that teal-500 (#0EA5A5) and blue-500 (#329DFF) are primitives *distinct from* the AA-deepened suite primaries (#0A7A7A, #006CD0, PD-294), while the JSON has folded the deepened values into the primitives. Deferring to the JSON by default would silently redefine the primitive ramp — status-info resolves from blue-500 — so the direction of the fix is a design call, not a sync. The PD-205 calibration table is exempt via a token-check: historical marker; it records values that were true at the time.
  • **--kcds-tenant-* documented in Tier 3 of colors.md with no definition in either machine file — the GC-38 class the skill defined for itself in v1.9.0. White-label theming currently has no token surface to override.
  • A-02 canonical drift check: two findings, carried as follow-ups.
  • 15 of 20 canonical references declare an incomplete radius scale, which is the exact trap 01-foundations/radius.md and F-047 exist to prevent — ten admin/authoring files omit 16/20/24/32, four Pattern A files omit 20, one omits 4 and 32. Latent, not live: none of those files currently consumes an undeclared step, so nothing renders square today. It bites the next person who copies a canonical head and reaches for var(--kcds-radius-16) — which is how F-047 happened in the first place. Not fixed here because completing the scale changes rendered output for any consumer already copying these heads, which is a release-tier decision, not hygiene.
  • The .app shell grid in the admin canonicals declares a bare 1fr next to the fixed side-rail track, while a comment a thousand lines above claims .app uses minmax(0, 1fr). The mobile media queries do use minmax(0, 1fr); the desktop declaration does not. F-004's signature, contradicted by the file's own comment.
  • A-04 count drift: pass after the fixes above. Two counts remain in prose, both in the header of the file that owns the set (29 stable GC checks, 7 GH heuristics) — verified against the file: 30 GC IDs of which one (GC-42) is retired, and 7 GH IDs. The documented counting command was also wrong: the GH set is written inline on one line, so a line-anchored grep -c returned 1 and would have read as a pass. It now counts IDs.
  • PD-288 lint validation. Run against the June 2026 pre-fix LMS Admin Course Manager artefact: L-09 (a font-weight: 600), L-12 (border-radius inside :focus-visible), L-22 (hamburger with no role="dialog") and L-23 (no canonical logo mark) all fire — true positives on known-bad output. Run against lms-admin-dashboard.html: two assertions over-reported and were corrected rather than excused — L-19 was flagging repeat(auto-fit, minmax(180px, 1fr)), which is already bounded, and L-23 was counting markup instances instead of mutually exclusive logo slots. The remaining hits on the canonical are the two A-02 findings above, not false positives.
  • A-05 reference integrity: pass. Every backticked in-bundle path resolves; the remaining unresolved names are maintainer-repo tooling (kcds-ref-audit.py, build-tokens.py), external URLs, consumer-side examples, and historical changelog entries under the append-only rule.
  • A-01 contrast: not run** — no token value changed in this release, so it has no trigger. Carried to the next release that touches values.

Note for consumers

Nothing to relearn — no rule, token, component, canonical, or gate check changed. Two
pointer updates if you hold local references: 04-product-context/kc-products.md is now a
router, so a reference that meant "the KC Comply briefs" should point at
04-product-context/products/kc-comply.md; and the root README.md no longer holds release
notes, so link 09-changelog/CHANGELOG.md instead. PD-305 (skill-readiness follow-ups)
closes with this release: PD-289, PD-290 and the reference-integrity gate were its
dependencies.

[1.10.0] — 2026-09-04

Tightens the gate classifier. A deterministic class must name a closed signature — a procedure with a decidable outcome — or it does not belong in the deterministic set; failing that test moves the class to the advisory heuristics, not down a severity tier. The reciprocal rule now governs additions: a new class is justified only when no existing class can see the pattern.

Surfaced by the Lane C precision follow-up (PD-437). Implementing detectors against the catalogue reached GC-42 and found nothing to implement — the class asked for a structural diff against a canonical reference, which is a judgement with no threshold. Sitting in the Low tier had hidden that for two releases: a class that never blocks attracts no scrutiny about whether it can run at all. Rationale in ADR 025.

Changed

  • 05-quality/gate-severity-model.md → v1.2. *Non-canonical naming/structure divergence* leaves the Low tier and enters the heuristic classes as canonical structure divergence, cited to 08-canonical-references/, with the reason recorded: structure in general is a family of judgements, not a check, and where a canonical reference names a specific required composition that composition becomes its own narrow deterministic class instead (the drawer identity block is the worked example). The Low icon-family class widens to cover a character glyph or emoji standing in for an icon — the extreme case of a mixed icon set, not a class of its own.
  • 05-quality/gate-check-catalogue.md → v1.2. GC-42 retires into a new "Retired checks" section, explicitly marked as not runnable and carrying no detect procedure so a catalogue-driven reader skips it; the ID is not reused — findings citing GC-42 predate this release. GC-41 gains the glyph-as-icon signature: a code point carrying the Unicode Extended_Pictographic property, or a dingbat used as an affordance, inside chrome (button, nav link, [role=tab|menuitem], an empty-state or list-row icon slot). Scope is what keeps it checkable — content regions and user-generated content are out entirely, and surfaces where emoji IS the content (reaction bars, the Communication emoji picker) are a documented exception emitting exception-applied, on the same mechanism as ADR 012 in GC-10.

Added

  • GC-39 · Native control left at the user-agent default, Medium. A form control KCDS specifies (select, input[type=checkbox|radio|range|date|file], progress) rendering with the browser's own appearance. Both conditions required: computed appearance resolves to a native value with no appearance: none in the declaration chain, and none of the control's box properties resolve through a --kcds-* variable. A control authored to keep a native affordance on purpose — the select chevron — is not a finding. This is the one class detected by absence: GC-11 needs a literal to catch and GC-31 needs authored geometry, so an unstyled control is invisible to both. Medium and not High deliberately: a native control is still operable and accessible, so this is a consistency and brand failure, not user harm. Source-greppable; the source form is the absence of any authored rule matching the control selector.
  • GH-07 · Canonical structure divergence, advisory. The former GC-42, one per route, no volume escalation, cited to 08-canonical-references/.
  • ADR 025 — a check needs a closed signature; without one the class is a heuristic, not a lower tier.

Stable checks hold at 29 (one added, one retired); heuristics 6 → 7, corrected in 05-quality/README.md.

Note for consumers

Lane C's shipped GC-41 detector (PD-437, iris-agent PR #33) is incomplete against this release until the glyph signature is implemented, and GC-39 needs a detector with no precedent in the existing set, because it asserts a negative. Neither reaches the fleet until the deploy host's skill mount moves past v1.9.0 (PD-425). Consumers holding GC-42 in a local check list should map it to GH-07 rather than delete it — the signal is unchanged, its flag becomes advisory.

[1.9.0] — 2026-09-03

Corrects the RTL font stacks. KCDS specified 'Noto Sans Arabic', 'Lato', sans-serif from the first typography file onward; per-glyph fallback plus the Noto faces' full Latin coverage means that order rendered every Latin run in an RTL page in Noto and left 'Lato' unable to render a single character. The order is reversed and the rule is restated as split by script, not by locale.

Surfaced by the K2 conformance conversation on PD-419 (finding A4) — the K2 owner's rebuttal was right about our documentation, which is what makes this our defect before it is his. Rationale in ADR 023. Catalogued as F-101.

Changed

  • 01-foundations/typography.md — the Arabic and Hebrew sections are replaced by one RTL section covering Arabic, Hebrew and Urdu: 'Lato' first, the script's Noto face second, 'Segoe UI' / Tahoma closing the stack, with the per-glyph rationale, a wrong-order counter-example, and the note that an RTL stack never ends on Lato or Arial. font-size-base: 17px corrected to the custom property --kcds-font-size-base (the old line declared a property that does not exist).
  • 02-cross-cutting/multilingual.md — the same reversal applied to the ar / he / ur stacks, a new "Order matters — Lato first" subsection, the supported-languages table now reads Lato (Latin) + Noto … for the RTL rows, and the quick-reference block gains a FONT STACK ORDER section.
  • Font loading split by family. Lato continues to load from Google Fonts via the canonical <head>. The Noto faces are now specified as self-hosted from the KC CDN with font-display: swap and a per-script unicode-range, replacing the combined Google Fonts link in both files. unicode-range is documented as a second line of defence: correct subsetting also prevents Latin capture, but the stack order is normative independently of it.
  • 05-quality/gate-check-catalogue.md GC-15 — tightened from "first family in the documented stack (Lato / documented Noto for RTL scripts)" to "first family is Lato, in every locale", plus a grep counterpart for a Noto-first declaration. Under the old wording a Noto-first RTL stack passed.
  • 05-quality/pr-review-checklist.md — the font-family line now checks stack order, not just membership.
  • SKILL.md rule 2 and 00-zero-rules/quick-lookup.md rule 2 — one clause each: the rule is split by script, Lato leads every stack including RTL. Detail stays in the foundation files.

Added

  • F-101 in 05-quality/failure-catalogue.md — Noto-first RTL font stack swallows the Latin runs. Catalogue count 99 → 100 (corrected in SKILL.md and 05-quality/README.md).
  • ADR 023 — the typeface rule is split by script, not by locale; Lato leads every stack.

Also in this release — the classifier gaps the K2 audit exposed

Four findings on PD-419 (A5, C4, F4, F5) matched no class in gate-severity-model.md v1.0. A closed classifier means an unmatched pattern cannot become a finding at all, so these were gaps in the gate rather than in K2. Closed here:

  • 05-quality/gate-severity-model.md → v1.1. Medium gains *retired interaction pattern rendered as current* (recorded retirement + detectable signature; the removed-taxonomy class stays High, because that one puts another product's identity on screen) and *documented token family with zero definitions* (the capability it carries is inert — Tier-3 tenant tokens are the live case). Low gains *wrong semantic tier within the right family*, with the boundary written down: if the substitution drops contrast below AA it is the AA class, not this one. The advisory heuristics gain *derivation inconsistency within a token family* — one family produced by two mechanisms across themes, every value correct, the family incoherent; it predicts drift and never blocks.
  • 05-quality/gate-check-catalogue.md → v1.1. GC-37 (retired pattern), GC-38 (empty token family), GC-43 (wrong tier) and GH-06. Stable checks 26 → 29, heuristics 5 → 6. The 30-check figure written when the catalogue shipped was wrong at the time (the real count was 26) and is corrected in 05-quality/README.md to the current 29.
  • Check scope, and the library-vs-product boundary (ADR 024). Each check is now scoped route-rendered / needs-live-DOM / source-greppable, and a run states its scope at the top. Ten checks cannot answer against a component library; they report not-applicable with the reason, never as passes. A library audit is not evidence about the products that embed the library.
  • 01-foundations/colors.md — the text tiers get usage guidance, not just values: what belongs to primary / secondary / tertiary / disabled, and the deciding question (does the user read this for the information in it, or to know what part of the UI they are looking at?). Three K2 components independently chose text-secondary where the spec says text-tertiary; three authors reaching for the same wrong tier is a missing rule, not three mistakes.

Note for consumers

RTL pages will render differently after this release: Latin runs move from Noto to Lato. Arabic, Hebrew and Urdu glyph rendering is unchanged — those characters never matched Lato and resolve to the same Noto face as before. K2's RTL stacks now diverge from the corrected spec; that is tracked on PD-419 A4, restated.

[1.8.0] — 2026-08-31

The detection companion to the v1.7.0 severity model. Same-day minor release: the model shipped in the morning; the catalogue operationalizes it for the Design Gate harness (PD-405/PD-407) and Lane R.

Tracked under PD-407 (epic PD-405). No new ADR — the catalogue implements ADR 022's model without new architectural decisions.

Added

  • 05-quality/gate-check-catalogue.md — 30 stable checks (GC-01…GC-42) mapping every deterministic class in the severity model to a machine detection procedure (computed-style comparison, DOM assertion, declaration-chain resolution, tab-order walk), the evidence the harness must emit for it (computed-styles / DOM node dump — the screenshot is an attachment, not the proof), and the resulting flag. Plus five advisory heuristic classes (GH-01…GH-05, one per route per class, never blocking) and run discipline: one finding per check per route, complete findings per run, no-dump-no-blocker (a blocking finding without harness evidence downgrades to warning and the missing evidence is itself reported), and the closed-classifier tie-back (a GC cannot exist without its class in the model). Evidence field names may be refined when the findings contract (PD-408) is agreed; procedures and thresholds are normative now.
[1.7.0] — 2026-08-31

Lands the severity model for the Design Gate (Gate 2, PD-405/PD-406) and makes it the single severity source for all design findings. Motivated by the agentic pre-deploy gate work: the gate's blocker/warning flag must derive from a KCDS-owned model, and the skill's severity guidance was scattered across three places and internally contradictory in one of them.

Tracked under PD-406 (epic PD-405). Rationale in ADR 022.

Added

  • 05-quality/gate-severity-model.md — the classification model for design findings: severity (Critical / High / Medium / Low) per rule class, verifiability (deterministic / heuristic), attribution (introduced / pre-existing), and the blocker-flag derivation blocker = deterministic AND severity ∈ {Critical, High} AND introduced. Critical follows the axe-core impact definition (a user cannot complete the task) and deliberately holds only user-exclusion classes; heuristic findings are always advisory; pre-existing findings never block the PR author (Clean-as-You-Code attribution — the bar applies to the change, not the codebase). Includes mechanism-agnostic judging (computed values vs tokens.json, regardless of K2 / vendored tokens / framework theming), documented-exceptions handling (exception-applied, never granted by analogy), the closed-classifier rule (no class in the file → not a finding → escalation), and the finding output mapping for the gate contract.

Changed

  • 05-quality/audit-and-refactor-protocol.md Step 3 no longer carries its own severity list — tiers come from the model file. This resolves an internal contradiction: the step listed "Hardcoded value…" under a "Known High severity" heading while the entry itself said "Severity Medium". Resolution: the class is High; what made bulk hardcoded values feel Medium was legacy volume, which attribution now handles (pre-existing never blocks) without softening the tier.
  • 05-quality/pr-review-checklist.md → "Finding format": severity is sourced from the model file alone (previously: Step 3 classes + F-IDs + production-checklist sections — three drift-prone sources). F-IDs and checklist sections remain descriptive context.
  • Failure-catalogue counts corrected in SKILL.md (48 → 99) and 05-quality/README.md (31 → 99) to match the actual number of catalogued F-ID entries.
  • Removed-taxonomy remnant fixed: 08-canonical-references/README.md succession-9box intro still read "KC Perform / indigo", contradicting the same section's own ADR 014 note (flagged by Nova as an out-of-scope finding in PD-415). Corrected to KC Performance → Grow / blue.
  • SKILL.md version paragraph slimmed to a router line: current version + pointers to 09-changelog/ + one sentence on the current release. The inline per-release recaps (v1.3.1 … v1.6.0) that had accumulated there are removed — that history duplicates this changelog, and the two had already drifted (v1.3.5 existed only in the SKILL.md prose; its entry is recovered above).
[1.6.0] — 2026-08-26

Closes the specification gaps that the K2 conformance audit (PD-404) exposed on the KCDS side. A meaningful share of what that audit recorded as K2 diverging from the system was the system being underspecified, self-contradictory, or — for the text tiers — measurably wrong, with K2 having filled the gap sensibly. This release fixes our side first; K2 remediation follows separately.

Tracked under PD-416.

Added

  • Suite accent ramps, 50–700, per suite (ADR 020). New semantic tokens --kcds-color-accent-50 … -700, resolving per data-kcds-product-category. 500 / 600 / 700 are the existing primary / hover / active; 50–400 are derived by gamma-space mixing toward white at fixed ratios, with the method recorded in 01-foundations/product-accents.md so future suites are generated rather than picked by eye. Under internal the ramp resolves to neutral greys. Primitive ramps for orange, teal and blue are now complete and coherent at all eight stops.
  • --kcds-radius-md, defined at 8px (ADR 019) — cited by five component specs since v1.3.x while being defined in no token file.
  • --kcds-font-mono and a 01-foundations/typography.md → "Monospace" section. For strings read or transcribed character by character: certificate and error ids, API keys, hashes, version strings, aligned figures. 0/O and 1/l/I are not distinguishable in Lato at identifier sizes.
  • Spacing steps 0, 2, 80, 128 and radius steps 0, 2 in tokens.css / .json / .scss. The prose scale documented fourteen spacing steps; the machine files exposed ten, so the tokens were poorer than the documentation.
  • Compound error ring in 06-components/inputs.md — a field that is both invalid and focused draws a 3px ring in status-error rather than the standard focus ring, so the error signal is not painted over at the moment the user is in the field.
  • "Same row, same height" stated as a system rule in 06-components/selection.md.

Changed

  • Text tiers hold literal values (ADR 018, closes F-075). text-secondary #9A9A9A → #737373 (2.9:1 → 4.7:1); text-tertiary #74838A → #5E6970 (3.9:1 → 5.6:1). Both now clear AA at body and caption sizes. The tiers no longer alias gray-500 / gray-600; the grey ramp is unchanged and border-default, border-strong and status-neutral are unaffected. Dark theme was already compliant and is untouched.
  • Compact control radius 4px → 8px (ADR 019), via --kcds-density-radius-control now resolving to --kcds-radius-md.
  • The accent-shade prohibition is reversed (ADR 020). product-accents.md previously said intermediate shades must not be used; it now says they exist as tokens and must not be computed locally. The old rule was aimed at the wrong target and produced the drift it existed to prevent.
  • Focus ring: the result is normative, the mechanism is not (ADR 021). A 2px ring in --kcds-color-border-focus on all four sides is required; outline remains the reference implementation and an inset box-shadow producing the same ring is equally conformant. An ancestor with overflow: hidden crops an offset outline and cannot crop an inset ring.
  • --kcds-color-primary-tint / -fill now resolve to accent-50 / accent-100 so there is one light scale rather than two. Visible deltas: Learn tint #FFEDDC → #FFF1E4, fill #FFE1C4 → #FFE5CD; Comply tint #E0F7F7 → #E2EFEF, fill #B5EBEB → #C9E2E2; Grow tint #E4F5FF → #E0EDF9, fill #C7E2FF → #C7DFF5. Comply moves most because its old stops were derived from #0EA5A5, a primary superseded by PD-294.

Fixed

  • 06-components/selection.md instructed that select matches input sizes and then listed different numbers (48/40/32px against input's 56/52/48px). The instruction was right and the table was wrong; the table is removed and select inherits input geometry in full — height, radius, horizontal padding and label size, not one of them.
  • 01-foundations/spacing.md gave the compact vertical gap as 16px in a diagram and 12px in prose. 12px is correct.
  • 06-components/actions.md gave X-small as both 28px and 24px for a size that exists at compact density only. 24px, with the comfortable column left empty.
  • 06-components/inputs.md cited --kcds-color-focus and --kcds-color-primary for the focus ring; accessibility.md holds the canonical --kcds-color-border-focus. Corrected to the canonical name.
  • SKILL.md still carried v1.5.0 in its version line after the v1.5.1 hotfix, so the router and the changelog disagreed about which release was mounted.

Notes

Three questions from the audit are recorded as open rather than decided here: select radius, padding and font size beyond the height rule; whether K2's undocumented additions beyond the monospace stack should be adopted; and the per-component override audit for the ~122 K2 components not covered in the first pass. They are on PD-404 and PD-416.

[1.5.1] — 2026-08-20

Taxonomy hotfix. Three files still described the pre-ADR-013/014 accent model in live guidance (not historical record), which put the skill in contradiction with itself: 05-quality/pr-review-checklist.md treats any reference to a Platform/cyan or Thrive/indigo suite value as a violation, while these files supplied exactly that. Found during a PD-309 scope review; no token, coverage, or rule change.

Fixed

  • 05-quality/self-audit-protocol.md — the standard test matrix listed "all four category accents" and then named five (Grow, Learn, Perform, Comply, Platform), with Marketplace defaulting to "Platform or public". Rewritten to the three suites (Learn, Comply, Grow) plus the internal no-accent category; Performance is now correctly placed in Grow per ADR 014, and User Directory covers the internal category per ADR 015.
  • 08-canonical-references/README.md — upgrade-to-enterprise.html was described as "Pattern B · Platform / cyan", with chrome following "User Directory & Licensing → Platform / cyan". User Directory is an internal tool: corrected to internal, neutral gray chrome, ADR 015. The canonical HTML itself was already correct — only its description had drifted.
  • audit-reports/self-audit-template.md — the expected-accent field offered "Grow Teal / Learn Blue / Perform Indigo / Comply Slate / Platform Cyan". Doubly stale: it carried both removed categories and the pre-v0.12 hue mapping. Corrected to Learn Orange / Comply Teal / Grow Blue / Internal (no accent) / Legacy Orange.

Not changed

Historical records retain their original wording, per the append-only rule: the root README.md release history, the PD-205 dark-calibration rationale in 01-foundations/colors.md, past audit reports under audit-reports/, and the "removed in vX" notes in 01-foundations/product-accents.md. These describe what was true at the time and are not read as current guidance.

[1.5.0] — 2026-08-12

Status border tier, surface hover state, and closure of the tokens.css/json drift on the status family. Triggered by CMB-1247 (SAM admin console referenced 135 non-existent token names — --kcds-color-danger-* numeric ramps falling through to hard-coded hex, so status colors never adapted to dark theme) and its Track B request; the same gap is anticipated by CMB-1164 (SAM learner sub-app) and the UD-1670 alignment audit. Rationale in ADR 017.

Added
- --kcds-color-status-X-border for all six statuses (success, error, warning, info, featured, neutral), both themes — the muted 1px border tier completing the badge/alert anatomy (-bg fill + border + status-X text). Derivation rule documented in colors.md: theme status color muted to ≈35% and baked opaque — toward white in light, toward surface #181D22 in dark; baked values are canonical. Light: success #A6DEAF, error #FABBBB, warning #FFCFA3, info #B7DCFF, featured #D4BDF2, neutral → gray-400. Dark: #2C6A48 / #723F42 / #735E23 / #355378 / #514978 / neutral → darkgray-border-default #3A424B. Covers feedback-*-border use cases from CMB-1247.
- --kcds-color-surface-hover — transient pointer-hover state for surfaces (table rows, list items, cards). Light: gray-200 #EAEFF3; dark: #262D34 (one step above elevated). Semantics split from surface-subtle, which is re-documented as the *resting* tinted plane (table header, section bg) — a gray-100 hover is invisible on a gray-100 plane, which is why hover needed its own step.

Changed
- 01-foundations/tokens.css / tokens.json — drift fix: status-X-bg, status-X-fill, and the entire status-neutral set were documented in colors.md but absent from the machine-readable files; both are now complete and in sync for both themes, alongside the new -border and surface-hover entries.
- 06-components/status.md — badge spec now names exact tokens per layer (-fill solid, -bg subtle, -border outlined/subtle border); the semantic-color table's shorthand names (--kcds-color-success etc.) corrected to the real --kcds-color-status-* names, with an explicit note that the infix-less names and numeric status ramps do not exist (this shorthand is the suspected origin of the invented names in CMB-1247).
- 01-foundations/colors.md — status block gains the -border lines, the derivation-rule paragraph, and the "never a full-saturation 1px status border" guardrail; surface blocks gain surface-hover in both themes with the subtle/hover semantics split.
- SKILL.md — version → v1.5.0.

Rejected
- text-subtle (a fourth text tier between text-secondary #9A9A9A and text-tertiary #74838A) — declined. The perceptual gap between the existing tiers is already narrow; an intermediate ≈#87919A is visually indistinguishable at body sizes and fails AA for small text on white. Consumers needing a quieter tier use text-tertiary. Recorded in decisions.md so the request is not re-litigated.

Notes
- Version: 1.5.0 (minor — new tokens, no breaking change; existing token values untouched).
- Downstream: requires a @kc/k2 release to reach consumers (K2 pipeline is owned outside this skill); SAM (CMB-1247 Track A/B), CMB-1164, and UD-1670 consume from that release.

[1.4.0] — 2026-08-12

Brand deployment modes and white-label logo semantics. Rationale in ADR 016. Triggered by a production Q&A failure: the design-system assistant, answering from the skill, told a product owner that a tenant logo replacing the KC mark violates the parent-brand-anchor rule — while KC Safety ships full white-label including a "remove KnowledgeCity branding" toggle live in prod (SAFETY-414/572/174) and KC Phishing plans custom branding at P1B. The skill's anchor rule was written without deployment scope, so a correct KC-branded rule was over-applied to white-label deployments.

Added
- 02-cross-cutting/tenant-theming.md — restored (present in earlier releases, lost in a packaging pass; the 02-cross-cutting/README.md file map and colors.md cross-link still referenced it). Rebuilt from the canonical Confluence "Tenant Theming" page (PD-215) and extended with: the three brand deployment modes — KC-branded (default) / white-label (tenant logo replaces the KC mark) / de-branded (KC identity removed entirely; a per-product capability) — three mode-independent invariants (no logo ever redrawn or recolored; single-instance rule; structure never changes), the entitlement rule (the product brief / Unified Scope decides which modes a product offers; brief silent → KC-branded only — silence is not permission), configurable vs locked lists, brand token chain + contrast-validation requirement for tenant primaries, web/mobile white-label flows, a dated per-product status snapshot (Safety live incl. de-branding; Phishing planned P1B; Portal mobile ~88–91 builds; Communication emails live; TNA documented as the mode-1 pattern — KC mark stays), and the PD-53 depth-tier hypothesis marked "to validate."

Changed
- 06-components/page-shell.md — Element 1: "no per-tenant override" reworded to "the asset itself is never modified for a tenant" plus an explicit scope paragraph: the anchor rule governs KC-branded deployments; white-label replaces the mark (never recolors, tints, or co-brands), de-branding removes KC identity, entitlement per product brief. Single-instance section: "no tenant exception" reworded — the mark has no per-theme variation and no tenant *modification*; a white-label tenant replaces it.
- SKILL.md — layer 3 anchor sentence rescoped to KC-branded deployments with pointer; Step 3 "Neutral / White-label" style line gains the replacement semantics + pointer; version → v1.4.0.
- 00-zero-rules/one-system-one-language.md — "What this rule preserves": KC-logo bullet rescoped to KC-branded deployments.
- 01-foundations/product-accents.md — "Logo treatment" anchor sentence rescoped with pointer.
- 01-foundations/colors.md — Tier 3 intro gains the replacement-semantics callout; the existing "Full tenant theming architecture" cross-link resolves again.
- 00-zero-rules/quick-lookup.md — rule 4 gains the white-label replacement parenthetical.

Notes
- Version: 1.4.0 (minor — restores a sub-file and adds new normative content: deployment modes + entitlement rule; no token change, no component API change).
- Scope guard: this release defines the *mechanism* only. Which products offer white-label/de-branding remains owned by product briefs; the full product × depth matrix is still the open deliverable of PD-53. The KC Native primary-color override question (colors.md) is untouched and remains open — logo replacement is independent of it.

v1.3.5 — 2026-08-07

PR review checklist (Lane R support, PD-312).

  • New 05-quality/pr-review-checklist.md: the ordered, mechanical procedure for a read-only diff review against KCDS — product category/shell context, colors & tokens, control geometry/radius/spacing, typography, computed WCAG contrast, binary accessibility/RTL checks, fast greps, report assembly. Findings only: no refactored code, no merge verdict (verdicts are the Design Lead's). Severity resolves from the failure catalogue and the audit protocol's documented classes; values resolve from tokens.json and the cited prose files, never from the checklist itself.
  • 05-quality/README.md file map + routing line updated; SKILL.md quick-start shape 3 gains the read-only-review pointer.
  • Rationale: review criteria are design-system content. The design-system assistant (Iris, PD-297) executes this file at review time and cites it; when a rule changes here, the review changes with it, with no agent edit.
[1.3.5] — 2026-08 *(entry recovered in the v1.7.0 release — the release shipped but its changelog entry was never written; recorded here from the SKILL.md version summary of the time)*

Added

  • 05-quality/pr-review-checklist.md — the read-only diff-review procedure (findings only, no refactor, no verdict) executed by the design-system assistant's review lane (Lane R, PD-312) and usable for manual pre-review.
[1.3.4] — 2026-08-04

Codifies the alert/banner contrast rule after a WCAG AA failure surfaced moving KC Skills onto @kc/k2 — the k2-alert error variant painted its message text in status-error #F03E3E on the red tint (~3.1:1). The failing pairing was latent in KCDS itself: status-error text on status-error-bg (#FFF0F0) is only ~3.5:1, and one step deeper (red-600 #D43333) still only ~4.3:1. Catalogued as F-100.

Added
- 05-quality/failure-catalogue.md — F-100 (A11Y/COLOR): alert/banner text in the status hue on the status tint fails AA; applies to error, warning, and info tints.

Changed
- 06-components/feedback.md — banner anatomy: title and body use --kcds-color-text-primary, never the status hue. Added the AA rule block (measured ratios) and made a colored border / 4px leading edge optional — the KC default is tint + severity-matched icon alone; the icon carries severity, text stays default ink.
- 01-foundations/colors.md — AA note on the red scale: red-500/red-600 must not be used as text on a red tint; alert text uses text-primary, red goes on the icon (border/edge optional).
- SKILL.md — version → v1.3.4; failure-catalogue range → F-100.

Notes
- Version: 1.3.4 (patch — codifies an existing AA constraint + one failure entry; no token value changed, no component API change). Status-hue text remains valid for inline field validation on a light/surface background — not on a tint.
- Downstream: the @kc/k2 component-palette fix (K2-owned) is tracked separately; this release gives that work a cited source of truth (F-100 + feedback.md).

[1.3.3] — 2026-07-15

Internal / admin tools get a defined no-accent state, and the Platform-canonical cleanup deferred from v1.3.2 is finished. Rationale in ADR 015.

Added
- data-kcds-product-category="internal" in tokens.css / tokens.json — neutral gray chrome, no hue. Light: primary #2C3E46 (white-on-primary 11.1:1), hover #1F2023, active #0F1419, fill #EAEFF3, tint #F3F7F9, on-tint #2C3E46, link/focus #404A4F (9.1:1). Dark: light neutral CTA primary #E8EAED / hover #FFFFFF / active #CCD5DD, link #CCD5DD, focus #74808A, and on-primary #1F2023 (dark — the one non-suite exception to white-on-primary; a dark button would not read on the dark surface). The five supporting apps (KC User Directory, KC Admin Tools, KC USMP, Integrations, Communications) use it.

Changed
- 01-foundations/product-accents.md — documents internal as the non-suite no-accent state with its full chain; valid category values are now learn / comply / grow / internal; how-to-apply and update-protocol updated (never leave an internal tool attribute-less — it falls through to legacy orange).
- SKILL.md — version → v1.3.3; routing + §3 note the internal state.
- **08-canonical-references/*.html (all 20) — the dead platform accent blocks (light + dark) replaced with internal blocks so each canonical again mirrors tokens.css (ADR 007). detail-record-shell.html + upgrade-to-enterprise.html bodies retagged platform → internal; detail-record-shell's bespoke root/dark cyan override neutralised to internal.

### Removed
-
All --kcds-cyan-* primitives from canonicals (dead since the v0.13 Platform removal) and the last platform category blocks/bodies. The ADR 014 Platform-canonical cleanup tail is now closed.

### Notes
-
Version: 1.3.3 (patch — adds a non-suite category + canonical cleanup; no suite value changed, no component API change).
-
Unaffected: status, severity, sensitivity, and AI-violet stay fully coloured on internal surfaces — they are system colours, not suite accents. No slate accent was adopted (a no-accent vs slate comparison found slate indistinguishable from neutral gray while still costing a full accent chain). User Directory was not** given legacy orange (orange is the Learn suite accent).

[1.3.2] — 2026-07-15

Removal of the Thrive/indigo suite to match the finalised official KC suite taxonomy (three suites: Learn · Comply · Grow). KC Talent and KC Performance move to Grow (blue). Rationale in ADR 014.

Removed
- Thrive / indigo suite — no longer a suite or an accent. The thrive and legacy perform data-kcds-product-category selectors, the indigo suite tokens, and the --kcds-indigo-* primitives are deleted from tokens.css / tokens.json / tokens.scss. Indigo is no longer a KCDS token.

Changed
- 01-foundations/tokens.css / tokens.json / tokens.scss — indigo primitives + light/dark thrive/perform accent blocks removed; header notes updated to the 3-suite model. No values changed for Learn, Comply, or Grow.
- 01-foundations/product-accents.md — rewritten to v0.14: three-suite table, per-product table (KC Talent & KC Performance now Grow; KC TNA added to Grow; KC Onboard + KC Phishing added to Comply), ramp tables, collision table, and update protocol all reduced to three suites. Indigo row retired.
- 01-foundations/colors.md — primitive-usage table indigo rows retired; the thrive/perform semantic block and the Pattern-A canvas Thrive row removed; the var()-indirection teaching example re-cast from perform/indigo to grow/blue; a stale "teal-50 for Grow" canvas summary corrected to blue-50. Dated PD-205 dark-calibration rationale left as historical record.
- SKILL.md — version → v1.3.2; §3 + routing steps + file tree reduced to three suites; suite-decision step lists learn / comply / grow.
- 00-zero-rules/one-system-one-language.md, quick-lookup.md, 04-product-context/kc-products.md, 10-email/email.md, 06-components/page-archetypes.md, 06-components/opinion-scales.md, 02-cross-cutting/accessibility.md — suite lists, examples, and accent enumerations reduced to three suites; Talent/Performance examples recoloured blue.
- **08-canonical-references/*.html (all 18) — perform/thrive accent blocks and indigo primitives removed. succession-9box.html retagged thrive → grow. tna-interview-agent-authenticated.html bespoke kc-grow (teal) block removed and body retagged to standard grow — fixes KC TNA rendering teal instead of its correct Grow blue. Stale "Grow (teal)" / "Comply — Slate" / "KC Perform — Indigo" comments corrected.

### Notes
-
Version: 1.3.2 (patch — category removal + token cleanup; no new component API). One accent per suite unchanged; Learn keeps #FF881A white-on-primary AA exception (ADR 012).
-
Deferred: the Platform/cyan canonical cleanup (two bodies still tagged platform, platform accent blocks still in canonicals) is not in this tag — it needs a defined neutral-gray-chrome body state first (no attribute currently falls through to legacy orange, not gray). Tracked separately.

### Fixed (full colour audit, same tag)
A full colour re-verification (tokens ↔ json ↔ scss ↔ all 18 canonicals ↔ docs, plus WCAG re-measurement of every documented ratio) surfaced and fixed:
-
colors.md dark suite blocks were on the pre-v0.12 mapping — [dark][grow] held the teal values, [dark][learn] held the blue values, and [dark][comply] held slate #64748B (v1.3.1 corrected the light block but missed the dark ones). Rewritten to the current mapping: Learn = orange, Comply = teal #0A8282, Grow = blue #0874C8; slate story condensed to a historical note.
-
colors.md on-primary-tint tables (light + dark) were on pre-v0.12 suite labels with unmeasured light values; rewritten to the three suites with measured ratios (light: Learn 3.63:1 — inside the ADR 012 orange exception; Comply 6.98:1; Grow 7.43:1).
-
product-accents.md dark Learn -active said #C75F00; tokens and all canonicals use #E0780F. Table corrected.
-
False "clears AA" claim for Learn links — orange-700 #C75F00 on white measures 4.15:1, under the 4.5:1 threshold. product-accents.md and the colors.md block comment now state the real ratio and scope it under the ADR 012 Learn exception (matching what 10-email/email.md already said).
-
AI accent doc drift — ai-augmentation.md, status.md, conversational-ui.md cited a Tailwind violet #7C3AED (+ #6D28D9/#F5F3FF/#DDD6FE) for --kcds-color-ai; ground truth in tokens (--kcds-color-ai-suggestion) and all canonicals is --kcds-violet-500 #8543DA (dark #A78BFA). All three docs aligned; -surface naming variant aligned to -bg.
-
text-tertiary contrast claim was wrong — #74838A on white measures 3.9:1, not the documented 4.6:1 (F-075, v1.3.0); dark #74808A measures 4.2:1 on the #181D22 surface, under the "verified 4.5+" claim. Claims corrected in colors.md, failure-catalogue.md (F-075), quick-lookup.md, navigation.md, with honest scoping (clears the 3:1 large-text/UI floor only). ⚠ Open follow-up (PD-280): recalibrate text-tertiary (light ≈#68757D reaches 4.7:1) or restrict the F-075 remedy to large text.
-
PD-205 calibration table** — added a note that its row labels are the pre-v0.12 category names (Teal = today's Comply, Blue = today's Grow; Indigo/Slate/Cyan retired), kept for measurement traceability.
- Verified clean: tokens.json ↔ tokens.css ↔ tokens.scss fully consistent; all 18 canonical suite blocks value-identical to tokens.css (formatting differences only); PD-294 ratios (5.15/5.18/4.61/4.64) re-measured exact; all dark link/on-tint values ≥8:1; email accent table consistent with the ramp; #8543DA on white 5.51:1 ✓.

[1.3.1] — 2026-07-14

WCAG AA colour-contrast fix for the Comply and Grow accents, plus removal of the Platform/cyan category. Resolves PD-294 (KCDS root) and PD-293 (kc-safety-app instance). Rationale in ADR 013.

Changed
- 01-foundations/tokens.css / tokens.json / tokens.scss — light Comply primary deepened #0EA5A5 → #0A7A7A (hover #096B6B, active #085C5C) and Grow primary #329DFF → #006CD0 (hover #005CB0, active #004E96). White-on-primary, accent-text-on-white and text-on-tint now all clear 4.5:1; each suite remains a single accent (deeper saturation, not a second shade). on-primary-tint, text-link, border-focus follow the new primary. Tints/fills (teal-50/100, blue-50/100) and all dark tokens unchanged (dark was already AA). Cyan primitives removed.
- 01-foundations/product-accents.md — v0.13: suite table, per-product table, light/dark ramp tables, representative token block, collision table (Grow no longer shares a hex with status-info), and update protocol all updated; Platform rows removed.
- 01-foundations/colors.md — primitive-usage table and the semantic per-category block corrected to the current 4-suite mapping (this block was still on the pre-v0.12 scheme: grow=teal, learn=blue, comply=slate — a stale-token-source drift, now fixed); Platform light+dark blocks, reference-table rows, and warm-canvas table entries removed/corrected.
- 00-zero-rules/quick-lookup.md, SKILL.md — category list reduced to four suites; Platform references removed; corrected a stale line stating Learn uses a *dark* on-primary (it is white, the documented AA exception).

Removed
- Platform / cyan internal-tools category — no longer a suite or a lane. Internal/admin tools (KC Reports, KC Admin Tools, KC Communication, KC User Directory & Licensing, KC Course Manager, KC USMP) use neutral gray chrome with no product accent.

Notes
- Version: 1.3.1 (patch — token-value fix + category removal; no new component API). on-primary stays white for every suite; Learn keeps #FF881A with white on-primary as the documented AA exception (ADR 012) — one orange, unchanged.
- Follow-up (not in this tag): canonical 08-canonical-references/*.html that hardcode the old teal/blue hues or the cyan lane still need a re-skin pass (ADR 010 pairing), and downstream prose references (04-product-context/kc-products.md, 10-email/*, component docs) carry the old hexes. Tracked for a canonical/downstream backfill. kc-safety-app (PD-293) must also adopt the new tokens and fix its dark-theme misuse (app was colouring text with the dark *primary* #0A8282 instead of the bright dark link token #5EEAD4).

[1.3.0] — 2026-07-13

TNA-redesign hardening batch (PD-291, feeds the PD-280 v1.3 cycle). Every item below was legacy or
generated output that a human had to catch during the TNA admin redesign; each is stated failure-first
in its file. Catalogued as F-067–F-099.

Added
- 00-zero-rules/visual-discipline.md (new zero-rule file) — four promoted hard rules: colour is a budget (one colour-carrying channel per component; icon = accent, value = text-primary, meaning in the label) (F-067); the product accent is never a status colour (F-068); font-weight is 400/700 only, with an allowed/forbidden-per-element map (F-069); never white-on-white — the fill/border trade places by parent surface (F-070). Wired into SKILL.md Step 1 (now "four short files").
- 02-cross-cutting/data-integrity.md (new file) — "the design must not render a lie": absence ≠ zero (F-071), a legend is a promise (F-072), buckets must not straddle a threshold (F-073), two panels must not colour by different axes (F-074), one vocabulary per concept, admin vs learner audience language, delete decoration that duplicates adjacent text.
- 05-quality/failure-catalogue.md → F-067–F-099 added as the "TNA redesign batch" (compact format), plus a Fast checks grep block in 05-quality/audit-and-refactor-protocol.md (font-weight:600 = 0, accent-color = 0, no radius in focus-visible, full radius scale declared, border-default on white parents, no text-secondary at small size, complete-table checklist, legend↔series, bucket↔threshold, no 0-for-no-data, ≥2 status channels, tag-balance).
- 08-canonical-references/auth-signin.html + auth-role-entry.html (two new canonicals, PD-291) — the universal pre-auth sign-in shared by all KC products. auth-signin.html: split brand/form layout, username/password with inline validation + error + loading states, password show/hide, working theme toggle (light first paint + persistence), mobile compact lockup, .sr-only; re-skins per product via data-kcds-product-category. auth-role-entry.html: the credential-less variant — role choice-tiles (no check, per selection.md) + a "no sign-in needed" explore CTA that stays inside the public surface (does not enter an authenticated shell, per public-surfaces.md). Reconciled to the v1.3.0 rules on intake: full radius scale declared in :root (F-047) and form controls lifted to radius-16 for the comfortable-density pre-auth surface (F-076). Registered in SKILL.md (file tree + canonical table) and the 08-canonical-references/README.md Status list.

Changed
- 01-foundations/colors.md — text-secondary (#9A9A9A, 2.9:1) fails AA at caption/body size; use text-tertiary (#74838A, 4.6:1) for small text (F-075).
- 01-foundations/typography.md — weight allowed/forbidden map; no mixed weights inside one line (breaks tabular-nums); two type styles per card header maximum (F-069).
- 01-foundations/radius.md — radius follows density; a public sign-in / lead-capture surface is comfortable density (16/24), not admin (F-076).
- 01-foundations/iconography.md — never set border-radius in a global :focus-visible rule (F-077); no emoji in UI chrome (F-078).
- 06-components/inputs.md — never rely on accent-color for checkboxes (Chrome draws a black tick on a blue box) — draw the control (F-079); flex-column children stretch — set align-items:flex-start when they hold chips (F-080).
- 06-components/data-display.md — the full required table pattern (anatomy, type-aware sorting with aria-sort, range-readout pagination that resets on filter change, three distinct empty states, labelled row actions, card-scoped overflow, tabular numerics) (F-081–F-084); chart honesty & legibility (multi-channel ramps, empty≠small, show the track, vertex dots, SVG text in user units) (F-085–F-089).
- 06-components/selection.md — chips vs segmented; an unselected option must not look disabled (F-090); equal-width chips in a column; control height is a property of the row (F-091).
- 06-components/status.md — never encode by colour alone; ≥ 2 channels (F-092).
- 06-components/opinion-scales.md — sentiment scales may use sentiment colour (the face is the datum).
- 06-components/navigation.md — active item: text = text-primary, icon = accent; inactive text = text-tertiary not text-secondary (fixes a spec bug) (F-093); role-scoped shells render only what the role may open — flag on <body>, verify the selector, clear on switch (F-094).
- 06-components/page-archetypes.md — drill-down pages lead with a summary strip; hierarchy is carried by structure not a caption; counts must match their scope label (F-095, F-096).
- 04-product-context/public-surfaces.md — consent is a blocking record not a checkbox (F-097); an obvious ← Back exit + Esc (F-098); a "no sign-in needed" entry must not drop into an authenticated shell (F-099); both gates share one layout.

Notes
- Version: bumped to 1.3.0 (minor — additive across 11 files + 2 new files, no breaking token/API changes). This tag covers the TNA-redesign batch only; the pending [Unreleased] (PD-244) and [Unreleased — PD-278] blocks below remain open and roll into their own tags as those epics close — retag if you prefer to fold them together.
- Canonical reference still deferred: §16 of the July rules proposal (08-canonical-references/admin-table.html — one reference implementation for the full table pattern) remains its own ticket; it is a full HTML build, not a doc edit. The table rules above stand on their own until it lands. (The auth / sign-in canonicals *did* land this version — see Added.)
- Consistent with the one-design-system rule: all additions are foundations/cross-cutting/component-level, no per-product or per-domain split.

[Unreleased]

Added
- Form & layout hardening from the KC Perform suite review (PD-272). Codified the recurring form/layout/table defects caught during the July 2026 review as failure-catalogue entries F-050–F-066 and added required-rule sections to 03-ux-principles/forms.md, 06-components/inputs.md, 06-components/data-display.md, and 06-components/page-shell.md. Covers: the field-row margin-leak that stair-steps multi-column rows (F-050 — the single most repeated alignment bug); one fixed 44px height for every single-line control so mixed input types (date/number/text/select) align (F-051); a single custom select chevron at a fixed inset instead of the width-dependent native arrow (F-052); mandatory canonical .th-sort sortable headers for data tables — never bare <th> (F-053); search/filters inside the panel, never floating on the canvas (F-054); tabs in the same block as their content with a gap under the tab bar (F-055); panel-content top padding so text/cards don't collide with the panel__head divider (F-056); explicit gap between panels stacked inside a wrapper (F-057); form actions in a bottom-left bar, primary first (F-058); list→detail navigation — a top-level list has no back link, the detail does (F-059); list-item primary action right-aligned & vertically centred (F-060); progress fills clamped 0–100 and completion bars filling their block (F-061); raw status enums always rendered as semantic badges (F-062); a top-bar bell owning notifications instead of a duplicate left-nav item (F-063); width-bounded sparse summary cards sharing a width with siblings (F-064); KCDS capitalization on all visible labels (F-065); key/value card = header row + aligned key→value list, never one grid with a floated action (F-066).
- 10-email/ — User Directory & Licensing template set (3 new templates). Built on the canonical chassis (kc-transactional-email.html), Platform / cyan: kc-product-assigned.html (product assigned to a user — summary + "Getting started" steps card, CTA *Open {{product_name}}*), kc-access-removed.html (product unassigned / access revoked — no primary CTA, neutral tone, quiet "review remaining products" link, reassures account + other products unaffected), kc-license-updated.html (seat / licence change — seats_previous → seats_total row, CTA *Manage licences*). Each carries its merge-token contract; email.md gains a Template set table + a note that purely-informational emails legitimately omit the bulletproof button. Completes the first product batch of the email epic (PD-249).
- 10-email/ — KC transactional EMAIL standard. New cross-cutting block: email.md (the rules) + kc-transactional-email.html (the reference — Platform / cyan "Enterprise request received", pairs with the upgrade-to-enterprise modal). Email is a separate rendering medium (table layout, inline styles, no CSS vars, hosted-PNG logo — no inline SVG/data: in prod, ~600px, light-only, Outlook ignores web fonts + table border-radius). Chassis is fixed (logo header bleeding to the top with squared top corners → greeting → content cards → dark footer bleeding to the bottom with squared bottom corners); colours + inner content vary per product/message. Logo = the real assets/kc-logo.svg mark rasterised to a hosted PNG (orange on light, a white knock-out variant on the dark footer) + "KnowledgeCity" as live Lato text — never redrawn (ADR 005). Orange → product accent on action surfaces only; the mark stays orange. No app-download block (KC has no consumer apps). Button: moderate radius, not a pill, not bold, with a fallback link. Rounded bordered tables need border-collapse: separate. Codifies the email work from the upgrade-to-enterprise session (PD-250).
- 08-canonical-references/upgrade-to-enterprise.html — canonical request / quote form + success-confirmation modal on the full Pattern B shell. Scenario: "Upgrade to Enterprise" (AI Teacher upsell) inside the KC User Directory & Licensing admin (Platform / cyan — the chrome follows the product the user is *in*, not AI Teacher, the form's subject). Demonstrates, beyond the shell: (1) .pagehead--card capping a focused single-task surface (see ADR 008); (2) the new choice-tiles component in both presets — product-accent (contact method) and severity/traffic-light (priority, via data-level); (3) a success-confirmation modal carrying a copyable ticket reference (+ toast), a left-aligned head (badge inline beside the title — no centre/left mix), a from-form summary, trailing-aligned actions, full focus-trap/Esc/backdrop/scroll-lock; (4) bounded form measure (paired row2 fields + capped single fields so nothing goes full-bleed) with content left-anchored to the sidenav. Carries the full category map (light + dark, light first paint).

Changed
- 05-quality/failure-catalogue.md → v1.0.7: added F-050–F-066 (July 2026 KC Perform suite review wave — form-row alignment, control height, select chevron, sortable headers, in-panel filters, tab/panel spacing, form action placement, list→detail nav, progress clamp, status badges, bell notifications, card width & layout, label casing).
- 09-changelog/decisions.md → ADR 009: email guidance lives inside this skill (10-email/), not a new skill — resolves the architecture question raised by the email epic (PD-248). SKILL.md: file tree now lists 10-email/.
- 06-components/selection.md → added the Choice tiles (single-select tile group) section: one component recoloured per group via --tile-accent/--tile-tint/--tile-on (product-accent + severity presets); severity is always a tint bg + saturated text (solid red/amber/green fills fail WCAG AA); the corner-check pitfall (an absolute corner check knocks a centred label off optical centre — omit it on centred tiles, or left-align + reserve symmetric padding); a "don't use a connected segmented control for a form-submit choice that needs per-option colour" note (its overflow:hidden clips the selection ring and it reads as a different component family).
- 06-components/page-shell.md → "What goes in the page header bar" now documents .pagehead--card as the standard realisation of the white header bar (required for focused single-task surfaces, optional for list/dashboard), with the canonical pointer.
- 09-changelog/decisions.md → ADR 008: .pagehead--card adopted as the standard header-bar realisation — resolves the "not yet a convention" open question flagged in pipeline-kanban.html (CHANGELOG v1.2.2). SKILL.md: file tree + Step 5.5 table updated for the new canonical.

Notes
- Still within the open v1.2 cycle (epic PD-244); no version bump — version remains 1.2.2 until the full PD-244 epic completes, consistent with the PD-203 handling above. When the cycle closes, these entries roll into the next tagged patch.
- The choice-tiles component is a foundations-level addition (lives in 06-components/selection.md), not a per-product or per-surface skill — consistent with the one-design-system rule. The same holds for 10-email/: a cross-cutting block inside this skill, not a new skill (ADR 009).

[Unreleased — PD-278 suite colour remap]

Changed
- Product accent model → 4-suite (PD-278, ADR 012). Accent now keys to suite instead of the v0.11 five-category split. Palette remapped (no new hexes; existing primitives reassigned): Learn = orange #FF881A, Comply = teal #0EA5A5, Grow = blue #329DFF, Thrive = indigo #4F46E5; Platform/internal tools stay cyan. slate retired from suite use. The perform category is renamed thrive (indigo unchanged), with perform kept as a backward-compatible CSS alias so shipped canonicals keep resolving.
- 01-foundations/tokens.css + tokens.json regenerated — [data-kcds-product-category] blocks (light + dark) remapped to the palette above; thrive selector added alongside the perform alias. :root legacy-orange default and the dark-theme root block unchanged. ADR 010 propagation triggered.
- 01-foundations/product-accents.md rewritten to v0.12 (per-suite model): four-suite palette, the nine renamed products with formerly + legacy-slug aliases, Platform internal lane, legacy→product aliases, features/modules (AI Teacher, Employee Onboarding, Succession/9-box) that inherit their host suite, and the Marketplace / TNA "not public — decide" note. Full CSS no longer duplicated here — points at tokens.css (source of truth per ADR 007/010) to avoid a PD-251-class split.
- 09-changelog/decisions.md → ADR 012 added; supersedes PD-246 (accent ≠ domain). The three former divergences now follow their suite (KC Map → blue, KC Skills → blue, KC Talent → indigo).
- Workstream 1 — downstream color + naming propagated (structure/index/canonical layer): 01-foundations/colors.md (color-families table → 4 suites + new product names), 04-product-context/kc-products.md (top category table → 4-suite + former→new map; TMS quick-ref teal→blue, kc-grow→grow), 00-zero-rules/one-system-one-language.md (suite/domain list + color-model sentence + worked example), and SKILL.md (§3 summary, version note, canonical file-tree labels).
- All 18 canonicals (08-canonical-references/) re-skinned to the new palette. Each embeds its own copy of the category map, so the token edit did not reflow them automatically — the embedded [data-kcds-product-category] blocks (light + dark) were regenerated in place to Learn=orange / Comply=teal / Grow=blue / Thrive=indigo, and a thrive selector was added beside perform. Body re-tags: conversational-ai.html comply→grow (Competency Builder = KC Map = Grow), succession-9box.html perform→thrive. Untagged learner-portal / lms-admin canonicals inherit :root orange = KC Learn (correct). pipeline-kanban (grow→blue) and wizard-shell (comply→teal) shift automatically to the right suite hue.

Notes
- Accent ramp reference added to product-accents.md. New "Full accent ramp — resolved values (light + dark)" section tabulates the per-suite semantic ramp (primary / -hover / -active / -fill / -tint / -on-primary, plus link / focus / on-tint) as it resolves at runtime, and a "Is there a full 50–700 primitive scale per accent?" section stating there is not one — the semantic layer is the supported API; primitives exist only at consumed steps; a full sequential scale is a PD-280 extension request, not something to improvise. Added because the agent could not answer a PE's ramp question (no complete ramp existed to report); it can now answer definitively.
- Learn = orange exception (updated — white on-primary). On-primary on the master orange is white (#FFFFFF), light and dark — a deliberate, accepted WCAG AA exception (2.39:1). This reverses the initial landing (dark #1F2226 on-primary): dark text on the brand orange was rejected as off-brand and darkening the orange itself reads brown, so the brand orange is kept exactly and the contrast shortfall is accepted and documented. orange-700 links (text on white, not on the fill) and icon/leading-stripe warnings are unchanged. Only Learn carries this exception; solid orange surfaces will flag in the monthly a11y audit as the known accepted case, not a regression (ADR 012, PD-278 rev). Applied across tokens.css / tokens.json (light + dark) and all 18 canonicals.
- Residual (deliberately not mechanically swept): the descriptive product-brief prose inside 04-product-context/kc-products.md (per-product sections still narrate with the former names — Marketplace ×80, Skills Assessment ×24, Talent Assessment ×22, Competency Builder ×14, Course Authoring ×8). These are an editorial rename, not a mechanical one (e.g. "Marketplace" the product vs. "marketplace" the concept; "Performance" the product vs. the word), so they were left for a careful prose pass rather than a blind global replace that would corrupt the file. Every color surface and every structural / index / canonical name reference is updated. README.md is intentionally untouched — it is append-only version history.
- Token-value change, so ADR 010 applies: tokens.css/tokens.json regenerated here in the same change. This is a MINOR-worthy remap; version tag lands when the release is cut (PD-244 cycle is closed — release hygiene decision owned by the Design Lead).

[Unreleased — PD-132 component library expansion]

Added
- 06-components/signature-pad.md — new component. Hand-drawn attestation capture (<canvas>) that locks into a tamper-proof record on submit. Quick-decision table (pad vs typed name vs checkbox), structure + HTML, four states (empty / drawing / signed / submitted-locked), specs (high-DPR scaling, baseline, stroke smoothing), Pointer-Events behavior, and the accessibility rule that a pad is never the only signing path (mandatory typed-name equivalent; role="img" + aria-live state announcements). The submitted-locked state deliberately hands off to 02-cross-cutting/tamper-proof-records.md rather than inventing its own sealed treatment. Added to 06-components/README.md (file tree + decision map). Approved Lucide only (signature, refresh-ccw, lock, shield-check); existing tokens only; shares the bounded form-column measure.
- 06-components/timeline.md — new component. Events on a real date axis: three event types (milestone / range / marker), Year/Month/Day granularity (reuses the segmented control), pan, detail-on-demand. Leads with a decision table separating a timeline from the things it's confused with — stepper (order, not dates), audit log (immutable list), activity feed (latest-first stream), gantt (dependencies). Encodes event *type* by shape (dot/bar/rule), never by status color (avoids severity collision). Accessibility: the absolutely-positioned track has a mandatory ordered-list equivalent (spatial position is invisible to AT); events are focusable buttons; detail opens on hover and focus and tap. Responsive: collapses to a vertical timeline on narrow viewports / long sets. RTL: axis mirrors via logical properties (earliest at inline-start). Added to 06-components/README.md (file tree + decision map). Approved Lucide only; existing tokens / product accents.
- 06-components/gantt.md — new component. Task rows + duration bars on a date axis, finish-to-start dependencies (single SVG overlay), today indicator, optional critical path. Shares the date-axis mechanics with timeline.md by cross-reference rather than re-specifying them (date→position math, granularity, pan, RTL all inherited). Two-pane layout with a pinned task-name column (frozen-column technique from data-display.md). Critical path is emphasis (accent), explicitly not status-red, kept distinct from overdue (a bar can be both). Accessibility: mandatory real-table equivalent (role="table"); bars are focusable with dates + dependency in the aria-label; dependencies/critical-path never conveyed by color/line alone. Responsive: falls back to the table on mobile/long plans. Added to 06-components/README.md (file tree + decision map). Resolves the planned-sibling cross-link from timeline.md (now a hard reference).

Notes
- Investigation finding, recorded so PD-132's scope is not re-litigated: the ticket lists six components as undocumented, but verification against the live skill showed three of the six already exist in the library and needed no new file. Chips multi-select → 06-components/selection.md "Multi-select" + "Autocomplete". File uploader → 06-components/inputs.md "File upload". Date picker / calendar → 06-components/inputs.md "Date picker" + "Date range picker". The three genuine gaps — signature pad, timeline, gantt — are all delivered in this block. All six PD-132 components are now documented.
- Remaining PD-132 DoD items before the ticket can close: at least one canonical surface (08-canonical-references/) demonstrating the three new components, and the SKILL.md Step-5.5 / file-tree touch-ups if a canonical is added. The component specs themselves (rules + inline examples) are complete.
- Documentation/component additions only — no token values, no canonical HTML changed yet. ADR 010 not triggered. Additive; the minor version bump the PD-132 ticket calls for lands when epic PD-244 closes (per the accumulate-as-[Unreleased], no-mid-cycle-bump convention) — version remains 1.2.2 for now.

[Unreleased — PD-245 decision]

Changed
- 09-changelog/decisions.md — ADR 011 added. Decision spike on self-hosting Lato 2.0 for a true Medium/SemiBold register resolved as stay on 400/700 (+900 display); do not self-host now. No current token or shipped surface needs 600; self-hosting costs (asset hosting/cache-busting, an @font-face block across every canonical, heavier first paint, divergence from the Google-Fonts link PE relies on) are unjustified by a hypothetical need. Explicit reversal trigger and implementation path recorded in the ADR. 01-foundations/typography.md → "Why only 400 and 700" now points to ADR 011.

Notes
- Documentation/decision only — no token values, no font assets, no canonical HTML changed. ADR 010 does not trigger. PD-245 closes Won't Do (no implementation path taken). Still within the open v1.2 cycle (PD-244); version remains 1.2.2.

[Unreleased — PD-244 universal patterns]

Added
- 06-components/inputs.md → "Per-field translations expander". New component section: a single form field whose default-language value stays primary and always-visible, with a compact collapsed disclosure (🌐 Translations (N)) beneath it that reveals one input row per additional locale. Anatomy + HTML/CSS + behavior + a11y (disclosure aria-expanded/aria-controls; per-locale aria-label; per-row aria-describedby validation) + RTL (per-row dir/font stack) + pitfalls. Fills the gap between the existing two-language side-by-side / stacked authoring patterns and full-document translation mode: this is the 3+ locale, some-fields-localize, keep-the-default-path-clean case used by User Directory custom-field labels, Performance review-template questions, Notification template subjects, and taxonomy names. Uses approved Lucide (globe, chevron-down, plus, x) and existing tokens only; shares the bounded form-column measure (no full-bleed). *Add translation* reuses the menu component (06-components/navigation.md), scoped to the tenant's enabled languages — no free-text locale entry.

Changed
- 02-cross-cutting/multilingual.md → "Bilingual content authoring" gains an "Authoring pattern — per-field expander (3+ locales)" pointer + a decision table (side-by-side / stacked / expander / full-document mode), cross-linking the full spec in inputs.md. Stops the expander being re-derived per product.
- 06-components/data-display.md → new "Row actions (trailing actions column)" subsection in the Table section. Consolidates the table-row-specific rules that were previously unstated and re-derived per surface: the trailing data-no-sort actions column; reveal model (hover-reveal must also fire on :focus-within and stay permanent on touch — hover-only is an a11y failure; always-visible is the admin default); focus return to the originating kebab on menu close; menu anchoring/upward-flip in a scroll container with no scrollIntoView; and the per-row-actions vs. bulk-selection-toolbar distinction. Deliberately does not redraw the menu component (06-components/navigation.md) or the inline-vs-overflow decision (06-components/actions.md) — it cross-links them. 06-components/actions.md cross-reference list now points back to it.

Notes
- Investigation result, recorded so it isn't re-litigated: of the three patterns flagged as skill-patch candidates, only the translations expander was a genuine gap. Sortable-header behavior was already fully specified in data-display.md → "The complete sortable-header pattern" (HTML/CSS/JS, mobile, aria-sort, three-state cycle) — no change made. Kebab/overflow row actions were already covered in substance (actions.md Patterns A/B/C + the navigation.md menu component); only the table-row consolidation above was missing.
- All three changes are documentation/component-spec additions, not token-value changes — ADR 010 does not trigger (no token export or canonical-reference regeneration required). No new tokens, no canonical HTML touched.
- Still within the open v1.2 cycle (epic PD-244); no version bump — version remains 1.2.2, consistent with the email / PD-203 / PD-251 handling above. Foundations-level additions, consistent with the one-design-system rule (no per-product/per-surface skill).

[Unreleased — PD-251]

Fixed
- PD-205 dark-mode accent calibration propagated to the runtime — was documentation-only (PD-251). The PD-205 recalibration (all KC Native dark --kcds-color-primary to OKLCH L=0.55) had shipped into 01-foundations/colors.md and the README.md changelog, but never reached the token export or the canonical references. 01-foundations/tokens.css and 01-foundations/tokens.json still carried the pre-calibration Native dark primaries (grow #0EA5A5, learn #329DFF, perform #6366F1, platform #22D3EE) and a white legacy/orange dark --kcds-color-on-primary. Because product-accents.md and ADR 007 both name tokens.css the single source of truth, every consumer reading the skill correctly got the stale values — which is why a downstream audit flagged canonical v1.2.2 as failing WCAG AA on white-on-primary dark CTAs (Grow 3.02:1, Learn 2.84:1, Platform 1.81:1, legacy orange 2.39:1). Now corrected so the runtime matches the documented design:
- tokens.css / tokens.json: five Native dark blocks set to the calibrated values (grow #0A8282, learn #0874C8, perform #5A5BE5, comply #64748B — floor, unchanged, platform #0A8091) with their hover/active chains; explicit white --kcds-color-on-primary added to each Native dark block; the legacy/orange dark --kcds-color-on-primary flipped to near-black #1F2226 (6.68:1 — the orange-family exception, since calibrating orange to L=0.55 reads brown).
- 01-foundations/product-accents.md: the example dark block updated to the calibrated values (prose already described L=0.55).
- All 18 08-canonical-references/*.html: each embeds the full per-category dark block; every one normalised to match the corrected tokens.css (calibrated primaries + white Native on-primary + near-black legacy on-primary). Several had been half-patched (white on-primary added but old primaries kept) — now consistent.
- Post-fix all five Native dark primaries clear AA with margin (4.64–5.20:1) and the 3:1 non-text floor (WCAG 1.4.11). Light-mode tokens untouched. Full per-category math remains in 01-foundations/colors.md → "Dark-mode accent calibration (PD-205)".

Changed
- 09-changelog/decisions.md → ADR 010: token export + canonical references must be regenerated in the same change that touches a documented token value (closes the documentation-only gap that caused PD-251).

Notes
- Still within the open v1.2 cycle (epic PD-244); no version bump — version remains 1.2.2, consistent with the email / PD-203 handling above. This is a correctness/accessibility fix, not new surface.
- This is an internal KCDS propagation fix, not a K2 defect: the downstream K2 component library already carried the correct PD-205 values (taken from the report directly). The corrected token export now agrees with K2.

[Unreleased — PD-203]

Added
- 08-canonical-references/conversational-ai.html — canonical conversational / AI standalone workspace (Archetype 7). Competency Builder Conversational AI Competency Agent, KC Comply / slate. The fourth, distinct member of the conversational family: unlike the ai-assistant-panel-* overlays (Pattern C) and the chrome-less tna-interview-agent-authenticated modal interview, this is a full-page conversational workspace inside the standard Pattern B shell — the dialogue thread is the primary surface and a trailing context rail holds the artifact the conversation builds (the competency-map draft, grouped, with per-competency source attribution SFIA / O*NET / KC + confidence; the rail mutates live when an inline action card is confirmed). Demonstrates the full conversational component set: AI vs user bubbles, inline expandable tool-call card, citation chip on every factual answer, inline action-confirmation card (confirm mutates the rail, cancel leaves a record — never a modal), confidence clarification (disambiguation chips, not error-styled), ≤3 suggested follow-up chips, typing indicator (animated → static "Thinking…" under reduced motion), dismissible resume banner, role="log"/aria-live thread with Enter-send / Shift+Enter / ArrowUp-edit-last. Dual accent by rule — AI elements use the violet AI accent (--kcds-color-ai-suggestion, a system color), user-side actions use the category accent (slate). Fixed-height shell (.app/.main height: 100dvh, .thread-scroll owns the scroll, composer pinned) so the page never scrolls; carries the full category map (light + dark, light first paint). Built from the lms-admin-dashboard Pattern B shell (copy-then-adapt) with the conversational composition grafted in (PD-203).
- 08-canonical-references/succession-9box.html — canonical matrix/grid-hero dashboard (Archetype 3). KC Perform 9-box talent grid (performance × potential), indigo. A labelled 3×3 matrix whose cells are named talent segments holding employee cards — explicitly not a data table or a dot-scatter. Axis ticks are grid items inside the matrix (Potential ticks share the cell rows, Performance ticks share the columns) so they stay aligned at any cell height; cell tint follows the conventional diagonal value tier via -bg status tokens with neutral borders. Demonstrates hero-element composition (the department filter, legend, and summary KPIs live inside the hero panel; the page's secondary "Succession readiness" surface is a separate card), a working department filter (recomputes per-cell counts + empty-segment state + the Calibrated KPI), cell drill-down into the canonical right-edge detail sheet (segment roster, focus trap, Esc / backdrop / close, focus restore; bottom sheet <md), succession-readiness chips, and the single-column mobile reflow (the 3×3 stacks in grid reading order with per-cell (Performance, Potential) coordinate chips so the matrix model survives — 44px touch targets). Built from the lms-admin-dashboard Pattern B shell (copy-then-adapt). (PD-203)
- 06-components/nine-box.md — the 9-box compound-component spec (axes orientation, default segment labels, value-tier tint rule, cell anatomy, in-panel supporting bits, drill-down, mobile reflow, a11y, tokens). Closes the June 2026 self-audit's S7 finding (the 9-box had no foundations-level spec, so generation fell back to "any dashboard"). First of the domain-specific compound components to land in 06-components/ (the framing fix — these live in foundations, not a per-product skill).

Changed
- 06-components/page-archetypes.md → Archetype 3: added the hero-element composition rule (when the dashboard hero is itself a complex composition — 9-box, heatmap, calibration grid — its filter/legend/stats live inside the hero card; the "multiple cards" rule governs secondary surfaces only) and a canonical-reference pointer to succession-9box.html + nine-box.md. Resolves self-audit S8.
- 08-canonical-references/README.md: entries added for conversational-ai.html and succession-9box.html; the PD-203 "Planned references" note now marks PD-203 complete. SKILL.md: file tree + version-line updated to list all four PD-203 canonicals and the new nine-box.md spec.

Notes
- Still within the open v1.2 cycle (epic PD-244); no version bump — version remains 1.2.2 until the full PD-244 epic completes. PD-203 is now complete: all four uncovered-archetype canonical references have shipped (kanban, document-context wizard, conversational/AI, 9-box matrix). When the v1.2 cycle closes, these Unreleased entries roll into the next tagged patch.
- conversational-ai.html covers the AI sub-type of Archetype 7. The Human-messenger sub-type (read receipts, participant list) shares the thread model with different actor affordances and remains documented-only in 06-components/page-archetypes.md → "Archetype 7".
- succession-9box.html closes self-audit findings S7 (9-box foundations spec) and S8 (hero-element internals vs. the dashboard "multiple cards" rule). The drag-to-recalibrate interaction (moving a card between cells) is intentionally out of scope — a Phase-2 interaction; this reference is the read/triage snapshot.

[1.2.2] — 2026-06-22 (Patch — within the open v1.2 cycle, epic PD-244)

Added
- 08-canonical-references/pipeline-kanban.html — canonical kanban-variant pipeline (Archetype 1). Skills Assessment Engine Assessment Pipeline, KC Grow / teal. Five stage columns with draggable candidate cards, a keyboard-accessible move menu, thin KPI row, filter chips above the board, mobile scroll-snap columns. Carries the full category map (light + dark) (PD-203).
- 08-canonical-references/wizard-shell.html — canonical document-context wizard (Archetype 6), the complement to lms-admin-wizard.html. KC Comply policy-acknowledgment, slate. One centred column: the document (Variant 2-W, light in dark) is the primary surface on top and the current step's action sits in a card directly below it — read first, then act, matching the compliance-acknowledgment convention (Vanta/Drata; DocuSign). Demonstrates the full stepper state set — done / current / future / skipped / error. The step card's fields sync live into the document (PD-203).

Fixed
- Wizard footer pinned under a tall document. Both wizard-shell.html and lms-admin-wizard.html used min-height: 100dvh on the shell, which pins the footer only when the content fits; a document taller than the viewport pushed it below the fold. Changed to height: 100dvh so the content row is the only scroller — bringing both into compliance with the rule already documented in 06-components/page-shell.md ("Shell height is height: 100dvh (definite), never min-height").

Changed
- 06-components/page-archetypes.md: Archetype 1 now points to pipeline-kanban.html (kanban variant); Archetype 6 now points to wizard-shell.html (document-context variant + full stepper state set). 08-canonical-references/README.md: entries added for both references.

Notes
- Part of the v1.2 development cycle (epic PD-244), which is still open. PD-203 covers four uncovered archetypes — two land here (kanban, wizard); conversational-ai (Archetype 7) and succession-9box (Performance 9-box) remain.
- pipeline-kanban.html carries a kanban-local chrome choice — the page header on a white surface block (.pagehead--card) — that is not yet a Pattern B convention; flagged in the reference, pending a system-wide decision.

[1.2.1] — 2026-06-22 (Patch)

Fixed
- Product-accent parity across canonical references (PD-203). The older canonical references (lms-admin-dashboard, lms-admin-detail-page, lms-admin-settings, detail-record-shell, authoring-shell, both ai-assistant-panel-*, all four learner-portal-*, tna-interview-agent-authenticated) shipped only the :root legacy-orange chain and no [data-kcds-product-category] blocks. Cloning one for a non-orange product left data-kcds-product-category inert — the page stayed orange. Every canonical now carries the full category mapping (five categories, light + dark) mirroring 01-foundations/tokens.css, plus the accent primitives the blocks reference. Pages with no category attribute are unchanged. lms-admin-wizard already had the blocks and was left as-is.
- on-primary-tint documented per category (PD-203). 01-foundations/product-accents.md listed only primary/hover/active/fill/tint per category, omitting on-primary-tint, text-link, and border-focus. The omission meant active chips/nav, links, and focus rings kept the root orange on non-orange products. The doc now mirrors the complete per-category set in tokens.css (which was already correct) and documents the dark category blocks. (tokens.css is the source of truth.)
- Pattern B sidenav top spacing (PD-203). Desktop nav groups sit directly inside .sidenav (no .sidenav__body wrapper), so no top padding was applied above the first group and the "WORKSPACE" label sat flush against the brand border. Added .sidenav__brand + .sidenav__group { margin-block-start: var(--kcds-spacing-16); } to the affected canonicals and documented it in 06-components/page-shell.md.

Notes
- Surfaced during the PD-203 kanban canonical build (pipeline-kanban.html, KC Grow / teal). See 09-changelog/decisions.md → ADR for the rationale and the chosen "mirror tokens.css in every canonical" approach.

[1.2.0] — 2026-06-19 (Minor)

Added
- 09-changelog/ block: this CHANGELOG.md (formal release history), decisions.md (architectural decision log, ADR format), and a block README.md documenting when to add a changelog entry vs an ADR (PD-141).

Changed
- Root README.md: the pre-1.0 archival changelog moved here under "Pre-1.0 archive"; the README now links to this file for full history.
- SKILL.md Maintenance section now points to 09-changelog/CHANGELOG.md and 09-changelog/decisions.md.

[1.1.15] — 2026-06-18 (Patch)

Added
- Accessibility baseline completed to full WCAG 2.1 AA in 02-cross-cutting/accessibility.md: the previously-uncovered A/AA criteria (non-text content, orientation, identify input purpose, resize & reflow, text spacing, content on hover/focus, pointer gestures & cancellation, label in name, motion actuation, status messages) plus a full A/AA coverage map (PD-206).

[1.1.14] — 2026-06-18 (Patch)

Changed
- Failure catalogue consolidated: Categories and Index-by-product tables extended through F-049; the avatar-initials failure catalogued as F-049 with its inline reference; stale catalogue counts in SKILL.md synced (PD-135).

[1.1.13] — 2026-06 (Patch)

Fixed
- Form column given a bounded measure (480 / 640 / 720px) so full-width forms stop spanning the whole content surface (PD-229, F-048).

[1.1.6] – [1.1.12] — 2026-06 (Patch series — PD-229 User Directory redesign wave)

Fixed
- Radius scale must be declared in full in :root; an undeclared step silently resolves to 0 (F-047).
- Entity header treated as an identity-card surface; stacked-surface gap range; one divider per boundary; content surfaces are Tier-1 resting cards; table delineation and metric-tile framing; color-collision, table-framing and bounded-search fixes; entity-header back row and tight content gap (F-043–F-047).

[1.1.1] – [1.1.5] — 2026-06 (Patch series)

Fixed
- Browse list/grid card re-layout; collapse-alignment fix; content-surface + section composition rules.

[1.1.0] — 2026-06-09 (Minor — first post-1.0 enhancement release)

Added
- Canonical-reference library bundled and version banner cut to 1.1.0 (PD-129).
- Self-audit protocol established and pilot-run across products; 05-quality/self-audit-protocol.md + report template (PD-131).

Changed
- Three accidental Russian quotes in skill prose translated to English (intentional Cyrillic localization examples preserved).

[1.0.1] — 2026-05 (Patch)

Fixed
- KC logo: agents redrawing the mark instead of copying the canonical asset; logo fixed as a single element with a file reference (PD-94). See ADR 005.

[1.0.0] — 2026-05 (Major — first production release)

Added
- Two production-ready application shells (Pattern A learner, Pattern B admin).
- Five KC Native product identities (Grow / Learn / Perform / Comply / Platform) plus legacy orange for LMS/Portal.
- Light and dark theme as a system-wide setting.
- Seven page archetypes, the core component library, the cross-cutting concerns block, the quality protocols, and per-product context for all KC products.

---

Pre-1.0 archive (0.1 – 0.12.6)

Detailed history of the pre-1.0 releases, preserved verbatim for reference. The surface-area summary in the root README.md is sufficient if you are only adopting a 1.x release.

v0.12.6 — Token indirection bug + dark-theme track invisibility. Two distinct bugs reported on KC Perform TNA AI Insights page; both turned out to share a deeper pattern worth surfacing as a generation-time rule.

Bug #1 — Active nav item uses legacy orange in light theme on KC Native products. On a KC Perform page (indigo primary), the active sidebar item's text and icon render orange (#C75F00) instead of indigo. Leading stripe, background tint, and count-badge fill resolve correctly to indigo — only the text/icon color is wrong. Affects every KC Native product (Grow, Learn, Perform, Comply, Platform). Root cause: the v0.12.3 --kcds-color-on-primary-tint token was bound by indirection — :root declared --kcds-color-on-primary-tint: var(--kcds-color-primary-active), and per-category blocks overrode --kcds-color-primary-active but did NOT override --kcds-color-on-primary-tint, relying on the cascade to carry through. Per the CSS Custom Properties spec, var() substitution is computed-value-time at the declaring element, not at the styled element — so the inherited value on descendants carries the :root-resolved orange primitive, never the per-category override. Verified with a browser test (Chromium: descendant element of <body data-category="perform"> with indirection chain returned the :root-time orange, not the cascaded indigo). The v0.12.3 commit comment claimed "Light theme: resolves to --kcds-color-primary-active via :root binding — current behavior preserved exactly" — that claim is false for indirection between cascade-overridable tokens. The same investigation surfaced two additional tokens with the same bug: --kcds-color-text-link: var(--kcds-color-primary) and --kcds-color-border-focus: var(--kcds-color-primary). Both were declared only on :root with indirection, meaning links and focus rings on every Native page rendered orange instead of the category accent. Three tokens, same pattern, same severity. Fix: bind every per-category and per-theme dependent semantic token as a direct primitive value, never as var() on another semantic. Each of the five Native categories (grow, learn, perform, comply, platform) now redeclares --kcds-color-on-primary-tint, --kcds-color-text-link, and --kcds-color-border-focus directly with primitive values. New rule added to 01-foundations/colors.md — "The Indirection rule — semantic tokens must not point at other semantic tokens through var()" — with the underlying CSS spec reasoning, the audit checklist before adding any new semantic token, and the list of tokens that violated this rule (now fixed) vs tokens that are safely declared with primitives. Audit protocol gains a new High severity finding for "Token indirection between cascade-overridable tokens". Production checklist gains a "Token indirection (v0.12.6)" subsection in Section 5.

Bug #2 — Progress / track backgrounds invisible in dark theme. In dark theme, any horizontal bar using --kcds-color-surface-subtle as track background blends into the panel surface — track is essentially invisible. surface-subtle is #1C2228, panel is #181D22, contrast is 1.06:1 (need ≥3:1 for WCAG 1.4.11 non-text contrast). Affects .prog__track in canonical reference + any consuming bar component (sentiment bars, severity bars, topic frequency bars on TNA insights page). Root cause: the v0.12.1 Rule 1 fix for .prog__track (which was using primitive var(--kcds-gray-200)) chose the wrong semantic token — surface-subtle is sized for "section divider / hover background / table header" (same-plane variation), not for "container with required visible empty state" (different-plane container). Fix: dedicated semantic token --kcds-color-track-bg added to the Surface group. Light value --kcds-gray-200 (#EAEFF3 — current behavior preserved). Dark value #3A424B (1.67:1 vs surface — perceptually visible but technically below strict WCAG 1.4.11 3:1; this is deliberate — see foundations doc for the reasoning about decorative tracks vs state-signaling fills). Applied in both canonical references (.prog__track); guidance added to foundations doc and audit protocol. Production checklist gains a dark-theme visibility check: "Every progress / meter / slider / sentiment / severity bar has ≥ 3:1 contrast against its containing panel OR uses the dedicated --kcds-color-track-bg token." For critical state communication, do not rely on track-vs-surface contrast alone — use numeric label, status badge, icon, or fill color.

The deeper pattern: Both bugs share a generation-time failure mode — silent breakage of semantic tokens that "should" work by the cascade but don't, because the CSS spec's substitution rules don't align with the mental model of token indirection. Bug #1 is the principal-component case (indirection between semantic tokens at different override levels); Bug #2 is the choosing-the-wrong-semantic-token case (using a same-plane variation token for a different-plane container). Both surface in dark theme and in per-category Native pages — places where the cascade should bring the right value through but doesn't. The audit protocol now flags both at High severity.

v0.12.5 — Dark-aware scrollbars. Bug reported: scrollbars render in the OS default style in dark theme — light track, light thumb — producing an obvious visual artifact on dark content. Reproduces everywhere a scroll appears (sidebar body, main canvas, future modals, dropdowns). Root cause: the canonical references had a complete dark-mode token block but never styled scrollbar-color (Firefox) or ::-webkit-scrollbar-* pseudo-elements (Chromium/Safari) — browsers fell back to OS defaults. Fixed by adding a single global block of scrollbar rules to both canonical references (Pattern A and Pattern B), resolving through semantic tokens: thumb = --kcds-color-border-default, track = --kcds-color-surface-subtle, thumb hover = --kcds-color-text-tertiary. Each token already auto-inverts per theme via the existing dark override, so no separate [data-kcds-theme="dark"] scrollbar rules needed — that is the point of doing it through semantic tokens. Style profile: thin, fixed-track (not overlay-only), neutral — visible as a real workspace control but not competing with content. Applied via * selectors so every new scrollable component (modals, dropdowns, code blocks, overflow panels) inherits correct theming. Same audit also caught a latent bug: --kcds-color-surface-subtle and --kcds-color-surface-elevated were defined in the dark override blocks of both canonicals but not in the light root — any component reading them in light theme silently fell back to initial (transparent for background). Both tokens now defined in light root too. Pattern documented in 01-foundations/colors.md → "Scrollbars — themed via semantic tokens" and 08-canonical-references/README.md → "Overflow patterns" item 5. Fix applies to all Pattern A and Pattern B products.

v0.12.4 — Composition decision tree for dashboard archetype. Bug reported in Skills Assessment Engine admin dashboard (KC Perform → indigo): generated row-2col with a short table on the left (Recent employee results, ~5 rows) and a content-heavy rail on the right (4 skill-gap cards + AI insight), leaving a large empty area under the shorter left column — page "sags" in the middle. Class-level bug, not specific to one product or page: any analytical dashboard where the rail-candidate content is content-heavy (ranked items, risk cards, cohort cards, outliers) hits the same composition imbalance. Root cause was two-fold: (1) the dashboard archetype in 06-components/page-archetypes.md described one composition (KPI + main panel + rail) without a height-balance decision tree, so agents copied the familiar layout without evaluating whether it fit the data; (2) the canonical reference 08-canonical-references/lms-admin-dashboard.html showed only that one composition (long courses table + short AI rail), and per SKILL.md's "specification by example" rule agents matched it regardless of prose. Fix in three places: (1) the dashboard archetype now has a required composition-choice step before any layout code is written — agents list planned blocks, estimate rendered heights (table of approximate per-block heights provided), split into main/rail candidates, and apply the rule if main height >= rail height × 1.3 → Composition A; otherwise → Composition B. Composition A (main + side rail) and Composition B (stacked full-width: full-width main + full-width card grid + optional balanced 2-up bottom row) are now both first-class named compositions with diagrams in the archetype doc. (2) The canonical reference now contains both compositions in one file separated by a marked .composition-divider, with data-composition="A" and data-composition="B" data attributes. Composition B example uses a Skills coverage scenario: page header + 4 KPI tiles + full-width Recent assessment results table + full-width 4-up card grid of skill-gap cards + balanced 2-up bottom row (coverage trend + AI insight). New CSS additions: .card-grid (4-up responsive), .severity-card (severity-stripe card pattern with critical/warning/info/neutral variants), .row-2col--equal (symmetric 2-up for balanced bottom rows), .composition-divider (reference-only). (3) Production checklist gains a "Composition balance — row-2col height check" subsection in Section 5: no empty area greater than ~20% of viewport height under the shorter column of any row-2col; if rail content is not at least ~30% shorter than main, page does NOT use row-2col. Verification: regenerated a clean analytical dashboard with content-heavy rail content without hints — outputs now consistently choose Composition B with no empty area.

v0.12.3 — Accessibility fix for active states on primary-tint surfaces in dark theme. Bug reported in Skills Assessment Engine (KC Perform → indigo) admin dashboard: active filter chips, active sidebar nav items, and active pagination pages had dark indigo text on a dark-indigo-tinted-on-dark-canvas surface — contrast collapsed to 2.62:1 (FAIL AA). Primary buttons on the same page read correctly (indigo + white text, 4.5:1+), confirming the bug was in the text-on-tinted-surface relationship, not in primary as a whole. Root cause: --kcds-color-primary-active was overloaded as both "pressed-state button background" and "text/icon color on top of primary-tint surface" — two roles that align in light theme (dark saturated color works for both) but diverge in dark theme (pressed state wants to darken from primary; text-on-tint wants to lift to overcome the tinted-dark composite background). Audit found the same failure mode in 5 of 6 category accents: KC Perform 2.62:1, KC Comply 2.22:1 (already fixed in v0.12.2), KC Learn 3.98:1, KC Grow 3.97:1, KC Platform 4.44:1; only legacy-orange passed (5.25:1). The previous canonical reference patched only the active-sidebar case with an ad-hoc [data-kcds-theme="dark"] .navitem--active override — the same patch had to be re-written for every new component (chip, pager, avatar) and was a per-component maintenance burden. Fix: introduce dedicated semantic token --kcds-color-on-primary-tint ("text/icon color on top of primary-tint or primary-fill surface"). In light theme it resolves to --kcds-color-primary-active via :root binding (light theme behavior preserved exactly). In dark theme it resolves to the *-300 end of each palette family per category (orange-300 #FFB060, teal-300 #5EEAD4, blue-300 #93C5FD, indigo-300 #A5B4FC, slate-300 #CBD5E1, cyan-300 #67E8F9), each verified ≥7.5:1 contrast against the effective tinted-on-dark-canvas surface. Rewrote .navitem--active, .chip--active, .chip--active .chip__count, .pager__page--active, .avatar, .topnav__avatar, .badge--warning to use the new token across both canonical references. Removed the ad-hoc [data-kcds-theme="dark"] .navitem--active and .avatar overrides from the Pattern B canonical. Future components with the same composition (tinted background + brand-color text) work correctly out of the box without per-component dark patches. Documented in 01-foundations/colors.md → "Text on primary-tint surfaces" with a usage table mapping background tokens to corresponding text/icon tokens.

v0.12.2 — Accessibility fix for KC Comply category accent in dark theme. The v0.12 value --kcds-color-primary: #94A3B8 (slate-400, intended as a "lift" of light-mode slate-600) failed WCAG AA contrast at 2.56:1 against white --kcds-color-on-primary — white button labels on KC Comply primary buttons in dark theme were unreadable. Root cause: slate is a desaturated palette family, and the "lift in dark" strategy that works for teal/indigo/cyan/blue doesn't apply — every step lighter from slate-600 drops the white-text contrast below the 4.5:1 floor before the color reads as a brand accent. Fixed by selecting #64748B (slate-500) as the primary — 4.76:1 against white (passes AA), 3.89:1 against dark canvas (reads as accent, not neutral gray). For slate only, hover and active darken (#566377, #475569) instead of lifting, because the palette can't lift without losing AA. This reverses the general "lift on hover in dark" rule for one category, driven by palette desaturation. Documented inline in 01-foundations/colors.md under "Dark product accent". Fix affects all KC Comply products in dark theme: Competency Builder, Compliance Operations Platform, Safety, Employee Onboarding.

v0.12.1 — Maintenance fix for the Pattern B canonical reference. Bug reported in lms-admin-dashboard.html: a functional but empty horizontal scrollbar appeared in .sidenav__body in both themes, both collapsed and expanded states. Root cause was overflow-y: auto without explicit overflow-x: hidden, combined with the ::before pseudo-element on active nav items positioned at inset-inline-start: -12px (extending past the parent's content box). Same audit pass found two additional latent issues: the table inside .panel { overflow: hidden } would be silently clipped on narrow viewports (no horizontal scroll available because the panel clipped it) — fixed by wrapping the table in a .tbl-scroll container. Grid children in .row-2col lacked min-width: 0, meaning wide content (long titles, wide tables) could push the entire page wider than viewport — fixed by adding > * { min-width: 0 } defensive rule. Two Rule 1 (primitive token reference) violations also caught: .prog__track background using var(--kcds-gray-200) (now --kcds-color-surface-subtle), and the collapsed-sidebar tooltip using var(--kcds-gray-950) / var(--kcds-gray-0) (now inline #1F2023 / #FFFFFF for light + a [data-kcds-theme="dark"] override per 06-components/overlays.md tooltip-inversion spec). All four patterns documented in 08-canonical-references/README.md → "Overflow patterns" so they don't regress when the canonical is updated.

v0.12 — Dark theme shipped as a required, system-wide feature. Adds Tier 4 token layer activated by data-kcds-theme="dark" on <body>, cascading over data-kcds-product-category. Both themes ship together — generating only the light variant is incomplete output and fails the production checklist. Every chrome includes a theme toggle (Pattern A: top nav between account and language switcher; Pattern B: top bar between search and notifications) with moon/sun icon convention, localStorage persistence, and prefers-color-scheme fallback. The surface plane inverts (chrome #181D22 on canvas #0F1419), product accent identity is preserved per category (KC Grow stays teal, KC Perform stays indigo, etc.) with -fill and -tint recomputed as semi-transparent overlays on dark surfaces, and status colors lift for dark contrast (e.g., #4ADE80 success on dark vs #00A01A on light) while preserving hue. Shadows degrade to near-invisible on dark — elevation is recommunicated via stepped surface lightness (--kcds-color-surface-elevated). First-week audit found that components referencing Tier 1 -50 primitives directly (icon tiles, day cards, achievement badges, course-card status pills) broke dark theme silently — they rendered as glowing pastel patches on dark canvas. v0.12 adds a "Decorative tiles and badges" semantic group (--kcds-color-tile-*, --kcds-color-surface-tile-day, --kcds-color-achievement-*) with proper dark overrides, expanded Rule 1 in 01-foundations/colors.md to be explicit about this failure mode, added a migration recipe (grep patterns + substitution table) for finding primitive references in existing code, and elevated primitive-reference violations to High severity in the audit protocol. The "light is default, dark is opt-in but always present, never partial" rule is recorded in 00-zero-rules/one-system-one-language.md. The theme toggle spec lives in 06-components/page-shell.md → "Theme toggle in chrome" with the documented Lucide null setAttribute pitfall and its fix. Production checklist gains a "Theme mode" section under cross-cutting concerns (always — no "if applicable") plus a new "primitive reference" check in Colors. Both canonical references ship with working theme toggles. Components reading semantic tokens get dark mode for free; explicit dark-mode tuning is added to inputs (input-on-card collision), overlays (tooltip inverts surface, not the inversion).

v0.11 — Each KC Native product owns its primary action color. Practical testing of v0.10 ("archetype + product accent in six restrained lanes alongside KC orange primary") showed that maintaining orange as universal primary while applying accent only in restrained lanes left products visually similar — peach pills, orange buttons, and orange tints dominated the chrome and overwhelmed the accent's identity work. v0.11 supersedes v0.10: the per-category primary color (KC Grow = Teal, KC Learn = Blue, KC Perform = Indigo, KC Comply = Slate, Platform & Operations = Cyan) is no longer a restrained accent — it is the primary action color for KC Native products. Buttons, focus rings, links, sidebar active state, hover backgrounds, tints all resolve from the product category. KC corporate orange is preserved in two places only: the KC logo mark (as parent-brand anchor across all products) and three legacy products (LMS 3.0, LMS Admin Legacy, Portal Legacy) which preserve historical brand recognition. The "six lanes" framing from v0.10 is retired. Tenant theming for KC Native primary is documented as an open question pending product strategy resolution.

v0.9.1 — Dedicated responsive layout rule added. New file 02-cross-cutting/responsive.md (~280 lines) establishes breakpoint tokens (xs/sm/md/lg/xl/2xl), four responsive strategies (Reflow / Reveal / Transform / Defer), the canonical hamburger-drawer transformation for both Pattern A (top nav → drawer or bottom nav for simpler 4–5-destination apps) and Pattern B (side rail → drawer below md, narrow desktop below lg), table-on-mobile strategies, form rules for small viewports, touch target floors (44×44 minimum on touch input), density × responsive interaction (mobile = comfortable forced, references existing density.md Rule 5), RTL × responsive interaction (logical properties, drawer slide direction, hamburger position, table scroll direction, carousel swipe direction), print/export as a fifth surface, and surface profile per product classifying all 17 KC products into responsive priority tiers (mobile-primary / mobile-supported / desktop-primary / desktop-only). Common failure modes documented (hardcoded pixels, hidden content with no entry point, side rail at 360px, untested RTL, "looks fine on my MacBook" syndrome). Pre-build checklist (7 questions) and production-checklist additions (12 items). SKILL.md updated to register responsive.md in cross-cutting list, surface description, and frontmatter. All 17 products briefed (no change). Responsive is now a first-class system concern alongside accessibility and RTL.