From abab6e1f599c7614396bf9b3f8a785e64b13346c Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 19 May 2026 22:29:37 +0200 Subject: [PATCH] =?UTF-8?q?feat(01-12):=20wave-1=20task-2=20=E2=80=94=20ca?= =?UTF-8?q?nonical=20src/shared/tokens.css=20(R2=20Lora=20substitution=20+?= =?UTF-8?q?=20.mks-word=20+=20local=20@font-face=20block)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit src/shared/tokens.css lands as the canonical token system — engineering working copy of .planning/intel/design-incoming/system/bundle/mokosh-handoff/ tokens.css with three surgical edits per Plan 01-12: 1. Handoff's PREVIEW-ONLY Google Fonts @import (line 12) REMOVED + replaced with 8 local @font-face rules pointing at ./fonts/*.woff2 (Lora normal + italic variable; Plex Sans Regular/Medium/SemiBold/Bold; Plex Mono Regular/Medium). MV3 CSP self-host enforced (style-src 'self' + font-src 'self'). 2. --mks-font-display VALUE substituted from "Newsreader" to "Lora" per R2 designer reply 2026-05-19 (Cyrillic coverage; brand-decisions-v1- followup-display-font.md). The Lora foundry note is preserved in the Type-section comment. ZERO Newsreader references remain anywhere in the file (verified by grep). 3. .mks-word class added at end-of-file with the {font-family,font-size, font-weight,letter-spacing,fill} declarations from the lockup SVG's class="mks-word" usage. Required by mokosh-lockup.svg line 21 per RESEARCH §8. src/shared/brand/ engineering working copies of: - mokosh-mark.svg (Loom 2×2 weave intersection at 32×32 viewBox) - mokosh-lockup.svg (mark + Mokosh wordmark at 240×56 viewBox) The intel/ design-incoming/ copies remain unchanged as the original handoff source-of-truth. Verification: - googleapis count: 0 (MV3 CSP self-host invariant) - Newsreader count: 0 (R2 substitution complete) - @font-face count: 8 (Lora normal + italic + Plex Sans ×4 + Plex Mono ×2) - .mks-word: 1 definition (referenced by mokosh-lockup.svg) - Lora references: 13 (font-family stack + @font-face + comments) - tests/build/fonts-present.test.ts: 10/10 GREEN - tests/build/tokens-adopted.test.ts case (a): GREEN (tokens.css exists) - tests/build/tokens-adopted.test.ts cases (b)(c): still RED (Wave 4 work) Co-Authored-By: Claude Opus 4.7 (1M context) --- src/shared/brand/mokosh-lockup.svg | 22 ++ src/shared/brand/mokosh-mark.svg | 25 ++ src/shared/tokens.css | 354 +++++++++++++++++++++++++++++ 3 files changed, 401 insertions(+) create mode 100644 src/shared/brand/mokosh-lockup.svg create mode 100644 src/shared/brand/mokosh-mark.svg create mode 100644 src/shared/tokens.css diff --git a/src/shared/brand/mokosh-lockup.svg b/src/shared/brand/mokosh-lockup.svg new file mode 100644 index 0000000..130d46e --- /dev/null +++ b/src/shared/brand/mokosh-lockup.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + Mokosh + \ No newline at end of file diff --git a/src/shared/brand/mokosh-mark.svg b/src/shared/brand/mokosh-mark.svg new file mode 100644 index 0000000..6e9bd8f --- /dev/null +++ b/src/shared/brand/mokosh-mark.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/shared/tokens.css b/src/shared/tokens.css new file mode 100644 index 0000000..22f52ae --- /dev/null +++ b/src/shared/tokens.css @@ -0,0 +1,354 @@ +/* ───────────────────────────────────────────────────────────────────────── + Mokosh Design System — tokens.css + Single source of truth for foundational tokens. + Surfaces: Chrome MV3 popup, welcome page, notification copy, toolbar. + Audience: Russian-first operators. Cyrillic coverage required. + + This file is the engineering working copy of the designer handoff at + .planning/intel/design-incoming/system/bundle/mokosh-handoff/tokens.css. + Three surgical edits applied for the engineering working copy (Plan + 01-12 Wave 1 Task 2): + 1. The handoff's PREVIEW-ONLY Google Fonts @import (handoff line 12) + is REPLACED with the seven local @font-face rules below — MV3 + CSP requires self-hosting (style-src 'self' + font-src 'self'). + 2. --mks-font-display value REPLACED from the handoff's serif + family to "Lora" per R2 designer reply 2026-05-19 (full Cyrillic + coverage via Cyreal foundry; see + .planning/intel/brand-decisions-v1-followup-display-font.md). + 3. .mks-word class added at end-of-file per mokosh-lockup.svg line + 21 + RESEARCH §8. + ───────────────────────────────────────────────────────────────────── */ + +/* ── Self-hosted fonts (MV3 CSP) ── + Faces per D-05 with R2 substitution applied (designer reply + 2026-05-19; see brand-decisions-v1-followup-display-font.md). + Subsetting: all faces are Latin (U+0020-007E + U+00A0-00FF) + + Cyrillic basic (U+0400-045F + supplemental code points per + scripts/subset-fonts.sh recipe). All OFL-1.1 (LICENSE-Lora.txt + + LICENSE-IBM-Plex.txt next to this directory). */ + +/* Lora variable — display family with full Cyrillic (R2 substitute, see brand-decisions-v1-followup) */ +@font-face { + font-family: "Lora"; + src: url("./fonts/Lora-VariableFont.woff2") format("woff2-variations"), + url("./fonts/Lora-VariableFont.woff2") format("woff2"); + font-weight: 400 700; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "Lora"; + src: url("./fonts/Lora-Italic-VariableFont.woff2") format("woff2-variations"), + url("./fonts/Lora-Italic-VariableFont.woff2") format("woff2"); + font-weight: 400 700; + font-style: italic; + font-display: swap; +} + +/* IBM Plex Sans — UI body family with full Cyrillic */ +@font-face { + font-family: "IBM Plex Sans"; + src: url("./fonts/IBMPlexSans-Regular.woff2") format("woff2"); + font-weight: 400; font-style: normal; font-display: swap; +} +@font-face { + font-family: "IBM Plex Sans"; + src: url("./fonts/IBMPlexSans-Medium.woff2") format("woff2"); + font-weight: 500; font-style: normal; font-display: swap; +} +@font-face { + font-family: "IBM Plex Sans"; + src: url("./fonts/IBMPlexSans-SemiBold.woff2") format("woff2"); + font-weight: 600; font-style: normal; font-display: swap; +} +@font-face { + font-family: "IBM Plex Sans"; + src: url("./fonts/IBMPlexSans-Bold.woff2") format("woff2"); + font-weight: 700; font-style: normal; font-display: swap; +} + +/* IBM Plex Mono — diagnostic / timer family with full Cyrillic */ +@font-face { + font-family: "IBM Plex Mono"; + src: url("./fonts/IBMPlexMono-Regular.woff2") format("woff2"); + font-weight: 400; font-style: normal; font-display: swap; +} +@font-face { + font-family: "IBM Plex Mono"; + src: url("./fonts/IBMPlexMono-Medium.woff2") format("woff2"); + font-weight: 500; font-style: normal; font-display: swap; +} + +:root { + /* ── Palette ────────────────────────────────────────────────────────── + The "loom" palette. Warm-earthy, NOT clinical-blue. Reads as + restrained, professional, slightly hand-made — distinct from the + standard SaaS Material defaults the engineering placeholder used. + Each step validated for WCAG AA against its intended pair. */ + + /* Linen — primary surface family (warm off-white through stone) */ + --mks-linen-50: #faf7f1; /* page background */ + --mks-linen-100: #f3eee4; /* card / popup surface */ + --mks-linen-200: #e8e0d0; /* hairline / divider on linen */ + --mks-linen-300: #d4c9b5; /* muted edge */ + + /* Ink — text + inverse surface family (warm near-black indigo) */ + --mks-ink-900: #181b2a; /* primary text, deepest surface */ + --mks-ink-800: #232639; /* dark surface */ + --mks-ink-700: #2f3349; /* dark surface raised */ + --mks-ink-500: #5b5f76; /* secondary text on linen */ + --mks-ink-400: #7a7e94; /* tertiary text, captions */ + --mks-ink-300: #a4a7b8; /* disabled text */ + + /* Accents — state colors. Each is a dye reference. */ + --mks-madder-600: #b2543d; /* REC accent — Rubia tinctorum dye */ + --mks-madder-700: #963f29; /* REC pressed */ + --mks-madder-100: #f5e2db; /* REC tint */ + + --mks-moss-600: #5a7349; /* success / saved */ + --mks-moss-700: #455a38; + --mks-moss-100: #e2e9da; + + --mks-amber-600: #c98b3a; /* warning / recoverable error */ + --mks-amber-100: #f6e6c8; + + --mks-brick-600: #a23a2b; /* unrecoverable error */ + --mks-brick-100: #f0d5cf; + + /* Semantic — point these at the palette. Use these in components. */ + --mks-surface: var(--mks-linen-50); + --mks-surface-raised: var(--mks-linen-100); + --mks-surface-sunken: var(--mks-linen-200); + --mks-surface-inverse: var(--mks-ink-900); + + --mks-fg-1: var(--mks-ink-900); /* primary text */ + --mks-fg-2: var(--mks-ink-500); /* secondary text */ + --mks-fg-3: var(--mks-ink-400); /* tertiary / caption */ + --mks-fg-disabled: var(--mks-ink-300); + --mks-fg-inverse: var(--mks-linen-50); + + --mks-border: var(--mks-linen-200); + --mks-border-strong: var(--mks-linen-300); + --mks-border-focus: var(--mks-ink-900); + + --mks-rec: var(--mks-madder-600); + --mks-success: var(--mks-moss-600); + --mks-warning: var(--mks-amber-600); + --mks-error: var(--mks-brick-600); + + /* ── Type ───────────────────────────────────────────────────────────── + Three families. Lora for display (Cyreal foundry; R2 substitute per + designer reply 2026-05-19; full Cyrillic coverage). + IBM Plex Sans for UI body (excellent Cyrillic; not Inter/Roboto). + IBM Plex Mono for diagnostic / timer overlays. */ + + --mks-font-display: "Lora", "Iowan Old Style", "Times New Roman", serif; + --mks-font-ui: "IBM Plex Sans", "Segoe UI", -apple-system, BlinkMacSystemFont, sans-serif; + --mks-font-mono: "IBM Plex Mono", "SF Mono", Menlo, Consolas, monospace; + + /* Base type scale — ratio ~1.2, tuned for popup density. + Smallest size 11px is reserved for badge labels only. */ + --mks-text-xs: 11px; + --mks-text-sm: 13px; + --mks-text-base: 15px; + --mks-text-md: 17px; + --mks-text-lg: 20px; + --mks-text-xl: 28px; + --mks-text-2xl: 40px; + --mks-text-3xl: 56px; + + --mks-lh-tight: 1.15; + --mks-lh-snug: 1.3; + --mks-lh-base: 1.5; + + --mks-weight-regular: 400; + --mks-weight-medium: 500; + --mks-weight-semibold: 600; + --mks-weight-bold: 700; + + /* Display tracking — Lora at large sizes wants negative tracking */ + --mks-tracking-display: -0.015em; + --mks-tracking-tight: -0.005em; + --mks-tracking-base: 0; + --mks-tracking-loose: 0.04em; /* eyebrow / caps labels */ + --mks-tracking-caps: 0.08em; /* badge text REC / ERR */ + + /* ── Spacing ────────────────────────────────────────────────────────── + 4px base. Steps named by px multiple for clarity. */ + --mks-space-1: 4px; + --mks-space-2: 8px; + --mks-space-3: 12px; + --mks-space-4: 16px; + --mks-space-5: 20px; + --mks-space-6: 24px; + --mks-space-8: 32px; + --mks-space-10: 40px; + --mks-space-12: 48px; + --mks-space-16: 64px; + --mks-space-20: 80px; + + /* ── Radius ─────────────────────────────────────────────────────────── + Architectural. Sharp-ish — 4px base, 8px cards, 999 chips. NOT pillow. */ + --mks-radius-sm: 2px; /* badge text container */ + --mks-radius-md: 4px; /* default control */ + --mks-radius-lg: 8px; /* card, popup body */ + --mks-radius-xl: 12px; /* welcome hero card */ + --mks-radius-full: 999px;/* chips, recording dot */ + + /* ── Borders + shadows ─────────────────────────────────────────────── + One pixel hairline, low-elevation shadows. + Restrained — no big card drop-shadows. */ + --mks-border-width: 1px; + + /* Hairline shadow — for buttons */ + --mks-shadow-1: 0 1px 0 rgba(24, 27, 42, 0.04), + 0 1px 2px rgba(24, 27, 42, 0.06); + /* Card shadow — popup elevation */ + --mks-shadow-2: 0 1px 2px rgba(24, 27, 42, 0.06), + 0 4px 12px rgba(24, 27, 42, 0.08); + /* Floating — modal / tooltip */ + --mks-shadow-3: 0 2px 4px rgba(24, 27, 42, 0.08), + 0 12px 32px rgba(24, 27, 42, 0.12); + /* Inset — sunken surfaces, fields */ + --mks-shadow-inset: inset 0 1px 0 rgba(24, 27, 42, 0.04); + /* Focus ring — visible against any surface, color-independent */ + --mks-shadow-focus: 0 0 0 3px rgba(24, 27, 42, 0.18); + + /* ── Motion ─────────────────────────────────────────────────────────── + Quiet. No bounces. Reduced-motion is honored at the component level. */ + --mks-dur-fast: 120ms; + --mks-dur-base: 200ms; + --mks-dur-slow: 320ms; + --mks-ease-out: cubic-bezier(0.2, 0.6, 0.2, 1); + --mks-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); + + /* ── Layout ──────────────────────────────────────────────────────────*/ + --mks-popup-w: 320px; + --mks-popup-min-h: 180px; + --mks-welcome-max-w: 720px; +} + +/* Dark theme — applied via .dark on root OR @media (prefers-color-scheme). + Used for the dark popup variant, smoke diagnostic overlay, and any + future dark Chrome theme support. */ +.dark, [data-theme="dark"] { + --mks-surface: var(--mks-ink-900); + --mks-surface-raised: var(--mks-ink-800); + --mks-surface-sunken: #11131e; + --mks-surface-inverse: var(--mks-linen-50); + + --mks-fg-1: #ece7dc; + --mks-fg-2: #a4a7b8; + --mks-fg-3: #7a7e94; + --mks-fg-disabled: #5b5f76; + --mks-fg-inverse: var(--mks-ink-900); + + --mks-border: rgba(243, 238, 228, 0.08); + --mks-border-strong: rgba(243, 238, 228, 0.14); + --mks-border-focus: var(--mks-linen-50); + + --mks-shadow-focus: 0 0 0 3px rgba(243, 238, 228, 0.24); +} + +/* ── Semantic typography helpers ────────────────────────────────────── + Apply these classes; do not redefine sizes ad-hoc. */ +.mks-display-1 { + font-family: var(--mks-font-display); + font-size: var(--mks-text-3xl); + line-height: var(--mks-lh-tight); + letter-spacing: var(--mks-tracking-display); + font-weight: var(--mks-weight-regular); + color: var(--mks-fg-1); +} +.mks-display-2 { + font-family: var(--mks-font-display); + font-size: var(--mks-text-2xl); + line-height: var(--mks-lh-tight); + letter-spacing: var(--mks-tracking-display); + font-weight: var(--mks-weight-regular); + color: var(--mks-fg-1); +} +.mks-h1 { + font-family: var(--mks-font-display); + font-size: var(--mks-text-xl); + line-height: var(--mks-lh-tight); + letter-spacing: var(--mks-tracking-tight); + font-weight: var(--mks-weight-regular); + color: var(--mks-fg-1); +} +.mks-h2 { + font-family: var(--mks-font-ui); + font-size: var(--mks-text-lg); + line-height: var(--mks-lh-snug); + font-weight: var(--mks-weight-semibold); + color: var(--mks-fg-1); +} +.mks-h3 { + font-family: var(--mks-font-ui); + font-size: var(--mks-text-md); + line-height: var(--mks-lh-snug); + font-weight: var(--mks-weight-semibold); + color: var(--mks-fg-1); +} +.mks-body { + font-family: var(--mks-font-ui); + font-size: var(--mks-text-base); + line-height: var(--mks-lh-base); + color: var(--mks-fg-1); +} +.mks-body-sm { + font-family: var(--mks-font-ui); + font-size: var(--mks-text-sm); + line-height: var(--mks-lh-base); + color: var(--mks-fg-2); +} +.mks-caption { + font-family: var(--mks-font-ui); + font-size: var(--mks-text-xs); + line-height: var(--mks-lh-snug); + color: var(--mks-fg-3); +} +.mks-eyebrow { + font-family: var(--mks-font-ui); + font-size: var(--mks-text-xs); + line-height: var(--mks-lh-snug); + letter-spacing: var(--mks-tracking-caps); + text-transform: uppercase; + font-weight: var(--mks-weight-semibold); + color: var(--mks-fg-2); +} +.mks-mono { + font-family: var(--mks-font-mono); + font-size: var(--mks-text-sm); + line-height: var(--mks-lh-base); + color: var(--mks-fg-1); +} +.mks-badge-label { + font-family: var(--mks-font-ui); + font-size: var(--mks-text-xs); + line-height: 1; + letter-spacing: var(--mks-tracking-caps); + text-transform: uppercase; + font-weight: var(--mks-weight-bold); +} + +/* Accessibility — honor reduced-motion */ +@media (prefers-reduced-motion: reduce) { + :root { + --mks-dur-fast: 0ms; + --mks-dur-base: 0ms; + --mks-dur-slow: 0ms; + } +} + +/* ── Lockup wordmark — referenced by mokosh-lockup.svg line 21 ── + The SVG inlines class="mks-word" on its element so the engineering + wordmark renders with the Lora display family. Per RESEARCH §8 + Plan + 01-12 interfaces block. */ +.mks-word { + font-family: var(--mks-font-display); + font-size: 32px; + font-weight: var(--mks-weight-regular); + letter-spacing: var(--mks-tracking-display); + fill: var(--mks-ink-900); +}