Canvas Design System
Main Site Tokens

Changelog

A log of additions, improvements, and fixes to the Canvas Design System.

August 2026
v2.9.57 — Every component page in the sidebar was a dead link
  • Fixed All 40 component links in the design-system sidebar were dead — and because ds-header.php is included on every design-system page, they were dead from every page, not just one. The nav listed each component as components/<name> while the pages actually live at components/demos/<name>; the router bounced the missing path to /, so clicking any component in the sidebar silently returned you to the homepage. The card grid on component-library.php was unaffected — it already used the demos/ path, which is why the break was easy to miss.
  • Improved The nav slug now matches the real page path for components, as it already did for every other entry. It does double duty as both the link target and the active-state key, so all 47 demo pages had their $ds_page updated in step — verified that each of the 40 still highlights itself in the sidebar.
  • Fixed The Button demo's example linked to /workshops, which does not exist; both the live button and its copyable code sample now point at /library/workshops/.
August 2026
v2.9.56 — Toasts that wait for you, and a truly modal modal
  • Fixed Toast auto-dismiss now pauses while hovered or focused (WCAG 2.2.1 Timing Adjustable) — the remaining time is kept across pauses and resumes when the pointer and focus both leave. Previously a toast with an action button could vanish mid-read or mid-Tab. Covered by tests/toast-a11y.spec.js.
  • Fixed wsModalOpen() now makes the page behind the dialog inert — the focus trap stopped Tab, but screen-reader virtual cursors could still wander the background. Restoration is stack-safe (each modal restores only what it set) and the toast container stays live so toasts fired from modal actions still announce. Covered in tests/modal-focus.spec.js.
  • Improved ws_alert() / ws_banner() now document their HTML-slot contract: $message renders unescaped by design (callers pass <strong>, links) — user-supplied data must be escaped with htmlspecialchars() before passing. The call-site audit found every dynamic caller already does.
