Skip to main content

Design System Sync

Specification for wiring the site to UI Design AMADEQ as the single golden rule.

note

Written: 2026-08-08. Source of truth: D:\Web\UI Design AMADEQ (referred to below as DS). Consumer: the frontend workspace of the web-site repository. Status: specification awaiting approval; §7a and §7c record what has since been executed.

0. The core idea

The flow is currently one-directional and the reverse of what it should be: the DS README names the landing page as one of its sources (web-site\frontend\src\styles\tokens.scss), and the DS components landingGoldBtn, landingLightBtn, downloadPill, and glassCard are described as taken from the site's _mixin.scss.

DS law №6 states the target:

Reference → site, never the other way round. The reference is the source; production consumes shared tokens and recipes. Never patch a component with a local literal.

The task is to reverse the flow: make DS the single origin and the site a consumer, so that changing a colour or size in DS propagates automatically to every page.

1. What was measured in the site's current code

Facts, not estimates.

MetricValueWhat it means
Distinct button classes in .scss109The site has no shared button.
Uses of the shared .ui-btn3The existing shared component is effectively dead.
Uses of --btn-h / --btn-radius2The button tokens do not work.
Hard-coded font-family literals178Typography is not driven by tokens.
Ad-hoc gold literals (hex + rgba)≈146A direct violation of law №2.
Of those, the wrong gold #e6bb4c / rgba(230,187,76)9Drift from the canonical #e6b84c.
rgba(255,255,255,.66) as a text colour43White instead of Alice Blue.

Base typography in globals.scss:

body { font-family: var(--font-brand); color: #ffffff; }
  • --font-brand = Space Grotesk → the base body font matches the DS --amq-font-ui. This is correct.
  • color: #ffffff → DS says --amq-text: var(--amq-alice) = #e7f0fa. This is the "wrong kind of white" in the text.

1.1 Font-name collision

Important, but not a visual bug.

SiteDS
--font-brandSpace Grotesk
--font-uiAlexandriaSpace Grotesk (--amq-font-ui)
Alexandria (--amq-font-title)

The names are inverted: the site's --font-ui is in fact the DS title font. Visually everything may currently be correct; the risk is purely that a mechanical name-based merge would swap the fonts across the whole site. The merge is therefore done by value, not by name.

2. What can be ported safely

None of this changes geometry — it only brings values to the canon.

  1. Colour primitives. --c-gold-*, --c-prussian/baltic/cool/alice become aliases of --amq-*. This fixes the 9 wrong-gold cases for free.
  2. Shadows and glass. --sh-default/hover/active and --landing-glass-shadow match --amq-sh-* / --amq-glass-shadow byte for byte — a pure alias swap, zero risk.
  3. Landing radii. --landing-card-radius: 20px and --landing-control-radius: 32px already exist in DS as --amq-landing-card-radius / --amq-landing-control-radius.
  4. Landing type scale. --fs-h1/h2/body/small and --lh-tight/normal match --amq-fs-* / --amq-lh-* exactly.
  5. Container and gutter. --container: 1120px = --amq-container; --landing-scene-gutter: 64px = --amq-landing-gutter.
  6. Text colour. #ffffffvar(--amq-text); rgba(255,255,255,.65)var(--amq-text-muted). This is the visual improvement being asked for.

3. What can be ported, but only in stages and with review

  1. Buttons. This is the main trap. DS carries two different scales:

    • the service scale (buttons.primary: py=4 px=8 r=12) — the dense application UI;
    • the landing scale — law №10: "on the landing page the base button height is 48px".

    The service 4/8/12 must not be dragged onto the landing page mechanically — it would destroy the marketing CTAs (in Figma they are 56 px: Reserve 528×56, Try Live Demo 250×56). Reductions must be targeted and deliberate, not a global rule.

  2. Collapsing 109 buttons into one implementation (law №5). This is the largest value and the largest risk. It is done section by section, with a visual check of each section, never in one sweep.

  3. Spacing. Law №1 forbids 12 and 20 outside the 4/8/16/24/32 scale. The site has --btn-py: 12px. But DS itself sanctions --amq-landing-btn-radius: 20px, so the landing scale is softer. A decision is needed on how strictly law №1 applies to the landing page.

4. What cannot be ported, and why

  1. DS components the site does not haveagentCard, sceneTimeline, wizardPill, studyStatusCard, bottomTabBar, and so on, about 45 recipes. These are recipes for the application, not the landing page. There is nowhere to port them.

  2. The DS engine (AMQ.rc() / AMQ.patch(), localStorage overrides) is the design-system editor's own infrastructure. The site runs React/Vite and neither needs it nor benefits from it.

  3. Conic button strokes. They live only in the site's _mixin.scss ($fs-stroke-gold, $fs-stroke-signin, …) and are tied to specific button sizes from Figma, since the angles are computed from width and height. DS only references them and does not own them. They cannot be moved into DS without losing precision — a DS gap, see §7.

  4. Breakpoints in media queries. DS exposes --amq-bp-* as CSS variables, but CSS custom properties do not work inside @media. The SCSS $breakpoints map in _mixin.scss has to stay; it can only be synchronised manually or by script, never by alias.

  5. Everything outside the landing page and outside this session. Profile, chat, studio, and marketplace have their own .module.scss. Touching them now is out of scope and risks breaking a working product.

5. Architecture: change it in one place, and it changes everywhere

D:\Web\UI Design AMADEQ\css\tokens.css ← THE single source
│ npm run tokens:sync (copies + verifies)

frontend/src/styles/amadeq-tokens.css ← generated, do NOT edit by hand
│ @import first, before everything else

frontend/src/styles/tokens.scss ← ALIASES onto --amq-* only


every .module.scss ← consumes semantic variables

Three mechanisms keep the system honest:

  1. npm run tokens:sync — copies tokens.css from DS into the site. Change a colour in DS → one command → the colour changes everywhere.
  2. npm run tokens:check — fails if the copied file has diverged from DS, so nobody edits the copy by hand. Suitable for CI.
  3. npm run tokens:audit — finds new ad-hoc literals (gold hex values, font names, rgba(255,255,255,…) used as a text colour) and prints them as a list. This is the safeguard against drift returning.

6. Work plan with self-verification

Every stage has a measured check rather than an eyeball one, per DS law №11 ("no blind visual edits").

Stage 0 — baseline snapshot, before any change

  • Capture getComputedStyle for a reference set of elements (section headings, all CTAs, cards) at 1920/1440/768/375.
  • Self-check: the snapshot is saved to docs/ds-sync-baseline.json.

Stage 1 — token infrastructure, visually a no-op

  • Add amadeq-tokens.css plus the three npm scripts.
  • Rewrite tokens.scss as aliases with identical values.
  • Self-check: a repeat snapshot matches Stage 0 byte for byte. Any difference is an aliasing error.

Stage 2 — text colour and gold, the first visible change

  • #ffffff--amq-text, rgba(255,255,255,.65)--amq-text-muted.
  • The 9 cases of #e6bb4c--amq-gold.
  • Self-check: tokens:audit reports 0 wrong golds; text-to-background contrast is computed programmatically and stays ≥ 4.5:1 (WCAG AA).

Stage 3 — typographic roles

  • Introduce role classes per law №14 ("an element takes a role whole — both size and colour"): section heading, card heading, body, label, caption.
  • Self-check: no font-family literal remains in the changed files; the count of 178 must drop.

Stage 4 — buttons, section by section

  • Revive .ui-btn as the single implementation, converting one section at a time.
  • Take sizes from the landing scale (48/56), not the service scale (4/8/12).
  • Self-check: after each section, measure the height and padding of every button in it; none changed outside the intent; the count of 109 drops.

Stage 5 — final verification

  • tsc -b, vite build, eslint src — all exit 0.
  • A pass at 1920/1440/768/375, compared against the Stage 0 snapshot.
  • Bring up the port and demo it. Do not push. Commit to Vlad.

7. What the design system is missing

Real gaps, visible specifically from the consumer side:

  1. No landing-button tokens. Law №10 says "48px", but no --amq-landing-btn-h / -px / -py exists, so the site has to keep its own. This blocks the main requirement of changing button size centrally.
  2. No gradient-text tokens. The landing page depends on gradient headings ($grad-white, $grad-whiteGray), which DS does not have at all.
  3. No ownership of the conic strokes. DS describes landingGoldBtn, but the gradient itself stayed in the site. A stroke generator driven by width and height is needed.
  4. No focus-visible token. There is activeOutline for selection, but nothing for keyboard focus — an accessibility hole.
  5. Breakpoints are not consumable. --amq-bp-* as CSS variables do not work in @media; an export to SCSS/JS is needed.
  6. No disabled state for the landing page — the service buttons have one, the landing buttons do not.
  7. The font-naming conflict with the site (§1.1). DS should fix canonical names so consumers stop inventing their own.

7a. Completed — pass of 2026-08-08

Decisions taken: scope is the landing page, 7 sections; reduce height and padding; apply law №1 strictly. Clarification: law №1 covers gaps, padding, and margins; radii are governed by law №4, and DS sanctions the landing radii with its own tokens, so the 20/32 px radii stayed.

Infrastructure. frontend/scripts/design-tokens.cjs plus the npm scripts tokens:sync / tokens:check / tokens:audit. src/styles/amadeq-tokens.css is a generated copy of the DS :root (119 tokens), imported first in main.tsx. The DS @font-face block is deliberately not copied: DS ships local woff2 files while the site loads the same families from Google Fonts. tokens.scss is now an alias layer; every value DS does not yet have is marked // GAP.

Measured changes (1920×1080, before → after):

ElementBeforeAfter
body colour#ffffff#e7f0fa (Alice Blue, canonical)
Hero CTA ×256 h · 32 px · Alexandria · pad 12/32–3648 h · 24 px · Space Grotesk · pad 8/32
"Launch demo"65 h · 48 px · pad 6.5/2051 h · 24 px · pad 8/32
Collaboration form ×347 h · 32 px · Alexandria · pad 4/1240 h · 16 px · Space Grotesk · pad 4/16
Application pills ×445 h · 24 px · Alexandria · pad 8/1240 h · 16 px · Space Grotesk · pad 8/24
Landing headingsSpace GroteskAlexandria (canonical, scoped to the 7 sections)

A side bug found and fixed: .demoButton had font: var(--font-ui) — an invalid font shorthand (a family only), so the rule did nothing at all and the label silently inherited the body font.

Checks: tsc -b ✅ exit 0 · vite build ✅ exit 0 (7.04 s) · eslint src ✅ exit 0 · tokens:check ✅ in sync · tokens:audit0 wrong golds in the landing scope, with 48 positions of existing debt remaining (31 ad-hoc golds, 15 whites used as text colour, 2 hard-coded fonts).

Deliberately left alone:

  • Conic button strokes. $fs-stroke-trydemo computes its angles for 250×56 and $fs-stroke-reserve for 528×56. Measurement showed that in the Ukrainian locale those buttons are already 330.7 and 599.4, so the angles did not match even before these edits. This is a pre-existing problem; touching it would mean guessing.
  • Header buttons (Sign in / Sign up, 31 px) — already compact and not covered by the "too big" complaint. Their font is Alexandria instead of the canonical Space Grotesk, which remains debt.
  • Heading colour #fff2c2 (Lemon) → canonical #e6b84c (Gold). That is a noticeable change across the whole landing page which cannot be verified by screenshot (the browser panel does not composite frames), so it is left to the owner's decision.

7c. Owner decisions — 2026-08-08, pass 2

QuestionDecisionWhat was done
tokens:sync after the DS updateRun it119 → 120 tokens; semantically two lines (--amq-danger-text, --amq-status-risk); no visual impact, since the token is not consumed by the site. tokens:check exit 0.
Button typefaceAlexandria--btn-font: var(--amq-font-title). Measured: 8 standard buttons render in Alexandria and the geometry 44/4·16/r22/16 px did not shift. A deliberate deviation from DS — DS needs updating.
Heading colourKeep Lemon #fff2c2No change. Rationale: the headings are gradient, and DS assigns Lemon to "gradient tops", so the current state is canonical.

7b. Temporary first-screen tuning panel

http://localhost:5173/?tuner=1 is a floating panel that edits the real page rather than a mockup: every control writes a CSS variable on :root, so the Hero and header rebuild live. "Copy changes" returns only what differs from the canon, ready to paste into tokens.scss.

Code: frontend/src/components/PageTuner/ — the panel was rebuilt from scratch on 2026-08-09, and the previous FirstScreenTuner/ was deleted (backup: D:\Web\_amadeq-backup\tuner-2026-08-09\). The full specification and its ten laws are in Page Tuner. It renders only under ?tuner=1 (the condition lives in LandingPage.tsx), so it does not appear in normal use — but it is not excluded from the production bundle, because the import is static; see Page Tuner §8.

This is a temporary tool — delete it together with its mount condition once the values are agreed.

For this purpose, the first screen's geometry was lifted out of the section styles into --fs-* variables, with identical values and no visual change:

GroupVariables
Logo--fs-logo-w/-h/-x/-y
Header--fs-center-y, --fs-right-y/-x, --fs-nav-gap
Heading--fs-title-x/-y/-fs/-lh
Hero button block--fs-cta-h/-pad-y/-gap
Button (site-wide)--btn-h/-px/-py/-radius/-fs

Logo measurements (1920×1080): the box is 550 × 128, viewBox is 0 0 550 128, scale 1:1; getBBox equals the whole viewBox, so there is no transparent padding inside and the edge of the "A" glyph is the edge of the box. The offsets from the page edges come not from container padding — every ancestor has padding: 0 — but from position: absolute; left: 68px; top: 19px on .left.

warning

68 / 19 do not sit on the 4/8/16/24/32 scale (law №1), whereas the canonical landing gutter is --landing-scene-gutter: 64px, and the heading below the logo sits exactly at 64. The logo is therefore 4 px to the right of the rest of the grid. This was not corrected unilaterally — it is visible and adjustable in the panel.

8. What is needed before starting

  1. Scope of Stage 4. All 109 buttons, or the landing page only (7 sections)?
  2. Strictness of law №1 for the landing page: drive 12/20 out of the spacing, or leave them?
  3. Button size. Is "far too big" about height (48/56), about padding, or about the text size? One concrete example is needed as the reference point.