July 2026
v2.9.55 — Sixty unnamed buttons, and a ratchet that was counting its own convention
  • Fixed 60 icon-only buttons had no accessible name — a WCAG 4.1.2 Level A failure across 24 files. Every one now carries an aria-label. Worst concentrations: includes/footer/modals.php (11), admin/banners.php and admin/system/banners.php (6 each), facilitator/app.php (6). Note icon() emits a bare <svg> with no <title>, so <?= icon('close') ?> inside a button leaves it unnamed.
  • Fixed check-page.php counted var(--token, #hex) fallbacks as hardcoded hex — the same defect ds-lint.mjs had fixed in 8dcdacfe, so the page ratchet was firing on the codebase's own defensive convention. The rule now strips fallbacks before counting; a chunk carrying both a real hex and a fallback still reports the real one. Baseline re-derived: 5,601 → 4,723 violations across 320 → 311 files, with zero drift absorbed.
  • Fixed The one genuinely alt-less image on the product surface — a JS-built reviewer avatar in includes/ratings-ui.php — now carries alt="" (decorative; the reviewer's name renders beside it). The audit's "94 missing alt" figure was a regex artifact: <img\b[^>]*> truncates at the > inside ?>, hiding any alt that follows a PHP attribute. Real numbers: 1,133 <img>, 40 without alt, 39 of them in ad creative, ebook HTML, or regex literals that merely contain the text <img.
  • Improved All eight TODO: no token match markers cleared from components.css with no visual change: #7F1D1D--toast-bg, #15803D--color-green-700, #B45309--color-warning-darker, plus three comment-only deletions on lines already using tokens. Two were not stale but real token gaps (amber-50 #FFFBEB vs the orange-50 --color-warning-surface; the checkbox-card purple) and are now documented as such.
July 2026
v2.9.54 — The shell arc's missing record, and the review fixes
  • New Retroactive record of the app-shell arc (this entry should have shipped with the branch, per the §15 rule the code review caught): ws_app_bar — the shared document bar under ws_header across Planner, Facilitator, and Synthesize; tokens --app-bar-height, --app-rail-width (320px unified rails), --header-bg, --paper-grid-image; --bg-page moved to #FAFAF9 with the drafting grid; ~575 lines of shell CSS in components.css.
  • New DESIGN.md §12.8 written. synthesize.css and the ws_app_bar docblock cited a §12.8 that didn't exist. It now does: one anatomy, component-owns-the-shell ownership rule, title modes, the single save-state pill, action variants, and the slots-are-for-legacy-JS rule.
  • New tests/header-shell.spec.js — the header migration's missing coverage: seven migrated pages assert exactly one ws_header, zero references to the retired header stack, zero stylesheet 404s; plus shell-token resolution (--app-rail-width = 320px).
  • Improved The identical seven-property interactive transition, repeated verbatim eight times in components.css, is now one definition: --ws-transition-interactive. Byte-identical expansion, so no visual change is possible.
  • Fixed Change-narration comments rewritten as constraints per CLAUDE.md §0 in academy/training/index.php, podcasts/index.php, includes/components/header.php (×2), and platform-tokens.css.
  • Fixed Stale references to the deleted global-header.php removed from the Navigation demo's Files table and corrected in CLAUDE.md §11 Key Files.
  • Fixed Synthesize docs squared with reality: EVAL-BENCHMARK is now the true contract (36 fixtures, new category P row for P-01…P-04 photo/CV traps, High-severity threshold re-based); ROADMAP no longer claims the v2-cv baseline is "pending" (it's committed, from the 16 Jul pre-fix run) and flags that the post-C-01-fix eval run is not yet committed to eval/reports/.
  • Improved synthesize.js: both synthesis success paths now enter results through one enterResults() — the duplicated setState + draft-autosave tail can no longer drift apart.
July 2026
v2.9.53 — The defects the doc pass turned up
  • Fixed Modal focus never entered the dialog. wsTrapFocus() called focus() in the same tick as the .is-open class, but .ws-modal-overlay animates in from visibility: hidden and an unrendered element can't take focus — so the call was a silent no-op and focus stayed on the trigger, outside the trap it had just installed. New wsFocusWhenVisible() waits for the transition. One frame isn't enough: the overlay reports visible at frame 2 while still at opacity: 0.01 and only becomes focusable once painted. Confirmed in headless Chromium, not the preview pane — the pane is itself visibility:hidden and can't measure this.
  • Fixed wsModalClose() now restores focus to the element that opened the modal, guarded on isConnected. Previously focus dropped to <body>.
  • Fixed closable: false now blocks Escape — the template emits data-closable="false" and the document handler honours it. Backdrop dismissal stays governed by backdrop.
  • Fixed wsFilterBarRemove() is now defined in components.js. The filter-bar template had called it since it shipped; nothing implemented it, so every chip remove threw a ReferenceError. Drops one query param, resets page, preserves the rest of the query string and the hash.
  • Fixed ws_progress omits aria-valuenow when indeterminate, per the ARIA spec — it was announcing a definite percentage for work of unknown length. Both progress animations now honour prefers-reduced-motion, matching ws-skeleton.
  • Fixed aria-atomic moved from the toast container onto each toast. On the container it told assistive tech to re-read the whole stack whenever one arrived.
  • Fixed ws_prompt_select renders a real <label for> instead of a <span> — the select had no accessible name, and clicking the prompt did nothing.
  • Fixed ws_chip_input's add button falls back to an aria-label when addText is omitted, so the icon-only form isn't an unnamed button.
  • New tests/modal-focus.spec.js covers all three modal fixes. Note strategist/tests/sections.spec.js is separately broken — it requires js/modules/sections.js, retired in v2.9.51 — so a bare npx playwright test fails before reaching anything else.
  • Improved Corrected a claim in the previous entry's doc pass: ws_chip_input's label is properly bound via for. The unbound-label finding stands for Form Row, Prompt Select, and the two card groups.
July 2026
v2.9.52 — Every component page, one structure
  • Improved All 47 pages in components/demos/ rebuilt to the section order in templates/README.md: When to Use · Variants · States · Real-World Usage · Options · Accessibility · Tokens · CSS Classes · Files. Adoption was 0/47 before this pass — the template existed, nothing followed it.
  • New Accessibility and Tokens sections on every component. Accessibility was present on 5 pages; Tokens on none. Each is written from the template and CSS source, not assumed — including the gaps.
  • Fixed Input documented icon, iconPosition, state, and helper — none are read by input.php. Its select example also passed flat value => label pairs, throwing Cannot access offset of type string on string; ws_input(type: 'select') wants a list of arrays, unlike ws_select().
  • Fixed Navigation described a data-property attribute and .property-switcher-* / .ps-* classes that exist nowhere in header.php. Rewritten against ws_header(?string $section, array $opts), the 17 section keys, and the real .wsh- prefix.
  • Fixed Accordion and Tabs documented arrow-key, Home/End, and roving-tabindex navigation; both JS inits bind click only. Modal claimed focus return to trigger and an inert background; neither is implemented. All now recorded as known gaps.
  • Fixed Filter Bar chips call wsFilterBarRemove(), which is defined nowhere in the codebase — every remove button throws a ReferenceError. Documented, with a working implementation in the usage example.
  • Fixed Unbound labels recorded on Form Row, Prompt Select, Chip Input, Radio Card Group, and Checkbox Card Group — each renders a visible label with no for, fieldset/legend, or aria-labelledby, leaving the control unnamed.
  • Fixed Retired phase hexes removed from Level Up Grid (#0284C7, #7C4DFF, #10B981), Navigation (plus #F87171, #BE123C), Button's var() fallbacks, and Planner Inspector Rail's theming advice. Every phase token resolves to #E54D4D.
  • Fixed Emitted-but-unstyled classes flagged where found: .ws-badge__text, .ws-avatar--initials, .ws-tabs__label, and Input's orphaned .ws-input-wrap__icon--* rules.
  • New Undocumented options surfaced: showHeader and scoreBadge.variant on Energy Arc Card, group_by_phase and phase_copy on Level Up Grid, meta on Planner Card, and the phase variants on Banner. Energy Arc Card's theme default corrected from dark to light.
July 2026
v2.9.51 — Strategist madlib rebuild
  • New strategist.css rewritten for the madlib screen: hero on the Display Text Pattern and a display-scale six-dropdown sentence own the first viewport, with three tool cards + full-width panels and a soft very-light-red exit bar below the fold. Platform tokens throughout; the page sits on the standard paper-and-grid background.
  • New .st-blank is a documented strategist-local control (like st-tabs was): an inline sentence blank that ws_input/ws_select can't express — they render labeled block fields. Baselined in check-page; if a second app ever needs inline blanks, promote it to a ws_* component.
  • Fixed Retired the three-phase shell CSS (docbar, phase tabs, steplist, wizard nav, readiness meter, rail). The st-brief/st-doc document blocks stay — brief-view.php renders with them.
July 2026
v2.9.50 — The icon-ligature sweep, finished (and a guard so it stays finished)
  • Fixed The remaining ligature-named controls in Synthesize: theme disclosure chevrons and theme overflow menus, which announced as chevron_right and more_vert — 22 of the 58 controls on the results screen, all sharing two names. New disclosureAttrs(what, open) emits the label and aria-expanded together, so a toggle can't ship a name without its state.
  • Improved A count rendered in its own span concatenates into the button's name — <span>Themes</span><span>11</span> is announced "Themes11". Where a label and a badge sit in one control, give the control an explicit name with the separator restored.
  • New Regression guard in synthesize.spec.js: it sweeps every visible control on the results screen and fails if any accessible name is a bare snake_case token. Catches new icon-only controls without needing a test per button.
  • Improved Sweep result across the input, review and results screens: 162 controls, none named by an icon. The rule this leaves behind — when a control's only content is icon(), it needs an explicit name; the ligature is not one.
July 2026
v2.9.49 — Icon ligatures are not labels; disabled controls owe a reason
  • Fixed icon() emits the Material Symbols ligature as real text, so any button whose only content is icon('close') announces as "close" — the wrong verb for a destructive control, and identical on every row of a list. New removeLabel(kind, text) in synthesize.js gives each of the seven per-row remove buttons a name carrying its own row's text, trimmed to 60 chars because these are read aloud in sequence.
  • Improved Deliberately not fixed by marking every icon aria-hidden: plenty of controls here carry no other text, so hiding the ligature would leave them nameless. Label the control, don't silence the icon.
  • Improved A disabled control owes the reason it is disabled, in the place people look. Synthesize's Start button has two blocking conditions — too much material already explained itself in an alert; an empty tray explained nothing, and the adjacent hint talked about saving drafts, so the greyed button read as broken. The hint is now conditional and wired via aria-describedby.
  • Improved Placeholder names should look unfinished. "Workshop synthesis" reads like a real title, so a library of them was unsortable; the fallback now borrows the first source's name.
July 2026
v2.9.48 — Synthesize overlays become real dialogs
  • Improved overlay() in synthesize.js now emits role="dialog" + aria-modal="true" on .synth-modal — the panel, not the backdrop, since the backdrop is the click-to-dismiss surface. One helper, so every Synthesize overlay gained it at once.
  • New wireOverlayA11y() names each dialog from its own heading via aria-labelledby rather than a hand-maintained name→label map, and pulls focus in. Two traps worth knowing: several overlays lead with a hidden file input, which silently refuses focus — pick the first visible field and verify focus landed, or the dialog keeps focus on <body>. And because render() replaces root.innerHTML wholesale, focus must be restored on every render behind an open overlay, not just on open.
  • Improved Escape closes the top overlay, with no exemption for focused fields. The usual "let the input's own Escape win" rule backfires here: focus lands in a field on open, so exempting fields meant Escape never closed the dialogs that have one — which is most of them.
July 2026
v2.9.47 — Planner: name the keyboard model, and the recovery route per audience
  • New .toast-undo-hint in css/planner/components/_modals.css — the keyboard shortcut shown beside the toast's Undo button, quieter than the button so it reads as a hint rather than a competing action. Paired with an .sr-only spoken form, since ⌘Z does not read well aloud.
  • Improved A toast action button is a mouse affordance. It mounts at the end of the document, focus is elsewhere, and it auto-dismisses — so a keyboard user cannot realistically reach it. When a toast offers recovery, state the shortcut too.
  • Improved #agendaItems now carries role="list" + aria-label, and each item an aria-describedby naming the keyboard model. The description is deliberately one sentence: it is read on every focus, so the fuller wording lives in the visible Instructions panel instead.
July 2026
v2.9.46 — ws_header: a nav href's fragment is part of its identity
  • Fixed ws_header() compared nav items on path alone, via parse_url(..., PHP_URL_PATH), which discards the fragment. Nine sections build anchor navs from absolute paths — /synthesize/, /synthesize/#how, /synthesize/#app — so all three collapsed to /synthesize and an activeHref of /synthesize/ matched every one, lighting the whole nav. Matching now uses path + fragment.
  • Improved Fragment items are excluded from path matching outright: the server never receives the anchor, so it cannot know which one the reader is on. Dropping them also leaves the fragment-less sibling as the unique match, where the group previously cancelled out as ambiguous and nothing highlighted.
  • Improved Bare #anchor hrefs still resolve to "" and never match — that is why sections written that way (/sidekick/) were already correct, and why the bug looked inconsistent across the platform.
  • Fixed activeHref must name the nav item's href, not the current page's URL. Both Facilitator session pages passed /facilitator/app.php, which appears nowhere in that nav, so they highlighted nothing despite a comment saying "highlight Run Session here".
July 2026
v2.9.45 — ws_header: aria-current, and 'active' means CTA not location
  • New ws_header() emits aria-current="page" on the nav item matching the current path or the page's activeHref. The red highlight was visual-only, so "you are here" never reached assistive tech.
  • Fixed Only one item can ever carry it. Anchor navs whose hrefs all resolve to a single path (/synthesize/, /synthesize/#how) light several items at once; the highlight tolerates that, the accessibility tree does not.
  • Improved The registry's 'active' => true flag paints a section's call to action red — it is not a location marker, and aria-current deliberately does not follow it. Setting it on a plain destination lights two items with two different meanings, which is what happened on templates.php. Use activeHref for location.
  • Improved The planner section's default nav is now Planner / Templates / Saved Agendas, matching the four planner surfaces. It previously said "Launchpad", a name retired when that page became a 301 to brief/.
July 2026
v2.9.44 — Planner: named the Energy score, retired the mixed badge row
  • New .energy-arc__score-label in css/planner/components/_canvas.css — a quiet caption naming the score pill, which otherwise rendered as a bare number discoverable only on hover. Carries aria-hidden, since the button's own aria-label already names the score; without it screen readers hear "Energy" twice.
  • Improved .lp2-option__badge now appears once per row, on the featured card only. Three badges in the same slot encoded three unrelated axes — a recommendation, a method, and a price — so the row read as one comparison it wasn't. One slot, one meaning.
  • Improved Quoted library counts must come from workshopr_count_label() (includes/library-counts.php), never a literal. Four planner pages had drifted to 300+/380+ against a 440-activity library; the helper's docblock already claimed to be the single source of truth, but the call sites had not adopted it.
July 2026
v2.9.43 — Planner: undo control in the toast, named dialog close buttons
  • New .toast-undo-btn in css/planner/components/_modals.css — the Undo control inside the agenda delete toast. Inherits the toast's white-on-blue (~8.6:1), and uses display: inline-flex so min-height/min-width: 24px actually applies; on a plain inline button the min-height is ignored and the target lands under the WCAG 2.5.8 floor.
  • Improved modal-planner.php now emits aria-label="Close {title}" and type="button" on .red-header-modal-close. One template, so all 15 planner dialogs gained a named close button; they announced as bare "button" before. The overlay already carried role="dialog"/aria-modal.
  • Improved Client-side field errors should reuse ws_input()'s own error markup — .ws-field--error, .ws-input--error, aria-invalid, and <p class="ws-field__error" role="alert">. setFieldError() in planner-home.js mirrors it exactly rather than inventing a second error style.
July 2026
v2.9.42 — Synthesize modals: entry animation belongs to opening
  • Fixed .synth-overlay's synth-fade and .synth-modal's synth-pop restarted on every state change behind an open modal, because Synthesize re-renders by replacing the whole of root.innerHTML — the modal visibly flashed and reopened. New .synth-overlay--settled sets animation: none on an overlay that was already on screen when the render started (snapshotOverlays() in synthesize.js), so the animation only plays on the render that opened it.
  • Improved Worth copying wherever a string-rendered surface re-mounts animated chrome. .synth .menu and the AI log (which already carries a comment about this) have the same exposure.
July 2026
v2.9.41 — Synthesize frame: full-height rail, flush surface
  • Improved .sy-rail drops its border and radius and stretches to the full height of the frame (.sy-app moves from align-items: start to stretch). It is no longer sticky: a stretched element has nothing to stick to, so keeping the rail fixed under a long board would mean moving it outside .synth-stage.
  • Fixed Full height needed a definite-height ancestor chain. A percentage min-height resolves against nothing when every ancestor is height: auto, so .synth-stage .synth is now a flex column and .wrap--app / .sy-app pass height down with flex: 1.
  • Improved .wrap--app loses its top padding and trims the inherited 110px bottom pad to --space-6; .sy-main goes to padding: var(--space-6) 0 so content runs the full width of the surface.
  • Fixed The zero top padding has to be restated inside @media (max-width: 640px), where .synth .wrap's padding shorthand resets it at equal specificity.
  • Improved .prio-tray moved below the matrix. Noted as a watch item rather than a clean win: the 2×2 is 543px tall, so a tray of several rows can fall below the fold on a 900px viewport.
July 2026
v2.9.40 — Synthesize adopts the shared components
  • Improved Synthesize's private re-implementations of button, tab, badge, pill, alert, empty state and skeleton are deleted; the app emits the platform class names instead. components.css was already on every page via includes/header.php — the components were present all along, just unused.
  • New wsAlert, wsEmpty, wsSkel, wsBadge, wsPill in synthesize.js, beside the existing icon(). They mirror the markup includes/components/*.php produces, because the PHP helpers can't be called from a client-rendered body. Keep them in step if those templates change.
  • Fixed The .tab collision is gone rather than worked around. Synthesize needed an explicit reset of the global pill rule's radius, shadow, shimmer ::before and hover lift — same specificity, decided only by source order. Adopting .ws-tabs--underline removed the reason for the reset.
  • Improved Two loading messages were wearing .empty. They are transient status, not empty states, and now use .load-hint.
  • Improved What stayed local is now only what carries data-driven colour: .pri-badge and .cat-pill set a background inline from app state, so the rules that remain do nothing but keep the text legible on top of it.
  • Fixed .ws-skeleton sets no display, so it must be emitted as a <div> — the <span> the old skeleton used would collapse to nothing.
July 2026
v2.9.39 — Synthesize app guide + component gallery
  • New design-system/app-synthesize.php — the fourteenth App Guide, and the first to double as a component gallery. Synthesize renders every screen from JavaScript template strings, so it has no ws_* helpers to demo; the page renders its class names directly against synthesize/synthesize.css, which means editing that stylesheet moves the specimens with the app.
  • New Forty specimens across nine groups, each shown in its real states — empty, loading, done, muted, error, and the degenerate cases (no notes, no owner, an overlong source name). Specimens are wrapped in .synth, since the whole stylesheet is scoped under it.
  • New A “Swap Candidates” section pairing each duplicated element with its platform equivalent: .btn.ws-btn, .badge/.pill.ws-badge/.ws-pill, .empty.ws-empty-state, .guardrail.ws-alert--warning, .sy-skel.ws-skeleton.
  • Improved ds-header.php gains a Synthesize entry under App Guides. Strategist is still missing from that nav — noted, not fixed here.
  • Fixed Recorded the one genuine platform gap the gallery surfaced: there is no shared segmented control, and Synthesize, Planner, and Facilitator each ship their own .seg. Flagged as the strongest candidate for a real ws_segmented.
July 2026
v2.9.38 — Synthesize app frame: rail, working surface, AI panel
  • New .sy-app replaces .sy-work as the shell every Synthesize working screen wears: var(--app-rail-width) rail + minmax(0, 1fr) surface, widening to a third 340px column for the AI panel above 1440px. .sy-work__main is now .sy-main and keeps the drafting grid on var(--bg-page).
  • New .sy-ai — a panel that is a grid column on wide screens, a fixed right-edge sheet below 1440px, and a bottom sheet below 1080px. The sheet's top comes from --synth-stage-top, set once per open, so a fixed element can sit under chrome it can't measure.
  • New .sy-tools / .sy-tool — a 38px icon rail with a hover tooltip, replacing the spelled-out .sy-rail--add column.
  • Fixed .synth .tab now resets the global .tab rule's pill radius, shadow, shimmer ::before, and hover lift. Same specificity, so only source order was keeping them apart — Synthesize's tabs are an underline row and now say so explicitly.
  • Improved Retired .uni-drop, .act-table, and .dec-row in favour of .sy-drop, .act-card, and .dec-card — the card forms survive a narrow column, the table did not.
July 2026
v2.9.37 — Synthesize work surface on the page paper
  • Improved .sy-work__main keeps the drafting grid but takes var(--bg-page) (#FAFAF9) instead of the warmer var(--bg-paper), so the centre column and the page behind it read as one sheet rather than two paper stocks.
  • New .sy-rail--add is now a panel on var(--bg-paper-dark) (#F0EBE3) — the same wash the global header wears.
  • Improved Both rails (.sy-rail) picked up the centre column's panel geometry — 1px solid var(--border), --rCard radius, --space-5 padding — so the work screen reads as three panels of one family. Fill is the only thing that distinguishes them: grid paper in the middle, the darker wash on the controls, nothing behind the sources list.
July 2026
v2.9.36 — Planner progress-header buttons on the red token
  • Improved .progress-header-btn (the History / Clean up / AI / Share / Export / Schedule / Delete cluster on the planner's agenda bar) takes its background from var(--planner-very-light) instead of a hardcoded rgba(229, 77, 77, 0.08). Same red family, now a solid #FEE2E2 that matches the soft fills used elsewhere on the platform.
  • Improved Shared ?v= stamp on every planner @import bumped to 20260726a, per the rule in planner-new.css — the imports are cached for 7 days and the entry file's own stamp does not invalidate them.
July 2026
v2.9.35 — Global header background token
  • New --header-bg: #F0EBE3 in platform-tokens.css (mirrored as backgrounds.header in the JSON). The global header now sits a step deeper than the #FEF7F1 page cream, so the chrome reads as its own band instead of bleeding into content. Same value the apps already carry as --color-paper-dark.
  • Improved ws_header() takes the colour from the token in both places it set the old hex — the .wsh-header rule and the inline style attribute the component emits (the inline one wins, so they have to move together). The bg option still overrides per call.
July 2026
v2.9.34 — ws_skeleton workshop-card variant + reduced-motion guard
  • New ws_skeleton(['variant' => 'workshop', 'count' => 3]) — a placeholder that mirrors the saved-workshop card (name, meta row, lifecycle strip, footer action) at the same 12px radius / 18px padding / 12px stack gap the real card uses. count emits sibling cards so it drops straight into an app's own grid. Adopted on planner/planner-home.php, facilitator/facilitator-home.php, and synthesize/synthesize-home.php, replacing three "Loading your workshops…" text lines. New .ws-skeleton-grid helper for pages whose skeleton isn't already inside an app grid.
  • Improved The skeleton shimmer now stops under prefers-reduced-motion: reduce (the placeholder stays visible, holding its "content is coming" status) — an infinite loop is decorative motion per DESIGN.md §7.
July 2026
v2.9.33 — ws_app_bar, one document bar for every tool shell
  • New ws_app_bar() — the bar every app shell wears under ws_header. One anatomy: app label or document title, contextual controls, save state, action cluster. The component owns the shell (60px min-height, red gradient, Fraunces title, 36px action geometry, tooltips); apps pass only their own markup through the leadSlot, center, trailLead, and trailSlot slots. Template in includes/components/app-bar.php, CSS in includes/components/components.css, registered in workshopr-design-system.json.
  • Improved Adopted by all three tool shells, replacing .planner-topbar, .synth-topbar, and .fac-app-bar. Every id and class the apps' JS binds to was preserved; the superseded layout, title, action, and tooltip rules were deleted from the three app stylesheets rather than left to fight the component on cascade order.
  • Fixed Removed the dead $header_variant = 'app' / $header_app_title / $header_app_actions block from facilitator/app.php — an unfinished app-mode header nothing ever read.
July 2026
v2.9.32 — Workshop Record architecture note linked from Decisions
  • New The Design Decisions page gained a Workshop Record section linking the architecture note (docs/workshop-record.md) and the self-contained, theme-aware diagram (docs/workshop-record-diagram.html). Explains the plan spine, the derived Designed → Delivered → Synthesized lifecycle that ws_lifecycle renders, and the federated read model — so the component's stages have a documented source of truth.
July 2026
v2.9.31 — ws_lifecycle workshop journey strip
  • New ws_lifecycle() component — a three-step workshop journey strip (Designed → Delivered → Synthesized). Options: status (designed|delivered|synthesized), variant (compact for card badges, full with an optional next-step cta). Template in includes/components/lifecycle.php, CSS in includes/components/components.css, demo at design-system/components/demos/lifecycle.php, registered in workshopr-design-system.json. Red Unification compliant: completed steps use the very-light red fill with full-strength border, pending steps are neutral outline — state is expressed by fill/weight, never by additional hues.
  • New Adopted on MyWorkshopr workshop cards and the Planner's saved-workshops list, hydrated client-side from GET /api/workshop-record.php?list=1 (lifecycle derived server-side; strips are absent, not broken, when the call fails).
July 2026
v2.9.30 — Facilitator start-agenda adopts the Planner card
  • New .fac-skeleton shimmer primitive (transform-only animation, reduced-motion-safe) plus per-part skeleton layouts — .picker-skeleton, .fac-sidebar-skeleton, .start-agenda-skeleton__*, .start-stat-skeleton, .fac-script-skeleton, .fac-panel-skeleton, and generic .fac-skel-line width helpers. Emitted by the shared FacilitatorSkeletons JS builders so the live app and the /facilitator/loading-states gallery render identical markup.
  • Fixed .fac-live__body gained grid-template-rows: 1fr + min-height: 0 (and min-height: 0 on the three columns) so the left/right columns stretch full height instead of collapsing to a content-sized row.
  • Improved facilitator/css/facilitator.css — the Session Start review list (#start-agenda) now reuses the Planner's .agenda-item card anatomy (type-coloured .item-icon square, .item-time, .item-title, .item-duration-badge) plus the shared ws_activity_badge. Class names mirror css/planner/components/_cards.css but the rules are scoped under #start-agenda so they never leak into the rest of the facilitator. Read-only: none of the Planner card's editing chrome (drag/delete/swap/edit) is carried over.
  • New Facilitator type tint tokens --fac-type-{exercise,icebreaker,break}-very-light (#EFF6FF / #ECFDF5 / --gray-50, mirroring the Planner's --planner-*-verylight). Applied as per-type card shading on #start-agenda .agenda-item[data-type] — very-light tinted background + full-strength type-colour border, matching the Planner canvas cards.
  • Fixed .start-cta__btn--compact no longer shrinks the button — the agenda-header "Start Session" now matches the hero CTA's size (the variant only keeps its header placement, not a smaller footprint). .start-cta is now text-align: right so the hero button shares the agenda's right edge with the header button.
  • Improved --fac-hero-gradient retinted from maroon (#3D0C0C→#6B1717) to an ink gradient (var(--color-ink)→var(--color-ink-secondary), #2C2416→#5C5242) for the start screen's dark hero banner; --fac-hero-dark (live dashboard timer bar) likewise retinted from #3D0C0C to var(--color-ink). .fac-nav (live dashboard bottom bar) background changed from --bg-surface to --fac-ink-faint, with its tool buttons / note button / position / shortcuts text set to --fac-ink for contrast. Added the missing --fac-ink-faint token (var(--color-ink-faint), #A8A29E) to the facilitator ink scale. .fac-nav__tool-btn (Polls/Reactions) and .fac-nav__note-btn (Quick Note) now inherit the .fac-nav__btn (Previous) treatment — white --bg-surface pill, solid --gray-300 border, --radius-lg, --text-meta — so all nav buttons match. Free-floating bar text (.fac-nav__shortcuts, .fac-nav__position) set to white; the pill buttons keep ink labels since their backgrounds are white. Added .fac-nav__btn:not(.fac-nav__btn--primary):hover — the Previous button now hovers to the same red-accent state (--fac-purple border/text, --fac-purple-very-light fill) as the other nav pills; the primary Next button keeps its own red-fill hover.
  • Improved .fac-main (live dashboard script panel) now paints the shared graph-paper grid (ink @ 6%, 24px cells over --bg-page) from css/base/_backgrounds.css, instead of a flat --bg-page fill.
July 2026
v2.9.29 — Agenda Health Check app styles
  • New agenda-check/agenda-check.css — a deliberately thin app-shell sheet (.ac-*) covering only the topbar/shell layout, input screen, dropzone, analyzing spinner, and sign-in gate wrapper. The report itself reuses the already-loaded components.css, _agenda-generative.css, and the .energy-arc-* card from prep.css — no new CSS for the grade card, dimension bars, recommendation rows, or badges.
  • New .ac-grade__letter — an additive Fraunces letter-grade flourish layered on the reused energy-arc card, with a one-time fade/settle entrance (--duration-reveal-lg + --ease-reveal) gated behind prefers-reduced-motion.
July 2026
v2.9.28 — Icon set: calendar_view_day + right_panel_open
  • New Added calendar_view_day.svg and right_panel_open.svg to images/icons/ (official Material Symbols outlines, fill="currentColor") — the icon() helper renders an empty span for missing files, which had left the Strategist doc-bar's rail toggle blank.
  • Improved Strategist's "Open in Planner" CTA is now a ws_icon_button (primary, md) with a CSS data-tooltip + aria-label instead of a labeled ws_button.
July 2026
v2.9.27 — Strategist joins the global header
  • New ws_header gained a strategist section (Plan phase, strategy icon, "Strategist" tag) with Strategist / Plan Agenda nav, and a matching app-switcher entry under Plan.
  • Improved The Strategist page now renders ws_header('strategist') above its locked shell; the shell height accounts for the header (calc(100dvh - 65px)) so the window still never scrolls, and the header joins the app chrome hidden in print.
July 2026
v2.9.26 — Strategist app-shell rework
  • New The Strategist shell is now locked to 100dvh with a grid-paper canvas: a doc-bar (editable workshop name, readiness pill + breakdown popover, save chip, Planner CTA) pins above an always-visible phase journey, with three independently scrolling bands beneath — no window scroll at any width.
  • New Every phase (Buy-In, Scope, Details) now drives a master–detail step list from StSections beside a single-section editor, with tick marks for complete/touched sections replacing the old inline stepper.
  • New The brief rail became a tabbed collapsible panel (.st-rail__tabs — Brief / Documents) that switches to a fixed off-canvas drawer below 1100px, with roving-tabindex keyboard support (arrows/Home/End) on the tab pair.
  • New First-run guidance is now an in-shell start card rather than an overlay.
  • Improved Below 760px the step list becomes a horizontal, scrollable chip row instead of disappearing off-screen.
  • Fixed Swept the dead .st-wizard* rule family (stepper dots, footer, print hide-list entries) left over from the pre-rework layout, plus the inert .st-wizard__next--last class toggle in strategist.js — neither had any surviving markup or styling effect.
July 2026
v2.9.25 — Synthesize on the platform motion system
  • Improved Synthesize micro-motion now pulls from the shared tokens: buttons, icon buttons, action cards, add buttons, and dropzones transition with --duration-fast/base + --ease-out; modals enter with --duration-enter + --ease-spring; menus pop with --duration-fast/base. Reduced-motion zeroing comes free via the token overrides.
  • New The Synthesize landing hero uses the page-reveal regime (--ease-reveal, --duration-reveal(-lg)): title → description → CTAs cascade on load, transform+opacity only, with an animation-duration kill added to the landing's reduced-motion block.
  • New .uni-drop variant of the Synthesize dropzone — a slim horizontal drop-anything target on the input screen (token-spaced, tscale-aware).
July 2026
v2.9.24 — Synthesize landing + app fully tokenized; Red Unification comments corrected
  • Fixed The Synthesize landing (.sy-land) palette now aliases platform tokens (--phase-learn family, --color-ink(-secondary), --bg-page/surface) instead of duplicating hex values; stale "red is a deliberate exception, like Intervention" comments in synthesize/index.php and synthesize.css rewritten to reflect Red Unification.
  • Fixed Remaining off-scale values in synthesize.css moved onto tokens: shadow/radius vars alias --shadow-sm / --radius-sm/xl/2xl, off-scale 7/28/36px spacing snapped to the 4px scale, the roadmap goal-card selection ring uses --accentVL, and the roadmap detail modal's red side-tab border became a quiet bordered wash.
  • Fixed Kanban card titles reference var(--font-heading) instead of a hardcoded font-family. All three Synthesize files now pass the enforcer with zero violations.
July 2026
v2.9.23 — Footer consolidation: ws_footer(), tokenized canon, forks retired
  • New ws_footer() wraps the global footer composite (Level Up grid · Letter CTA · brand bar) and is registered in workshopr-design-system.json; the composite gained a render-once guard so any include combination yields one footer. Documented in DESIGN.md §12.7 with the footer-less app-shell exception (Planner, Strategist) and the BEM naming rule.
  • Fixed The canonical footer's 18 enforcer violations: hardcoded hexes replaced with --bg-paper, --phase-learn(-light), --bg-muted, --color-ink(-muted), --text-inverse, --bg-surface, and --mainsite-gradient; the raw Subscribe button is now ws_button().
  • Fixed Footer legal line contrast: rgba(255,255,255,.4).55 (3.67:1 → ≈5.8:1, AA pass) in both the composite and the legacy stylesheet.
  • Improved includes/footer.php now renders the composite via ws_footer(), putting all legacy-footer pages on-canon; the survey fossil footers (3 files) and the Facilitator Bootcamp footer fork were retired.
July 2026
v2.9.22 — Critique fixes: navy aliases retired, toast side-stripes removed, mobile nav
  • Fixed Red Unification: the legacy --primary-navy and --uh-color-navy aliases now resolve to warm ink (--color-ink), retiring cold navy headings platform-wide; library category chips render brand red instead of raw DB Material hexes; the header's per-phase active-link colors and the purple BETA pill collapsed to the red family.
  • Fixed Toast variants and the facilitator callout dropped the banned side-stripe accent for full light borders on semantic surface tokens.
  • New Both global headers (gn-shell, wsh-header) gained a mobile menu sheet (hamburger toggle, scroll lock, Escape/scrim dismiss, reduced-motion aware) replacing the nav that was display:none below their breakpoints.
  • New includes/library-counts.php: canonical library counts with floors — the single source for every "N+ exercises" claim.
July 2026
v2.9.21 — Strategist app CSS brought fully on-system
  • Fixed strategist/css/strategist.css referenced text-size tokens that don't exist (--text-sm, --text-lg, --text-2xl…), so its font sizing silently inherited. Rebuilt on the real scale (--text-h2/h3, --text-ui/small/meta/caption/micro) during the document-centric redesign.
  • Fixed Strategist focus styles used red outlines; now the platform --focus-ring (sky-blue), the sole sanctioned non-red accent.
  • Improved Strategist status/verdict surfaces now use the semantic surface tokens (--color-warning-surface, --color-success-surface) with text labels, per the color-has-meaning rule.
July 2026
v2.9.20 — Motion cleanup: retire the bounce curve, add press feedback, scope transitions
  • Fixed Purged the banned overshoot curve cubic-bezier(0.34, 1.56, 0.64, 1) (removed July 2026) from circulation: neutralized --transition-bounce in css/tokens/_variables.css, corrected per-app --ease-spring overrides (Tips, Podcasts, Academy, Tips v2) that had subverted the sanctioned token, and replaced the raw literals in css/styles.css, both _modals.css sheets, participant.css, and two planner pages with var(--ease-spring).
  • Improved ws_button now has a :active press scale on the base class (covers all variants); global header icon buttons gained a press scale + transition.
  • Improved Removed transition: all from the shared component library and the planner card/sidebar/modal sheets (~71 rules), scoping each to transform/opacity/color/shadow so state changes composite on the GPU.
July 2026
v2.9.19 — Fix footer overriding secondary button borders
  • Fixed Scoped the newsletter subscribe-button styles in includes/components/footer.php to .cta. An unscoped .ws-btn { border: none } was loading after components.css and stripping the red border from every .ws-btn--secondary on any page that renders the footer.
July 2026
v2.9.18 — Red Unification: retire "plan blue"
  • Fixed Repointed the legacy --planner-blue / --planner-blue-dark / --planner-blue-light aliases in platform-tokens.css to the Learn Red family, so surfaces that load only the platform tokens (e.g. planner/index.php) no longer render the retired plan-blue.
  • Fixed Cleared leftover sky-blue / violet accents in css/planner/launchpad.css, css/planner/briefing.css, and planner/email-preview.php that had only been half-converted to red.
July 2026
v2.9.17 — iOS Companion app added to the design system
  • New Added app-companion.php, the per-app guide for the Workshopr Companion iOS app (React Native / Expo) — mobile palette with swatches, type scale, an iOS component inventory grouped by primitives / Run Mode / Capture / Cards, and an iOS patterns section covering safe areas, tactile press, Dynamic Type, and the "one home, two escapes" navigation model.
  • New Added a companion entry to apps in workshopr-design-system.json, mirroring the shape of the existing app entries plus a platform note flagging it as a standalone native codebase with no CSS token.
  • New Added mobile-ios.md, a concise reference mirroring the tone of theming.md/motion-system.md, pointing to workshopr-companion/DESIGN.md and src/theme/ as the code source of truth.
July 2026
v2.9.16 — Strategist form-field borders
  • Improved Scoped a darker resting border on strategist form fields in strategist/css/strategist.css: .st-app .ws-input / .ws-select move from the platform-default --gray-200 to --gray-400, with --gray-500 on hover. Scoped to .st-app so the shared ws-input/ws-select components are unchanged platform-wide.
July 2026
v2.9.15 — Strategist Buy-In wizard
  • New Added .st-wizard stepper nav and .st-wizard__footer Back/Next bar to strategist/css/strategist.css, splitting the Buy-In phase's five .st-section blocks (in strategist/includes/phase-buyin.php) into wizard steps via .st-step / data-st-buyin-step. Active step uses --phase-learn-dark text on --phase-learn-very-light chip fill; a touched-but-inactive step gets a quieter --gray-200 chip. Step transitions are a 200ms fade+4px rise (.st-step--entering), disabled under prefers-reduced-motion. Labels hide under 860px, numbers remain. Print stylesheet forces [data-st-buyin-step] visible and hides the wizard chrome, matching the existing hidden-phase-panel print pattern.
July 2026
v2.9.14 — Strategist generated documents section
  • New Added .st-sidebar__section / .st-sidebar__heading card and .st-docs button stack to strategist/css/strategist.css, hosting the new Documents section (Executive Summary, Facilitator Briefing, Risk Report, Agenda Blueprint) in strategist/includes/sidebar.php after the Workshop Brief preview. Generated output reuses the existing .st-script / .st-skeleton patterns from the Objection Coach; the section is hidden from print via the existing print stylesheet.
July 2026
v2.9.13 — Strategist recommendation banner
  • New Added .st-reco go/caution/not-yet recommendation banner to strategist/css/strategist.css, hosted at #stRecommendation in strategist/includes/sidebar.php directly above the readiness meter. Status is conveyed by a text label plus a bordered card (--color-success / --color-warning / --gray-200), never by color alone, per Red Unification.
July 2026
v2.9.12 — Global footer Letter CTA form restyle
  • Improved Restyled .cta__input in includes/components/footer.php: solid var(--bg-surface) fields with ink text and var(--shadow-xs) replace the translucent white-on-brown inputs, and field focus now uses the platform sky-blue ring (--focus-ring-color) instead of a blush glow, per the focus-ring exception to Red Unification. Added :focus-visible ring to the footer's local .ws-btn.
  • Fixed The footer now carries a scoped .cta .sr-only fallback so the form's screen-reader labels can't render as visible text on host pages that don't define the class.
July 2026
v2.9.11 — Planner topbar Strategist readiness badge
  • New Added .topbar-strategist / .topbar-strategist-icon / .topbar-strategist-badge rules to css/planner/components/_topbar.css for the planner topbar's Strategist handoff link — a quiet white link with a light-red readiness pill (--phase-learn-very-light ground, --phase-learn-dark text) that appears when the strategist has left a readiness pointer. Tokens only (--space-1, --space-2, --text-micro, --radius-full, --planner-transition); no hardcoded values beyond the topbar's existing white-on-red link convention.
July 2026
v2.9.10 — Strategist standalone shared-brief page styles
  • New Added .st-app--brief-view and .st-brief--standalone rules to css/strategist.css for the public read-only Workshop Brief page (strategist/brief-view.php): centered 720px column with token-based spacing and an unclamped brief body. Tokens only (--space-6, --space-4); no hardcoded values.
July 2026
v2.9.9 — Tips category tints unified to brand red
  • Improved Completed Red Unification (D1) for Tips: the six --tips-cat-1..6 category tints in platform-tokens.css were changed from the legacy purple ramp (#4527A0…#B39DDB) to a brand-red ramp (#7F1D1D · #991B1B · #C73E3E · #E54D4D · #F87171 · #FCA5A5), matching the Intervention/DNA red tint ramps and the already-red app-tips.php guide. Regenerated tokens.dtcg.json; drift check passes.
  • Fixed Tips app: the local --cat-* tokens in css/tips/styles.css (half-purple, half-red) and the --tips-cat-* fallbacks in tips/index.php are now the full brand-red ramp.
  • Fixed Migrated the live category colours: the 13 rows in the tip_categories DB table stored 7 distinct purples (the source of the category card/chip colours) — these were remapped to the brand-red ramp so the Tips feed and category pages render red instead of purple.
July 2026
v2.9.8 — Launchpad choice screen heading alignment
  • Improved Launchpad heading: upgraded .launchpad-choice-screen__title (the "How would you like to build?" h1 page title) from var(--text-h2, 1.5rem) to standard var(--text-h1, 32px), matching the premium page typography of other index headings across the platform.
  • Improved Semantic Card Headings: changed launchpad choice card titles (.launchpad-choice-card__title, e.g. "Build from scratch" and "Generate with AI") from div tags to semantic h1 tags and zeroed their margin-top in CSS to maintain design consistency and search engine metadata structure.
July 2026
v2.9.7 — Saved Workshop & Schedule modal improvements
  • Improved Applied "Ink Muted" (var(--color-ink-muted, #78716C)) icon styling and neutral var(--bg-muted, #F5F5F4) backgrounds to saved workshop/agenda cards across both the Saved Workshops page (planner/saved.php) and the My Library section of MyWorkshopr (myworkshopr/myworkshops.php). Added precise CSS filters for inline img.icon elements to prevent raw black SVG fallbacks.
  • Improved Meta Pills color: set all calendar meta-pills text and icon colors in the "Schedule Workshop" slide-out modal to pure white.
  • Improved Energy Details panel: reduced the width of the expanded energy details dropdown panel (.energy-detail) by 25% (from 920px to 690px) to make the overall canvas layout feel more compact and polished.
July 2026
v2.9.6 — Red Unification cleanup (guide pages + stray gradients)
  • Fixed app-tips.php guide rewritten from the retired Facilitate purple (#7C4DFF) to the Learn Red family — identity swatches, philosophy cards, core palette, the six category tints, tab-strip demo, and Do/Don't now all read red. Notes that four legacy purple --cat-* tints still ship in css/tips/styles.css and are flagged for migration.
  • Fixed app-hybrid.php guide rewritten from the retired Plan blue (#0284C7) to the Learn Red family; the "Do" now points at var(--phase-learn), matching the shipped /toolkits/hybrid/ page.
  • Fixed Finished two half-migrated gradients — collections-tabs.css and _sidebar.css no longer blend brand red into leftover indigo (#6366F1); both are now #E54D4D → #C73E3E.
July 2026
v2.9.5 — ws_task_checklist component (activation flow)
  • New ws_task_checklist — progress-tracked task list for activation/setup flows (helper in helpers.php, template task-checklist.php, CSS in components.css, demo at components/demos/task-checklist.php). Items carry real-data done states, optional phase eyebrows, links on undone items, a dismiss hook (data-checklist-dismiss), and data-task keys for JS enhancement. Sky-blue focus ring, :active tactile feedback, 375px-safe. First consumer: the MyWorkshopr Getting Started checklist.
  • New .topbar-unsaved-pill (planner _topbar.css) — quiet "Not saved" affordance for anonymous builders.
  • Fixed JSON catalog + generated roster updated (55 components); check-drift.php passes.
July 2026
v2.9.4 — Documentation consistency pass, round 2 (canonical docs + motion pair)
  • Fixed /DESIGN.md: frontmatter elevation.colored re-synced to the all-red shipped shadows; motion frontmatter aligned to shipped easing tokens (deleted --ease-bounce removed, --ease-reveal/--ease-spring named correctly); §3 Coach moved to the Reflect row; §7 phantom --shadow-learn--{app}-shadow; §11.8 and §12.6 pre-D1 color copy corrected; §14.3 "cooler product palette" removed; §10.3 gained the scannability and inclusive-by-default rules recovered from taste.md.
  • Improved /motion.md converted from generic template to the dated rank-1 Workshopr mandate: two-regime scoping in the header and Standard Values (page reveals here; 150–300ms UI micro-motion per motion-system.md), stray wrapping code fences removed.
  • Fixed motion-system.md post-shipping prose: reveal ease is a token (--ease-reveal, P1); --ease-bounce moved out of the live spec table (deleted, P2); the --ws-ease-bounce stray corrected from "defines" to "uses — defined nowhere (dangling)"; the participant reduced-motion spin exception marked as documented-intent-only (not implemented in participant.css).
  • Improved theming.md exceptions table records the planner activity-type colors as a sanctioned functional-coding exception; ADOPTION.md font matrix corrected (Tips/Intervention/Podcasts ship Fraunces + Inter; Priority 1 closed); style guide toast snippet (--text-caption, 12px) and radius decision rule (8px buttons per DESIGN.md, shipped 10px flagged) reconciled.
July 2026
v2.9.3 — Documentation consistency pass (post-D1 reconciliation)
  • Fixed workshopr-design-system.json phase mapping: Coach moved from facilitate to reflect (it had inverted the "Coach = Reflect, never swap" rule); DNA marked standalone. check-drift.php passes (54/54 components, 9 apps).
  • Fixed workshopr-style-guide.md reconciled to rank-4: deference banner to /DESIGN.md added; stale pre-unification content corrected (per-phase blue/purple/emerald map, Tips/Podcasts/Coach app blocks, colored shadows, app-tinted focus rings → sky-blue ring tokens, z-index scale → shipped tokens, coach legacy mode tokens marked historical).
  • Fixed platform-color-system.md rewritten to post-D1 reality (was presenting blue/purple/emerald phases and a per-app "exceptions" model as live while labeled Status: Current).
  • Fixed illustration-guidelines.md: wrong ink hex (#1F2937#2C2416), per-app color-variant table collapsed to the unified red family, stale Planner-blue prompt example.
  • Fixed README.md architecture line and counts (54 ws_* helpers, 44 demos in components/demos/); ADOPTION.md internal cool-gray contradiction resolved (≈25 remain in planner trees, not "all replaced"); DOC-TEMPLATE.md stale "Tips purple" exception example; START-HERE.md counts, §15 changelog pointer, and pre-D1 "phase color discipline" wording; theming.md dead motion.md link.
  • Fixed /motion.md illustrative token block aligned to shipped tokens (--duration-reveal 800ms, --duration-reveal-lg 1200ms, --stagger-reveal; deleted-overshoot curve removed); deprecated taste.md/principles.md/forms.md reduced to pointer stubs.
July 2026
v2.9.2 — Audit B1 participant bridge + lint-blind indigo cleanup
  • Fixed Audit B1: css/facilitator/participant.css referenced 22 undefined tokens surviving on hardcoded fallbacks (a future platform token of the same name would silently restyle the page). Added a participant theme bridge (per theming.md's app-alias pattern) that defines them once — neutrals alias exact-match platform tokens, activity/status ramps are participant-specific. Zero visual change (verified via computed values).
  • Fixed Three lint-blind indigo gradients (pre-unification "AI button" styling) that ds-lint misses because indigo isn't a signature phase hex: briefing.css (#536dfe/#4338ca), _sidebar.css and _modals.css (#6366F1) — all repointed to the red family. Zero indigo/violet hexes remain in planner + facilitator CSS.
July 2026
v2.9.1 — Red Unification executed (D1) + audit decisions D2/D3 + motion tokens P1–P4
  • Improved D1 — the entire platform is red, everywhere the system speaks. Aligned the last holdouts: platform-tokens.css section comments and stale /* #7C4DFF */ annotations, the JSON phases block (was still blue/purple/emerald), and the ds-lint.mjs phase map (tips/coach/live now enforce red — lint is 0 violations across 103 files, down from 13 false positives). DESIGN.md §3 and START-HERE.md rewritten: phases are naming-only.
  • Improved D2 — the sky-blue focus ring is documented as the one intentional non-red accent (keyboard visibility against red UI). Do not "fix".
  • Improved D3 — deprecation register added to the tokens header (delete after Aug 2026: podcast platform brands, planner blues, unused gradients/shadows, cool-text tokens, transition shorthands). The semantic component layer + --animate-* are kept as theming/motion hooks.
  • Fixed Five tokens defined twice in :root deduped (warm backgrounds + status inks — audit F2); stale --z-dialog/facilitator annotations corrected (F3).
  • New Motion P1: page-reveal regime tokenized (--ease-reveal, --duration-reveal/-lg, --stagger-reveal), zeroed under reduced motion. P2: --ease-bounce deleted (zero consumers; --animate-scale repointed to --ease-spring). P3: --transition-* deprecated. P4: --ease-spring documented as non-overshooting. DTCG mirror regenerated (347 tokens); drift + DTCG + ds-lint all green.
July 2026
v2.9.0 — Consolidation pass: token audit, templates, theming + motion specs, pattern library
  • New token-audit-2026-07.md — full token audit (344 tokens, 33% unused, shadow vocabularies in participant/planner CSS, 5 duplicate definitions). Three decisions pending (phase-abstraction color, focus ring, unused-token disposition); DTCG mirror regenerated.
  • New templates/ — standard documentation templates (component page, foundation doc) based on the card.php exemplar, plus a .ds-status maturity badge in the ds-header chrome.
  • New theming.md — three-layer theming architecture, the blessed app-alias bridge pattern, and the six-step new-app checklist. D1-dependent sections marked.
  • New motion-system.md — reconciles /motion.md with the animation tokens (two regimes), catalogs the shipped named patterns (enter/exit/pop/live-pulse/progress/nudge/reveal), proposes four motion-token changes (P1–P4).
  • Improved component-library.php is now the Pattern Library: 50 components organized into five problem categories with jump links, honest "docs pending" states for the 7 helpers without demo pages, and a documented app-patterns promotion queue.
  • Improved START-HERE.md links all consolidation artifacts.
July 2026
v2.8.11 — Facilitator wrong-phase purple purge
  • Fixed css/facilitator/facilitator.css still had 78 references to the facilitate-purple tokens (var(--phase-facilitate*, #7C4DFF/#6D28D9) and stale purple fallbacks) that bypassed the app's red-resolving --fac-purple* aliases. All now route through --fac-purple* (→ --mainsite-* red) per the documented all-red exception in apps.facilitator.colorNote; the poll-bar gradient's raw #A78BFA was replaced with var(--fac-purple-dark). ds-lint is now clean for the file.
July 2026
v2.8.10 — Facilitator confirm dialog + panel typography
  • Fixed The Facilitator's reusable confirm dialog (.confirm-card) had no styles at all — it now follows the established modal anatomy (accent icon tile → Fraunces title → muted subtitle → ws_button row), matching the end-session card.
  • Improved Slide-in panel titles (Polls, Reactions) adopt the modal heading treatment (Fraunces, --text-h4); poll form validation renders as an inline .poll-form__error notice (error tokens) instead of a native alert(); native confirm() calls (session resume, agenda jump) replaced with the styled dialog.
July 2026
v2.8.9 — Audit follow-through: lint exceptions, focus traps, demo pages, facilitator red completion
  • Fixed scripts/ds-lint.mjs phase map now encodes the documented app color exceptions (Planner, DNA, Intervention, Facilitator → red; Tips → purple) instead of flagging shipped red as wrong-phase. Full-repo violations dropped from 156 (mostly false positives) to 83 genuine legacy items.
  • New Pre-commit hook (.git/hooks/pre-commit) runs ds-lint.mjs --staged so new CSS drift is blocked at commit time. Note: git hooks are per-clone — re-create after a fresh clone.
  • New Shared wsTrapFocus() / wsReleaseFocus() utility in components.js; ws_modal refactored onto it and the Coach panel + Intervention drawer wired up (guarded, no-op where components.js isn't loaded).
  • New Demo pages for ws_pill, ws_toggle, ws_cta_section, ws_filter_bar, ws_how_steps under design-system/components/demos/, registered on the component-library index (whose cards now link to demos/ — the old links 404'd).
  • Improved Facilitator red completed on remaining surfaces: css/facilitator/facilitator.css, participant.css, and summary.css now resolve accents to --mainsite-* tokens (purple fallbacks removed). Stale "facilitator = purple" comment in platform-tokens.css corrected.
July 2026
v2.8.8 — Facilitator app red confirmed + live poll cards
  • Improved Corrected apps.facilitator.colorNote in workshopr-design-system.json: the ENTIRE Facilitator app (landing and app.php dashboard) is mainsite/Learn red (#E54D4D) — the facilitate purple in the Facilitator PRD is deprecated for this app. facilitator.css keeps the legacy --fac-purple* variable names but resolves them to red. Also updated the phaseColors.facilitate note.
  • New Poll result card styles (.fac-poll, .fac-poll__bar, etc.) in facilitator/css/facilitator.css for the live Polls panel — token-based spacing/color, GPU-friendly (transform: scaleX) vote bars.
  • Improved Facilitator Reactions + Polls panels visual pass: counts and percentages adopt the timer bar's mono voice ('SF Mono', 'Fira Code', tabular numerals); reaction bubbles pulse (scale + dissipating ring, --ease-spring, reduced-motion guarded) when a count rises; poll cards gained LIVE/FINAL chips and leader emphasis — only the leading option renders a fully saturated bar (trailing fills at 30% opacity), with in-place bar updates so votes animate between refreshes.
July 2026
v2.8.7 — Generative agenda renders from ws_* components
  • Improved The Planner's AI Workshop Generator now composes its output entirely from design-system components. A new client renderer (planner/js/modules/agenda-renderer.js) mirrors the ws-card, ws-activity-badge, ws-badge (duration), ws-suggestion-card, ws-stat, ws-alert, ws-empty-state and ws-skeleton markup instead of bespoke .generator-item HTML — and drops all inline onclick in favor of delegated listeners.
  • New Layout-only stylesheet css/planner/components/_agenda-generative.css (imported by planner-new.css) — all spacing/color/radius via platform tokens, type signalled by the activity badge (no colored side-tab), with a reduced-motion-aware on-canvas assembly animation and a GPU-friendly (transform: scaleX) streaming progress bar.
  • Improved The planner's inline "Swap with AI" alternatives now render as ws-suggestion-card via AgendaRenderer.swapAltCard() — removed the bespoke .ai-swap-alt-card markup and its hardcoded inline styles.
July 2026
v2.8.6 — Self-contained global footer + facilitator landing exception
  • Improved The global footer composite (includes/components/footer.php) now self-loads its fonts (Fraunces / Inter / JetBrains Mono) and emits its semantic tokens (--paper, --ink, --display, …) as zero-specificity :where(:root) defaults. Host pages no longer need to copy-paste the token block; pages that define the tokens on :root still win.
  • Improved Documented in workshopr-design-system.json that the Facilitator landing page (/facilitator/index.php) ships mainsite/Learn red (#E54D4D) as a deliberate exception, while the Facilitator app dashboard stays Facilitate purple (#7C4DFF).
July 2026
v2.8.5 — Synthesize header section (red)
  • New Registered a synthesize section in the global header (ws_header) — icon hub, tag "Synthesize", under the REFLECT app-switcher group. The header ships the mainsite red, so Synthesize adopts red as a deliberate accent exception (like Intervention and Tips).
July 2026
v2.8.4 — Audit close-out (JSON component tiers)
  • Improved Promoted the 10 helpers that were only documented as nested convenience/alternatives/related notes to full top-level component entries in workshopr-design-system.json: ws_card_start, ws_card_end, ws_modal_start, ws_modal_end, ws_modal_footer, ws_duration, ws_category, ws_status, ws_icon_button, ws_stats. The drift check now catalogues 49/49 helpers at top level (was 39), so they're discoverable and won't get re-implemented as raw HTML. Closes the last open finding (P1-3) from AUDIT-2026-07-01-app-vs-design-system.md.
July 2026
v2.8.3 — app-tips.php color fix
  • Fixed app-tips.php still showed coral/red. Tips has shipped Facilitate purple (#7C4DFF) as a deliberate, documented exception since at least v2.8.0 (which corrected the JSON's category colors to match), but the app guide page itself still displayed the old coral/red palette. Updated all color swatches, hex displays, the gradient/shadow, the 6 category tints, and prose ("warm coral" / "coral red" / "coral") to the purple values in platform-tokens.css (#7C4DFF / #6930C3 / #E8DEFF / #F3EEFF + --tips-cat-1..6). Clarified the exception note: Tips is Learn-phase content but deliberately ships Facilitate purple, not Learn red.
July 2026
v2.8.2 — app-planner.php color fix
  • Fixed app-planner.php still showed sky blue. The v2.8.0 Planner recolor (blue → Learn red) updated platform-tokens.css and the JSON but missed the Planner app guide page itself. Updated all color swatches, hex displays, the gradient, and prose ("blue" → "red") to #E54D4D/#C73E3E/#FEE2E2/#FEF2F2. Added an explicit note that the Plan phase token (--phase-plan) stays #0284C7 — only the app itself ships red.
July 2026
v2.8.1 — Documentation cleanup
  • Fixed platform-color-system.md was badly stale (last synced Feb 2026) and contradicted the code on five apps (tips shown red, intervention purple, planner blue, dna green, training green). Rewrote it as a lean ~130-line color-architecture doc that points to platform-tokens.css for hex values instead of mirroring them (mirroring was the drift source). Fixed the same stale planner/DNA colors in workshopr-style-guide.md.
  • New DOC-TEMPLATE.md — standard copy-paste templates (Component / Pattern / Foundation) plus shared doc conventions (status + last-updated header, TOC for long docs, second person, maturity indicators) so every DS doc is structured consistently.
  • Improved De-duplicated the entry docs. START-HERE.md is the single router (source-of-truth hierarchy + on-ramps); README.md is now purely the detailed file map and no longer repeats the "what to read" guidance. Fixed stale claims (JSON is hand-maintained not generated; DESIGN.md is intent truth; 12 app guides not 8).
  • Improved Added standardized status / last-updated headers to START-HERE, README, platform-color-system, illustration-guidelines, and a Contents TOC to the long docs. Updated START-HERE's documented color exceptions to include Planner, DNA, and Intervention.
  • Fixed Refreshed the per-app guide pages to match the recolor — app-planner.php → red, app-dna.php → red, app-tips.php → purple — corrected the remaining stale app-color blocks in workshopr-style-guide.md (tips categories → purple, intervention → red, training → red), and fixed app-hybrid.php's stale "aligned with Planner" note (Hybrid uses the Plan phase blue; the Planner app is now red).
July 2026
v2.8.0 — App-vs-design-system reconciliation (audit)
  • Fixed Planner recolored blue → red. The Planner app shipped mainsite/Learn red (#E54D4D) since June 2026 but the DS still said sky blue. Updated --planner-* in platform-tokens.css, apps.planner in the JSON (with a colorNote), and the phase table + a new exception bullet in DESIGN.md. The Plan phase (--phase-plan) stays blue; only the app overrides.
  • Fixed DNA recolored green → red. Same treatment for DNA (--dna-* + 5 category tints, JSON, DESIGN.md). The Reflect phase (--phase-reflect) stays emerald because Coach still uses it.
  • Fixed Tips category colors. The JSON listed a red scale for apps.tips.categories; corrected to the purple scale that platform-tokens.css and the app actually use.
  • Fixed Motion easing contradiction. Canonical reveal/spring ease is now cubic-bezier(0.22, 1, 0.36, 1) across DESIGN.md, the JSON, and motion.md (was split between two curves). Added standard (0.4, 0, 0.2, 1) for micro UI transitions.
  • Improved motion.md rewritten for the real stack — vanilla CSS transitions/@keyframes + IntersectionObserver (it previously documented Next.js/React/Framer Motion/GSAP, none of which this platform uses).
  • New Z-index scale extended to cover what the app actually uses: --z-overlay: 1000, --z-header: 1100, and a high band --z-dialog: 10000 / -high: 10001 / -highest: 10004 (planner live-mode/kiosk). Mirrored in the JSON zIndex.
  • New Extended utility color tokens for values the app was hardcoding: --color-orange-600, --color-green-700, --color-auth-primary, --color-auth-gradient-dark, and purple/orange 100–200 pastels.
  • Improved Aligned css/facilitator/facilitator.css --phase-facilitate fallbacks from stale #7C3AED to the real #7C4DFF. Bumped DESIGN.md last-reconciled to 2026-07-01. Full audit at design-system/AUDIT-2026-07-01-app-vs-design-system.md.
June 2026
v2.7.18 — Intervention accent: purple → red
  • Improved Intervention now uses red (Learn red #E54D4D) as its accent instead of facilitate purple. Updated the --intervention-* tokens (primary/dark/light/very-light/gradient/shadow + 6 category tints) in platform-tokens.css, the apps.intervention block in workshopr-design-system.json (with a colorNote), and the app-intervention.php guide. Drift check passes. Intervention stays in the Facilitate phase but is a deliberate color exception, like Tips.
June 2026
v2.7.17 — My Workshopr header section + self-contained footer
  • New Added a myworkshopr section to ws_header (icon space_dashboard, tag “My Workshopr”, single Dashboard nav link). The title band is enlarged for this section (15px, wider) via a [data-section="myworkshopr"]-scoped rule so other apps are unaffected.
  • Improved The global footer (includes/components/footer.php) now self-loads platform-tokens.css so it renders correctly on host pages (e.g. MyWorkshopr) that don't already include the token sheet. Browsers dedupe the identical href elsewhere.
June 2026
v2.7.16 — ws_header account menu + wired controls
  • New ws_header (includes/components/header.php) gained a logged-in account dropdown (.wsh-header__account / .wsh-header__menu) with avatar, name/email, and links to My Workshopr, My Workshops, Team, Settings, and Sign out.
  • Improved Header controls are now functional: search button opens the site-search overlay (data-search-trigger), the apps grid icon became a gear linking to /myworkshopr/, and Sign In opens the auth modal in place. The component now self-loads its auth-modal and search-overlay dependencies.
June 2026
v2.7.15 — Letter CTA form polish
  • Improved Refined the footer Letter CTA form: input border-radius now matches the button (10px), inputs bumped to 16px / roomier padding (no iOS zoom), added input hover states, a .cta__note privacy line, and a single-column stack under 480px.
June 2026
v2.7.14 — Letter CTA form wired to newsletter API
  • Fixed The Letter CTA subscribe form (global footer + academy/components/letter-cta.php) now submits to /api/newsletter.php with loading/success/error states. Added a .cta__hp honeypot field and .cta__msg / .cta__msg--error status-message styles.
June 2026
v2.7.13 — Larger .section-title display headings
  • Improved .section-title display headings increased ~25%: the clamp(28px, 4vw, 38px) rule (Intervention, Podcasts, Tips) is now clamp(35px, 5vw, 48px); DNA moved --text-3xl--text-4xl; shared-components and Academy use calc(token * 1.25). Small uppercase sidebar/handout labels were intentionally left unchanged.
June 2026
v2.7.12 — Global header label left-aligned
  • Improved ws_header() app/section label (.wsh-header__tag) is now left-aligned (justify-content: flex-start; text-align: left) instead of centered, so multi-line labels like “Facilitator Style Quiz” read cleanly.
June 2026
v2.7.11 — Global header sticky to top
  • Improved ws_header() (.wsh-header) is now position: sticky; top: 0 instead of position: relative, so the global navigation pins to the top of the viewport on scroll. Existing z-index: 1050 (above planner topbar/slide panels, below modals) is unchanged.
June 2026
v2.7.10 — Section hero: book-cover carousel
  • New ws_section_hero() now supports a per-section carousel config (array of {img, href, title}) that renders an auto-advancing book-cover carousel in the visual slot instead of the static illustration. Includes clickable covers, prev/next arrows, dot navigation, pause-on-hover/focus, and prefers-reduced-motion support. CSS/JS are namespaced under .wsh-carousel and self-emitted once. First used by the Academy hero to showcase all six ebook covers. Each slide also supports an optional top-right status pill ({label, tone}available green / soon red).
June 2026
v2.7.9 — Section hero component
  • New ws_section_hero($section) (includes/components/section-hero.php) — section-aware hero from the Figma "Hero — *" frames, with a per-section registry (home, library, academy, tips, planner). Self-emits its CSS under the .wsh-hero namespace so it renders on any page regardless of bundle. Illustrations live in /images/heroes/. Placed on the home, library, academy, tips, and planner-landing pages.
  • New section-hero.php is require_once'd by both helpers.php and components/header.php, so any page with the global header can render a section hero without pulling in the full helpers.
  • Fixed ws_header now establishes a stacking context (position: relative; z-index: 1050) so its app-switcher dropdown clears app chrome (planner topbar/panels) while staying below modals.
  • Improved Tuned ws_section_hero to match the Figma "Hero — Home" frame exactly — light-weight Fraunces title in warm ink (#4D453B) with the red italic accent, bordered badge, gradient primary CTA, and dark (not red) stat figures. Pulled the exact illustration from Figma.
  • Improved Recreated the Library hero from the Figma "Hero — Library" frame — added optional imageRounded (16px) and visualChips (category quick-links under the illustration) to the component; Library now shows Workshops / Icebreakers / Collections / Goals chips.
  • New includes/page-grid.php — a reusable snippet that lays the house graph-paper grid (24px, warm ink, background-attachment: fixed) over the page body background, preserving each page's background-color. Added to the home, library, academy, tips, and planner landing index pages; ws_section_hero also carries the grid so it reads behind the hero.
  • New ws_dna_cta() (includes/components/dna-cta.php) — Facilitator-DNA quiz promo strip from the Figma "dna cta" frame: light-red bar with an overlapping circular archetype badge, red icon chip, title/subtitle, and a "Take the quiz" button linking to /dna/. Self-emits its CSS; ships with the global header.
  • Improved ws_section_hero buttons now accept an optional icon (the Academy hero's "Get the Books" uses it). Synced the Academy hero to its Figma frame (badge "Workshopr Academy", book icon on the primary CTA).
  • Fixed Hero/CTA icons rendered as literal text on pages (e.g. Academy) that use ws_header but don't load includes/icon.php — the header component now loads the inline-SVG icon() helper so component icons always render.
  • Improved The global footer's "Level Up Your Facilitation" section now animates in on scroll — each row fades + rises as it enters the viewport, with cards staggered 70ms within a row (ease-out, ~0.5s). Progressive enhancement via IntersectionObserver: no-JS and prefers-reduced-motion users get the section with no hidden state, and the revealed state is explicit so content is never stuck hidden. Doesn't interfere with the existing card hover-lift.
June 2026
v2.7.8 — Planner recolored to mainsite red
  • Improved The planner phase color is now mainsite red, not the legacy plan-phase blue. _component-bridge.css previously remapped --mainsite-primary → --planner-primary (blue), forcing the whole planner blue. It now points the planner accent tokens (--planner-primary/dark/light/very-light, plus the --planner-interactive* and --planner-blue* aliases) at the native --mainsite-* reds, scoped to body.planner-page/.planner-app-active so it beats the :root token re-imports. Note: aliases declared : var(--planner-primary) at :root are computed there and must be re-declared in the scoped block to recolor.
  • Improved AI Workshop Generator loading state (_generator-modal.css) — heading/subtitle dropped from --text-display/--text-h2 to --text-h3/--text-small, with a pulsing auto_awesome sparkle layered inside the spinner.
June 2026
v2.7.7 — Generator modal type scale
  • Improved AI Workshop Generator modal (css/planner/components/_generator-modal.css) — form labels/inputs/selects were using heading tokens (--text-h2/--text-h3); right-sized to --text-ui/--text-small/--text-meta so controls match the planner UI scale. Added a :-webkit-autofill override so autofilled fields stay on-theme instead of browser blue. Shared planner @import stamp bumped 20260610 → 20260615.
  • Improved Generator output view got the same treatment — agenda item names dropped from --text-h2 to --text-h4, start times / headers / rationale / refine input from --text-h3 to --text-ui/--text-small, the "total" badge became a pill, and the loud salmon (#FCA5A5) refine strip was softened to a light-red bar with a subtle border.
  • Improved Generator error state now matches the loading state — title/body dropped from --text-display/--text-h2 to --text-h3/--text-small, and the icon (which was targeting a never-rendered .material-symbols-rounded) is now a 44px circular error chip. All four generator states — form, output, loading, error — share one type scale and layout language.
June 2026
v2.7.6 — Versioned @imports rolled out platform-wide
  • Fixed Extended the v2.7.5 stale-cache fix to every other CSS bundle with unversioned @imports: css/styles.css (main site), css/coach/coach.css, css/dna/styles.css, css/academy/training.css, css/intervention/styles.css, css/participant/participant.css, css/facilitator/*.css, css/planner/analytics.css, plus the nested token imports (css/tokens/_variables.css, css/coach/base/_variables.css, assets/css/auth-modal.css, facilitator/css/facilitator.css). All imports now carry the shared ?v=YYYYMMDD stamp. Bump the stamp whenever any imported file changes. External imports (Google Fonts) and bundler-managed apps (dna/mobile) deliberately excluded.
June 2026
v2.7.5 — Versioned @imports in the planner bundle
  • Fixed Stale-cache breakage after CSS deploys: the ?v= stamp on planner-new.css never invalidated the files it @imports, and the server caches CSS for 7 days — so production visitors kept week-old partials (collapsed .planner-body flex layout, exposed card edit panels). Every @import in planner-new.css (and the platform-tokens.css import inside base/_variables.css) now carries a shared ?v=YYYYMMDD stamp. Bump the stamp on all imports whenever any planner CSS changes.
June 2026
v2.7.4 — Planner stylesheet consolidation
  • Fixed Made css/planner/planner-new.css the single canonical planner bundle. The partially-gutted planner-v2.css monolith (1,042 DUPLICATE/EXTRACTED markers) was retired and deleted; every selector it still held was already present in the imported component set, except the .sr-only a11y utility which was migrated into planner-new.css. planner/includes/header.php now loads the one bundle on the modular path (the dead planner.css link and the temporary standalone _modals.css patch are gone), and the kiosk/embedded headers were repointed off the retired monolith. Token values unchanged — drift check passes.
June 2026
v2.7.3 — Global 80% text scale
  • Improved Platform text now renders at 80%. Font sizes are rem and spacing is px, so a root html { font-size: 80% } shrinks all rem text while leaving layout intact. Added to platform-tokens.css and both global headers (unified-header.css, academy/global-header.css) to reach pages outside the token chain; the per-app html bases (mainsite, planner, academy, participant, facilitator) were scaled by the same 0.8 so it stays uniform. No token values changed, so the JSON mirror stays in sync (drift check passes). Inline px font sizes on bespoke landing pages are not covered.
June 2026
v2.7.2 — Invalid negative-margin token syntax
  • Fixed Repaired 8 invalid -var(--space-*) negative margins across css/detail-immersive.css, css/styles.css, css/planner/planner-v2.css, css/planner/live-mode.css, and css/academy/styles.css. -var() is not valid CSS, so browsers dropped the entire declaration — most visibly leaving the library detail-page stats card (.immersive-stats-float) fully left-aligned because its margin: -var(--space-8) auto 0 (and with it the auto centering) was ignored. The correct form for negating a token is calc(-1 * var(--space-8)).
June 2026
v2.7.1 — Planner phase-color fix
  • Fixed The planner’s component bridge (css/planner/components/_component-bridge.css) never remapped --mainsite-primary, so the global header and ws_* components fell back to mainsite red (#E54D4D) instead of the planner Plan-phase blue (#0284C7). Added a body-scoped remap (body.planner-app-active) that beats :root and survives the late platform-tokens.css @import in assets/css/auth-modal.css. Semantic danger reds use their own tokens and are unaffected.
June 2026
v2.7.0 — Portable component library (PHP + React)
  • New design-system/components/php/ and design-system/components/react/ — portable implementations of every ws_* component (49) and all 6 documented patterns. PHP ships as namespaced Workshopr\DS\* standalone functions (collision-free with the global ws_* helpers); React ships as typed .tsx function components (Ws<Name> + Ws<Name>Props).
  • Improved Both flavors render the existing ws-* class names from components.css (single source of truth) — no duplicated CSS, no hardcoded colors/sizes/fonts. Shared helpers: _icon.php (icon/cx/attrs/e) and Icon.tsx / cx.ts.
  • New Barrels: php/index.php (requires all 50 components, 59 Workshopr\DS functions) and react/index.ts (52 exports), plus a README.md with usage and a patterns-CSS caveat. All PHP verified with php -l + render smoke tests.
June 2026
v2.6.0 — AI-enablement: enforcer fix, enriched catalog, DTCG export
  • Fixed The design-system-enforcer MCP pointed at a stale /sites/newphp dir where the server file doesn’t exist, so it never launched — the AI’s real-time compliance oracle was dead. Repointed to the absolute platform path (now reads 325 tokens + 49 ws_* helpers). Wired “validate before finishing any UI work” (check_snippet / validate_file / suggest_component) into CLAUDE.md, GEMINI.md, and START-HERE.
  • New generate-catalog.php now enriches components.generated.json with a canonical example, whenToUse / whenNotToUse, an a11y note, and a derived antiPattern per ws_* helper — extracted from the components/*.php demos. It’s now the “how do I use this component” reference for AI (example 41/49, whenToUse 20/49, a11y 6/49).
  • New generate-tokens-dtcg.phptokens.dtcg.json: all tokens in W3C DTCG format with $type inference, $description from CSS comments, and var(){alias} references. Standard format for Style Dictionary, Figma, Tokens Studio, and AI tooling.
  • New design-system/llms.txt — an llms.txt-convention index pointing AI agents at the canonical files, machine-readable sources, rules, and validators. Both new generators have --check modes wired into npm, the CI ds-drift job, and the pre-commit hook.
June 2026
v2.5.2 — Display + timer tokens (font-size scale complete)
  • New Extended the type scale with five above-base tokens: --text-display-lg (3.5rem/56px), --text-display-xl (4.5rem/72px) for large hero headings, and --text-timer-sm/md/lg (4/5/6rem) for the live & run-mode countdown numerals.
  • Improved Tokenized the final 12 held hero/timer declarations. The platform now has zero bare font-size values — every font-size resolves through a --text-* token. check-drift passes; all apps verified HTTP 200.
June 2026
v2.5.1 — Off-scale font-size normalization
  • Improved Snapped 619 off-scale font-sizes to the nearest type-scale step via ds-tokenize-fontsize.mjs --snap. Each becomes var(--text-*, <token-rem>) so the fallback matches the snapped size. Most deltas are sub-pixel; the visible ones are 28px→24px (62×), 22px→20px (46×), 36px→32px, and 40px→46px.
  • Held 12 hero declarations (56–96px / 3.5–6rem) are above the top scale step (46px); the snapper holds anything whose nearest step is >8px away rather than collapsing hero text. These await dedicated display tokens.
June 2026
v2.5.0 — Type-scale tokenization
  • Improved Tokenized 1,635 hardcoded font-sizes to --text-* across 104 stylesheets. Only exact on-scale values were converted (px and rem, parsed unit-agnostically), each retaining its original value as a standalone fallback — e.g. font-size: 14pxfont-size: var(--text-small, 14px). Value-preserving, idempotent, and safe on pages that don't load platform-tokens.css.
  • New scripts/ds-tokenize-fontsize.mjs — exact-match font-size tokenizer. Reports off-scale values rather than snapping them, so no size silently changes.
  • Note ~631 off-scale sizes remain (e.g. 0.8rem, 0.85rem, 17px, 22px, 28px, hero 36–96px). These need a typography decision (snap to the nearest scale step = a visual change) and were deliberately not auto-converted.
June 2026
v2.4.0 — Compliance gate + token cleanup
  • New scripts/ds-lint.mjs — a low-noise compliance gate that fails on three high-signal regressions: cool-gray hex, banned font stacks (Source Sans 3, legacy Bitter/DM Sans), and wrong-phase brand-color leakage. Scopes phase rules carefully (purple is allowed in the blue planner for activity/icebreaker accents; green is never flagged because it doubles as success/complete). Runs via npm run lint:ds, the pre-commit hook on staged files, and a CI job.
  • New scripts/ds-tokenize.mjs — value-preserving hex→token rewriter. Maps grays (warm Stone), ink, semantic status, and brand primaries; resolves #fff by context (color:--text-inverse, else --bg-surface); and skips hexes already in var() fallback position so it never produces redundant var(--x, var(--x)).
  • Improved components.css — 55 bare hardcoded colors tokenized and all 27 cool-grays removed. Several were dead-token fallbacks (var(--color-border, #e5e7eb), var(--color-text, #111827)) referencing undefined variables, so the cool gray was actually rendering; these now resolve to warm Stone / ink tokens. Component demo page verified rendering with zero PHP errors.
  • Fixed Phase-color leakage — Coach mobile app --primary and note-icons moved off mainsite red / planner blue onto Facilitate purple; Tips footer accents moved off red onto Tips purple. Coach, Tips, and Facilitator pages verified at HTTP 200.
  • Fixed Source Sans 3 → Inter across facilitator, myworkshopr, participant, and prep stylesheets (12 declarations), enforcing the Fraunces/Inter mandate. Microsite --font-* definitions confirmed already on Fraunces/Inter (Bitter/DM Sans only survive in comments).
  • Improved Remaining cool-grays cleared from library-goals.css, the shared _sidebar.css, listing-redesign.css, and the DNA mobile reading sheet, then from the consolidated planner tree — zero cool-grays platform-wide.
  • Fixed Resolved the last 22 wrong-phase lint hits. Investigation found these were all intentional danger/CTA reds caught only by their redundant literal #E54D4D fallbacks (facilitator --fac-red = --color-error; planner --planner-red = documented mainsite-CTA alias; --phase-learn status colors). Tokenized them (drop literal, keep the var) for zero visual change; mapped the live-mode --run-danger token to --color-error; and marked the standalone-capable auth-modal CTA with a documented lint exception. ds-lint now clean across all 112 scanned files.
June 2026
v2.3.0 — Consolidation: single entry point + drift guard
  • New START-HERE.md — one entry point with a stated source-of-truth hierarchy (/DESIGN.md + /motion.md for intent; platform-tokens.css + helpers.php for implementation; JSON as a machine mirror) and audience on-ramps for designers, developers, and Claude.
  • New check-drift.php — guards the JSON mirror against drift: fails if any ws_* helper is undocumented in the JSON, or if phase-color tokens disagree between platform-tokens.css and the JSON. Known source contradictions (tips, training) are allowlisted as visible warnings pending a design decision.
  • Improved JSON meta now references the canonical /DESIGN.md and /motion.md, declares itself a hand-maintained mirror (correcting the earlier “auto-generated” claim), and points to the drift guard.
  • Improved README.md now defers to START-HERE.md and corrects the JSON provenance note.
  • Fixed Phase-color records reconciled to the shipped apps: Tips documented as a deliberate Facilitate-purple exception (Learn content, purple brand), and Academy/Training documented as Learn red (#E54D4D) — the unimplemented “training = green” mapping was retired from the JSON, DESIGN.md, and CLAUDE.md §11. Each app now carries a colorNote in the JSON, and both pass check-drift.php without an allowlist.
  • New Added the --facilitator-primary token family (aliased to --phase-facilitate, #7C4DFF) — facilitator was the only app missing its --{app}-primary token. The JSON facilitator color was corrected from the stray #7C3AED to the phase purple, matching coach/intervention.
  • Improved check-drift.php now resolves one level of CSS var() indirection, so phase-aliased app tokens validate. Wired into governance: npm run lint:ds:drift, a ds-drift PHP job in the Design System Lint GitHub workflow, and a staged-file gate in the pre-commit hook.
  • Improved check-drift.php gained a reverse check — a JSON component with no matching ws_* function (renamed/removed) now fails the build — and reports component counts. Corrected stale counts in README.md (39 demo pages, 49 helpers, not “34”/“40+”), and aligned GEMINI.md with the consolidated DESIGN.md (it still pointed at the deprecated taste/principles/forms files).
  • New generate-catalog.php + components.generated.json — a real generator that derives a ws_* component roster (signature, summary, declared options) straight from the helpers.php docblocks. The curated JSON keeps its rich hand-authored option metadata; the generated file is the can’t-drift companion. --check mode fails on a stale roster or a curated signature that no longer matches source, wired into npm run lint:ds:catalog, the CI ds-drift job, and the pre-commit hook. Also added the canonical-source banner to voice.php/philosophy.php pointing at DESIGN.md.
May 2026
v2.2.0 — Token compliance: extended accent + brand tokens
  • Improved Tokenized recurring hardcoded colors across css/academy/styles.css, css/facilitator/facilitator.css, css/planner-new/*, css/styles.css, and css/unified-header.css — raw hex values replaced with platform tokens. Exact color values preserved.
  • New Teal accent tokens for planner secondary actions: --color-teal, --color-teal-dark.
  • New Extended state shades: --color-warning-darker, --color-error-strong, --color-error-darker, --color-info-strong, --planner-accent-dark, --color-success-surface, --color-success-darker, and the soft warning callout surface (--color-warning-surface + -border / -ink).
  • New Meeting-tool brand tokens mirroring the podcast platform set: --platform-meet, --platform-zoom, --platform-inperson (each with -ink / -bg variants where used).
May 2026
v2.1.1 — Planner sidebar: prototype-matched toolbar + flat suggested list
  • New .sidebar-toolbar component for the planner's activity sidebar — sticky search input + pill-style type tabs. Lives in css/planner/components/_sidebar.css (mirrored at css/components/_sidebar.css).
  • New .side__group / .side__group-title / .side__list / .side__more / .side__group-empty structural classes for the flat "Suggested for X" list and "Browse all activities" footer link.
  • New .library-card--lib variant — full-bleed flat draggable card with .lib-card__top (dot + title), .lib-card__meta (pill + duration), .lib-card__dot--{exercise|icebreaker|break}, and .lib-card__pill--{exercise|icebreaker|break} type modifiers. Scoped under .activity-sidebar so it doesn't affect other surfaces that use .library-card.
  • Improved All new card / pill colors pull from existing planner tokens (--planner-exercise-color, --planner-icebreaker-color, --planner-break-color) via color-mix() for tinted backgrounds — no new hex values introduced.
  • New Utility hide rules: .sidebar-section[hidden], .library-card[hidden], .sidebar-sections[hidden], .sidebar-custom-activity-section[hidden], .side__group[hidden], .side__group-empty[hidden]. Lets the filter module + legacy-section wrapper hide nodes via the native HTML hidden attribute.
May 2026
v2.1.0 — Level Up Grid: phase grouping + button --half
  • New ws_level_up_grid() now supports an optional group_by_phase => true mode that renders Learn / Plan / Facilitate / Reflect as their own sub-sections, each with an italic phase title and a half-paragraph intro in Workshopr voice (overridable via phase_copy).
  • New CSS classes for the grouped layout: .ws-level-up__phase, .ws-level-up__phase-head, .ws-level-up__phase-title, .ws-level-up__phase-desc, plus phase-color modifiers (--learn / --plan / --facilitate / --reflect) on the phase block itself.
  • New .ws-level-up__grid--3 modifier for 3-up phase rows (used by Learn and Plan phases). Existing 4-up grid stays the default.
  • New .ws-btn--half width modifier (50%) — sized for narrow card columns where --full reads as too dominant.
  • Improved Responsive overrides updated so both .ws-level-up__grid and .ws-level-up__grid--3 step down 4 → 3 → 2 → 1 column, and .ws-level-up__phase-head stacks below 1024px.
  • Improved Demo: /design-system/components/demos/level-up-grid.php now showcases the grouped variant. Button demo cheatsheet lists --half.
April 2026
v2.0.0 — Planner ws_* Component Migration (Phase 5)
  • Improved Migrated planner/edit.php buttons and form inputs from raw HTML to ws_button() and ws_input()
  • Improved Migrated remaining raw inputs in planner/includes/modals.php — invite email, role select, search inputs, category filter
  • Improved Replaced raw type badges and duration spans in planner/view.php with ws_badge() and ws_duration()
  • Improved Standardized planner/saved.php buttons with ws_button()
  • Improved Migrated schedule panel in planner/planner.php — date/time inputs, timezone select, footer buttons
  • Improved Tokenized inline checkbox styles in save modal to use var(--space-*) and var(--text-sm)
April 2026
v1.9.1 — Planner Brand Color Tokenization
  • New Added --planner-overlay-light/medium/heavy and --planner-backdrop/backdrop-light tokens to planner variables
  • Improved Tokenized standalone #E54D4D (red), #22C55E (green), #9333EA (purple), #F59E0B (warning) hex values across planner CSS to use var(--planner-*) and var(--color-*) tokens
  • Improved Replaced standalone #2563EB in planner cards and generator modal with var(--planner-exercise-color)
  • Improved Tokenized status/semantic colors (warning, error, success backgrounds) in planner-v2.css, analytics.css, exercise-builder.css, briefing.css, live-mode.css
April 2026
v1.9.0 — Cool Gray Eradication & Structural Adoption
  • Improved Eradicated all 354 hardcoded cool gray hex values across 23 CSS files. Entire platform now uses warm stone grays (--gray-50 through --gray-900) exclusively
  • Improved Added helpers.php to global header.php — all pages now have automatic access to ws_* component helpers without manual includes
  • Improved Migrated /contact/ form from raw HTML to ws_input(), ws_select(), ws_button() components
  • Fixed Replaced 6 hardcoded font-family: 'Bitter' in MyWorkshopr CSS with var(--font-heading)
  • Fixed Cleaned up 2 DM Sans font fallbacks in Academy CSS
  • Improved Coach variables now reference var(--gray-*) tokens for text colors instead of cool gray hex values
  • Improved Landing page, auth modal, content gating, and typography base CSS fallbacks updated from cool to warm stone
  • New Added "Touch It, Fix It" convention to Conventions.md for ongoing adoption enforcement
April 2026
v1.8.4 — Live-Mode Font-Size Normalization
  • Improved Normalized all hardcoded font-size values in live-mode.css to design system tokens: compact type scale variables for UI chrome, rem units for presentation display elements, icon sizes preserved as px
April 2026
v1.8.3 — Planner Font-Weight & Font-Size Normalization
  • Improved Converted 9 hardcoded font-size px values to rem units in run-mode.css and workshop-studio.css
  • Improved Replaced all hardcoded font-weight numeric values (400/500/600/700) with design tokens (--font-normal, --font-medium, --font-semibold, --font-bold) across 7 planner CSS files
April 2026
v1.8.2 — Facilitator CSS Hardening
  • Improved Replaced ~25 instances of transition: all in facilitator.css with specific property transitions using design tokens (--duration-fast, --duration-base)
  • Improved Tokenized ~40 standalone hardcoded hex colors to CSS variables with fallbacks (--color-warning-*, --color-error-*, --color-success-*, --color-info-*, --phase-facilitate-*, --gray-*)
  • New Added :focus-visible outlines to all 45+ interactive elements in the Facilitator app (buttons, tabs, cards, inputs)
  • New Added @media (prefers-reduced-motion: reduce) block scoped to .facilitator-app
March 2026
v1.8.1 — Secondary Button Refinement
  • Improved .ws-btn--secondary hover style updated: now uses a subtle background tint (--phase-learn-very-light) and darker text instead of a full solid color fill, matching the academy pattern for a more refined interaction
  • Improved .ws-btn--secondary default background changed from opaque white (--bg-surface) to transparent for better layering on non-white backgrounds
March 2026
v1.8.0 — Semantic Tokens & Cross-App Polish
  • New 40+ semantic component tokens added to platform-tokens.css — buttons, cards, inputs, modals, badges, tooltips, toasts, links, and dividers now have dedicated token sets
  • New Standard suffix convention documented in style guide: -dark, -light, -very-light, -secondary, -muted, -faint
  • New Semantic component token documentation in tokens.php with full usage tables for each category
  • Improved Google Font imports cleaned across 24 PHP templates — removed unused Bitter and DM Sans font families from <link> tags
  • Improved Coach landing pages updated: inline CSS font references migrated from DM Sans to Inter
  • Improved Token count updated from 180+ to 280+ across documentation and hero stats
  • Improved Changelog CSS now uses design tokens instead of hardcoded hex values
  • Fixed Audit score: 87 → 92/100
March 2026
v1.7.0 — Comprehensive Audit & Migration
  • New 6 overlay/backdrop tokens added: --backdrop-light, --backdrop-medium, --backdrop-heavy, --backdrop-brand, --overlay-white, --overlay-surface
  • New Accessible contrast alternatives: --color-primary-on-white (#C73E3E, 5.02:1) and --color-ink-faint-accessible (#78716C, 4.6:1)
  • New Contrast reference table added to colors.php documentation
  • New Deprecation timeline for legacy v1.x tokens — v2.0 sunset plan with console warning phase
  • New components/components.css — dedicated component stylesheet separated from token file
  • Improved Full ARIA + keyboard navigation documentation added to Tabs, Accordion, Tooltip, and Modal components
  • Improved Font migration complete across all microsites: Bitter → Fraunces, DM Sans → Inter in 9 CSS files
  • Improved Planner hardcoded color sweep: 156 hex → token replacements across 9 CSS files (86% reduction, 361 → 49)
  • Improved Modal component documentation now includes parameters table
  • Improved Breakpoint documentation updated from 4 to 6 breakpoints matching platform-tokens.css
  • Fixed 8 cool gray hex values in overview.php and 4 in changelog.php replaced with warm stone palette
  • Fixed --phase-reflect-light corrected to #A7F3D0; missing -very-light variants added
  • Fixed Hero stats corrected: "15 Components" → "33", "100+ Design Tokens" → "280+"
  • Fixed Missing half-step spacing tokens and typography tokens added to documentation
  • Fixed .app-badge component CSS moved out of platform-tokens.css into components.css
  • Deprecated Legacy token aliases (v1.x names) — scheduled for removal in v2.0
  • Fixed Audit score: 62 → 78 → 87/100
March 2026
v1.6.0 — Specialized Components
  • New ws_chip_input() — Multi-value input with removable chip tokens for email lists and tag inputs
  • New ws_radio_card_group() — Single-select card grid with icon, title, and description per option
  • New ws_checkbox_card_group() — Multi-select card grid for choosing multiple options
  • New ws_suggestion_card() — Action-oriented card for AI suggestions and contextual prompts
  • New ws_modal_footer() — Standardized modal footer with primary/secondary action buttons
  • New ws_activity_badge() — Color-coded activity type badge (exercise/icebreaker/break)
  • New ws_results_overlay() — Full-screen/inline overlay for results, scores, and completion states
  • New .ws-toggle — Reusable toggle switch CSS extracted from planner patterns
  • New .ws-chip — Chip markup pattern with remove button for JS-rendered chips
  • Improved Component library grid updated with all 7 new component entries and demo pages
  • Improved CSS uses platform tokens with hardcoded fallbacks so components work outside the planner
  • Improved CLAUDE.md updated with mandatory design system usage rules and full component list
February 2026
v1.5.0 — Developer Experience
  • New Copy-to-clipboard button on all .ds-code blocks (hover to reveal)
  • New Responsive preview toolbar (Desktop / Tablet / Mobile) on component demos
  • New Live demo for ws_hero() — full, minimal, and accent variants with rendered output
  • New Live demo for ws_listing_card() — workshop, exercise, and icebreaker card examples
  • Improved Code blocks now show copy button on hover with "Copied" confirmation feedback
  • Improved Demo containers auto-wrap with responsive preview controls via shared DS footer
February 2026
v1.4.0 — New Components
  • New ws_section_header() — Page/section titles with subtitle, label, and alignment options
  • New ws_feature_card() — Icon + title + description cards with compact and coming-soon variants
  • New ws_stat() / ws_stats() — Single metric display and grouped stat rows with dividers
  • New ws_checklist() — Icon-prefixed lists with custom icons and compact variant
  • New ws_empty_state() — Placeholder with icon, description, and CTA button
  • New ws_breadcrumb() — Accessible navigation trail with separator icons
  • Improved Added animation/transition tokens to platform-tokens.css
  • Improved Swept index.php and about/index.php to use component library
  • Improved Added storybook-style documentation pages for all new components
  • Improved Updated component library grid and sidebar navigation
January 2026
v1.3.0 — Component Library
  • New ws_badge(), ws_duration(), ws_category(), ws_status() — Badge system
  • New ws_button(), ws_icon_button() — Button with variants, sizes, loading state
  • New ws_input(), ws_select() — Form field components
  • New ws_card_start() / ws_card_end() — Card containers
  • New ws_avatar() — User avatars with initials fallback
  • New ws_modal_start() / ws_modal_end() — Dialogs, drawers, bottom sheets
  • New ws_tabs() — Tab navigation
  • New ws_tooltip() — Contextual hints on hover/focus
  • New ws_accordion() — Collapsible content sections
  • New ws_progress() — Progress bars and indeterminate loading
  • New ws_alert() — Notification banners with actions
  • New ws_skeleton() — Loading placeholder system
  • New Toast notification JS (wsToastSuccess, wsToastError, etc.)
  • New Component documentation pages for each component
December 2025
v1.2.0 — Design System Foundations
  • New Design system microsite with sidebar navigation
  • New Color palette, typography, spacing, and elevation documentation
  • New Platform design tokens (platform-tokens.css)
  • New Philosophy, voice & tone, and design decisions pages
  • New Icons reference and accessibility guidelines