agemon 0.1.0 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +983 -30
- package/assets/skills/architecture/agemon-architecture/LICENSE +21 -0
- package/assets/skills/architecture/agemon-architecture/NOTICE.md +9 -0
- package/assets/skills/architecture/agemon-architecture/SKILL.md +275 -0
- package/assets/skills/code-quality/agemon-clean-code/LICENSE +21 -0
- package/assets/skills/code-quality/agemon-clean-code/NOTICE.md +9 -0
- package/assets/skills/code-quality/agemon-clean-code/SKILL.md +78 -0
- package/assets/skills/code-quality/agemon-house-rules/SKILL.md +103 -0
- package/assets/skills/commit/agemon-commit/SKILL.md +87 -0
- package/assets/skills/design/agemon-design/LICENSE +21 -0
- package/assets/skills/design/agemon-design/NOTICE.md +43 -0
- package/assets/skills/design/agemon-design/SKILL.md +128 -0
- package/assets/skills/design/agemon-design/references/accessibility.md +182 -0
- package/assets/skills/design/agemon-design/references/actions.md +215 -0
- package/assets/skills/design/agemon-design/references/ai-chat.md +158 -0
- package/assets/skills/design/agemon-design/references/brief.md +190 -0
- package/assets/skills/design/agemon-design/references/color.md +216 -0
- package/assets/skills/design/agemon-design/references/components.md +91 -0
- package/assets/skills/design/agemon-design/references/copy.md +300 -0
- package/assets/skills/design/agemon-design/references/core-rules.md +166 -0
- package/assets/skills/design/agemon-design/references/craft-intent.md +162 -0
- package/assets/skills/design/agemon-design/references/dashboard.md +131 -0
- package/assets/skills/design/agemon-design/references/dataviz.md +197 -0
- package/assets/skills/design/agemon-design/references/finish-bar.md +243 -0
- package/assets/skills/design/agemon-design/references/forms.md +192 -0
- package/assets/skills/design/agemon-design/references/heuristics.md +319 -0
- package/assets/skills/design/agemon-design/references/inspiration.md +287 -0
- package/assets/skills/design/agemon-design/references/layout.md +236 -0
- package/assets/skills/design/agemon-design/references/loops.md +155 -0
- package/assets/skills/design/agemon-design/references/metadata.md +98 -0
- package/assets/skills/design/agemon-design/references/modern-css.md +448 -0
- package/assets/skills/design/agemon-design/references/motion.md +434 -0
- package/assets/skills/design/agemon-design/references/personas.md +206 -0
- package/assets/skills/design/agemon-design/references/preset-dashboard.md +109 -0
- package/assets/skills/design/agemon-design/references/preset-editorial.md +94 -0
- package/assets/skills/design/agemon-design/references/preset-minimal.md +93 -0
- package/assets/skills/design/agemon-design/references/principles-catalog.md +299 -0
- package/assets/skills/design/agemon-design/references/recipe-auth.md +88 -0
- package/assets/skills/design/agemon-design/references/recipe-dashboard.md +130 -0
- package/assets/skills/design/agemon-design/references/recipe-landing.md +120 -0
- package/assets/skills/design/agemon-design/references/responsive.md +168 -0
- package/assets/skills/design/agemon-design/references/review.md +340 -0
- package/assets/skills/design/agemon-design/references/routing.md +143 -0
- package/assets/skills/design/agemon-design/references/sound.md +150 -0
- package/assets/skills/design/agemon-design/references/spec.md +123 -0
- package/assets/skills/design/agemon-design/references/stack.md +522 -0
- package/assets/skills/design/agemon-design/references/stage-assets.md +106 -0
- package/assets/skills/design/agemon-design/references/stage-build.md +46 -0
- package/assets/skills/design/agemon-design/references/stage-critique.md +34 -0
- package/assets/skills/design/agemon-design/references/stage-directions.md +44 -0
- package/assets/skills/design/agemon-design/references/stage-intake.md +34 -0
- package/assets/skills/design/agemon-design/references/stage-verify.md +44 -0
- package/assets/skills/design/agemon-design/references/state-design.md +188 -0
- package/assets/skills/design/agemon-design/references/tells-2026-11.md +32 -0
- package/assets/skills/design/agemon-design/references/themes.md +233 -0
- package/assets/skills/design/agemon-design/references/third-party-licenses.md +323 -0
- package/assets/skills/design/agemon-design/references/tokens.md +350 -0
- package/assets/skills/design/agemon-design/references/typography.md +248 -0
- package/assets/skills/design/agemon-design/scripts/audit-page.js +532 -0
- package/assets/skills/design/agemon-design/scripts/check-source.mjs +358 -0
- package/assets/skills/design/agemon-design/scripts/deal.mjs +231 -0
- package/assets/skills/design/agemon-design/scripts/inventory.mjs +676 -0
- package/assets/skills/essentials/web-design-guidelines/LICENSE +21 -0
- package/assets/skills/essentials/web-design-guidelines/NOTICE.md +14 -0
- package/assets/skills/essentials/web-design-guidelines/SKILL.md +18 -0
- package/assets/skills/essentials/web-design-guidelines/references/guidelines.md +184 -0
- package/assets/skills/essentials/writing-guidelines/LICENSE +21 -0
- package/assets/skills/essentials/writing-guidelines/NOTICE.md +14 -0
- package/assets/skills/essentials/writing-guidelines/SKILL.md +18 -0
- package/assets/skills/essentials/writing-guidelines/references/guidelines.md +250 -0
- package/assets/skills/founder/agemon-founder-board/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-board/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-board/SKILL.md +111 -0
- package/assets/skills/founder/agemon-founder-board/lenses.md +84 -0
- package/assets/skills/founder/agemon-founder-brand/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-brand/NOTICE.md +12 -0
- package/assets/skills/founder/agemon-founder-brand/SKILL.md +77 -0
- package/assets/skills/founder/agemon-founder-cfo/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-cfo/NOTICE.md +12 -0
- package/assets/skills/founder/agemon-founder-cfo/SKILL.md +109 -0
- package/assets/skills/founder/agemon-founder-cfo/example.json +27 -0
- package/assets/skills/founder/agemon-founder-cfo/unit_economics.py +270 -0
- package/assets/skills/founder/agemon-founder-competitors/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-competitors/NOTICE.md +12 -0
- package/assets/skills/founder/agemon-founder-competitors/SKILL.md +84 -0
- package/assets/skills/founder/agemon-founder-consumer/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-consumer/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-consumer/SKILL.md +126 -0
- package/assets/skills/founder/agemon-founder-consumer/customer.example.json +34 -0
- package/assets/skills/founder/agemon-founder-consumer/panel.py +424 -0
- package/assets/skills/founder/agemon-founder-consumer/pitch.example.md +3 -0
- package/assets/skills/founder/agemon-founder-launch/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-launch/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-launch/SKILL.md +65 -0
- package/assets/skills/founder/agemon-founder-marketing/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-marketing/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-marketing/SKILL.md +80 -0
- package/assets/skills/founder/agemon-founder-offer/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-offer/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-offer/SKILL.md +75 -0
- package/assets/skills/founder/agemon-founder-ops/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-ops/NOTICE.md +12 -0
- package/assets/skills/founder/agemon-founder-ops/SKILL.md +77 -0
- package/assets/skills/founder/agemon-founder-plan/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-plan/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-plan/SKILL.md +88 -0
- package/assets/skills/founder/agemon-founder-plan/compile.py +178 -0
- package/assets/skills/founder/agemon-founder-pricing/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-pricing/NOTICE.md +12 -0
- package/assets/skills/founder/agemon-founder-pricing/SKILL.md +92 -0
- package/assets/skills/founder/agemon-founder-pricing/van_westendorp.py +172 -0
- package/assets/skills/geo-seo/geo/LICENSE +21 -0
- package/assets/skills/geo-seo/geo/NOTICE.md +18 -0
- package/assets/skills/geo-seo/geo/SKILL.md +145 -0
- package/assets/skills/geo-seo/geo-audit/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-audit/NOTICE.md +17 -0
- package/assets/skills/geo-seo/geo-audit/SKILL.md +371 -0
- package/assets/skills/geo-seo/geo-audit/references/ai-visibility.md +233 -0
- package/assets/skills/geo-seo/geo-audit/references/content.md +329 -0
- package/assets/skills/geo-seo/geo-audit/references/platform-analysis.md +294 -0
- package/assets/skills/geo-seo/geo-audit/references/schema.md +383 -0
- package/assets/skills/geo-seo/geo-audit/references/technical.md +368 -0
- package/assets/skills/geo-seo/geo-brand-mentions/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-brand-mentions/NOTICE.md +15 -0
- package/assets/skills/geo-seo/geo-brand-mentions/SKILL.md +459 -0
- package/assets/skills/geo-seo/geo-citability/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-citability/NOTICE.md +14 -0
- package/assets/skills/geo-seo/geo-citability/SKILL.md +320 -0
- package/assets/skills/geo-seo/geo-content/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-content/NOTICE.md +14 -0
- package/assets/skills/geo-seo/geo-content/SKILL.md +352 -0
- package/assets/skills/geo-seo/geo-crawlers/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-crawlers/NOTICE.md +15 -0
- package/assets/skills/geo-seo/geo-crawlers/SKILL.md +388 -0
- package/assets/skills/geo-seo/geo-llmstxt/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-llmstxt/NOTICE.md +14 -0
- package/assets/skills/geo-seo/geo-llmstxt/SKILL.md +433 -0
- package/assets/skills/geo-seo/geo-platform-optimizer/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-platform-optimizer/NOTICE.md +14 -0
- package/assets/skills/geo-seo/geo-platform-optimizer/SKILL.md +282 -0
- package/assets/skills/geo-seo/geo-report/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-report/NOTICE.md +14 -0
- package/assets/skills/geo-seo/geo-report/SKILL.md +406 -0
- package/assets/skills/geo-seo/geo-report-pdf/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-report-pdf/NOTICE.md +20 -0
- package/assets/skills/geo-seo/geo-report-pdf/SKILL.md +153 -0
- package/assets/skills/geo-seo/geo-report-pdf/templates/geo-report-template.html +548 -0
- package/assets/skills/geo-seo/geo-schema/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-schema/NOTICE.md +16 -0
- package/assets/skills/geo-seo/geo-schema/SKILL.md +396 -0
- package/assets/skills/geo-seo/geo-technical/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-technical/NOTICE.md +15 -0
- package/assets/skills/geo-seo/geo-technical/SKILL.md +566 -0
- package/assets/skills/output-style/agemon-adhd/LICENSE +21 -0
- package/assets/skills/output-style/agemon-adhd/NOTICE.md +13 -0
- package/assets/skills/output-style/agemon-adhd/SKILL.md +138 -0
- package/assets/skills/performance/agemon-performance/NOTICE.md +1 -0
- package/assets/skills/performance/agemon-performance/SKILL.md +76 -0
- package/assets/skills/security/agemon-security/LICENSE +21 -0
- package/assets/skills/security/agemon-security/NOTICE.md +8 -0
- package/assets/skills/security/agemon-security/SKILL.md +356 -0
- package/assets/skills/security/agemon-security-audit/AI-AND-LLM.md +83 -0
- package/assets/skills/security/agemon-security-audit/ATTACK-CLASSES.md +130 -0
- package/assets/skills/security/agemon-security-audit/CLIENT-SIDE.md +83 -0
- package/assets/skills/security/agemon-security-audit/CLOUD-AND-DEPLOYMENT.md +86 -0
- package/assets/skills/security/agemon-security-audit/DATA-ISOLATION-AND-LIFECYCLE.md +84 -0
- package/assets/skills/security/agemon-security-audit/DESKTOP-MOBILE-AND-LOCAL-IPC.md +89 -0
- package/assets/skills/security/agemon-security-audit/HUNTING.md +251 -0
- package/assets/skills/security/agemon-security-audit/LICENSE +21 -0
- package/assets/skills/security/agemon-security-audit/MEMORY-SAFETY-AND-BINARY.md +101 -0
- package/assets/skills/security/agemon-security-audit/NOTICE.md +12 -0
- package/assets/skills/security/agemon-security-audit/PROTOCOLS-RPC-AND-MESSAGING.md +81 -0
- package/assets/skills/security/agemon-security-audit/RECONNAISSANCE.md +156 -0
- package/assets/skills/security/agemon-security-audit/RESOURCE-EXHAUSTION-AND-AVAILABILITY.md +78 -0
- package/assets/skills/security/agemon-security-audit/SKILL.md +192 -0
- package/assets/skills/security/agemon-security-audit/SUPPLY-CHAIN-AND-RELEASE.md +73 -0
- package/assets/skills/security/agemon-security-audit/VALIDATION-AND-REPORTING.md +186 -0
- package/assets/skills/security/agemon-security-audit/WEB-PROTOCOL-AND-AUTH.md +105 -0
- package/assets/skills/security/agemon-security-audit/report-schema.json +461 -0
- package/assets/skills/security/agemon-security-audit/validate-coverage-ledger.cjs +872 -0
- package/assets/skills/security/agemon-security-audit/validate-findings.cjs +773 -0
- package/assets/skills/self-review/agemon-review-intake/LICENSE +21 -0
- package/assets/skills/self-review/agemon-review-intake/NOTICE.md +9 -0
- package/assets/skills/self-review/agemon-review-intake/SKILL.md +205 -0
- package/assets/skills/self-review/agemon-review-request/LICENSE +21 -0
- package/assets/skills/self-review/agemon-review-request/NOTICE.md +9 -0
- package/assets/skills/self-review/agemon-review-request/SKILL.md +104 -0
- package/assets/skills/self-review/agemon-review-request/code-reviewer.md +188 -0
- package/assets/skills/self-review/agemon-root-cause/LICENSE +21 -0
- package/assets/skills/self-review/agemon-root-cause/NOTICE.md +10 -0
- package/assets/skills/self-review/agemon-root-cause/SKILL.md +283 -0
- package/assets/skills/self-review/agemon-root-cause/condition-based-waiting-example.ts +158 -0
- package/assets/skills/self-review/agemon-root-cause/condition-based-waiting.md +115 -0
- package/assets/skills/self-review/agemon-root-cause/defense-in-depth.md +122 -0
- package/assets/skills/self-review/agemon-root-cause/find-polluter.sh +72 -0
- package/assets/skills/self-review/agemon-root-cause/root-cause-tracing.md +169 -0
- package/assets/skills/self-review/agemon-root-cause/test-academic.md +14 -0
- package/assets/skills/self-review/agemon-root-cause/test-pressure-1.md +58 -0
- package/assets/skills/self-review/agemon-root-cause/test-pressure-2.md +68 -0
- package/assets/skills/self-review/agemon-root-cause/test-pressure-3.md +69 -0
- package/assets/skills/self-review/agemon-verify-before-done/LICENSE +21 -0
- package/assets/skills/self-review/agemon-verify-before-done/NOTICE.md +9 -0
- package/assets/skills/self-review/agemon-verify-before-done/SKILL.md +120 -0
- package/assets/skills/team-lead/agemon-plan-rfc/SKILL.md +317 -0
- package/assets/skills/team-lead/prd-generator/SKILL.md +437 -0
- package/assets/skills/team-lead/skill-headofit-audit/SKILL.md +72 -0
- package/assets/skills/team-lead/skill-incident-rca/SKILL.md +66 -0
- package/assets/skills/team-lead/skill-meeting-lifecycle/SKILL.md +63 -0
- package/assets/skills/team-lead/skill-obsidian-vault-sync/SKILL.md +69 -0
- package/assets/skills/team-lead/skill-prd-decomposer/SKILL.md +71 -0
- package/assets/skills/team-lead/skill-sec-check/SKILL.md +70 -0
- package/assets/skills/team-lead/skill-task-extractor/SKILL.md +79 -0
- package/assets/skills/team-lead/skill-tech-spike/SKILL.md +57 -0
- package/assets/skills/team-lead/skill-techlead-reviewer/SKILL.md +81 -0
- package/assets/skills/workflow/agemon-brainstorming/LICENSE +21 -0
- package/assets/skills/workflow/agemon-brainstorming/NOTICE.md +14 -0
- package/assets/skills/workflow/agemon-brainstorming/SKILL.md +287 -0
- package/assets/skills/workflow/agemon-brainstorming/builder-check-prompt.md +23 -0
- package/assets/skills/workflow/agemon-dispatching-parallel-agents/LICENSE +21 -0
- package/assets/skills/workflow/agemon-dispatching-parallel-agents/NOTICE.md +13 -0
- package/assets/skills/workflow/agemon-dispatching-parallel-agents/SKILL.md +167 -0
- package/assets/skills/workflow/agemon-executing-plans/LICENSE +21 -0
- package/assets/skills/workflow/agemon-executing-plans/NOTICE.md +15 -0
- package/assets/skills/workflow/agemon-executing-plans/SKILL.md +322 -0
- package/assets/skills/workflow/agemon-executing-plans/scripts/task-done +55 -0
- package/assets/skills/workflow/agemon-executing-plans/scripts/task-start +32 -0
- package/assets/skills/workflow/agemon-finishing-a-development-branch/LICENSE +21 -0
- package/assets/skills/workflow/agemon-finishing-a-development-branch/NOTICE.md +13 -0
- package/assets/skills/workflow/agemon-finishing-a-development-branch/SKILL.md +225 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/LICENSE +21 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/NOTICE.md +15 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/SKILL.md +339 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/code-reviewer.md +198 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/implementer-prompt.md +154 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/re-review-prompt.md +116 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/batching.md +11 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/cannot-verify.md +10 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/final-review.md +49 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/fix-loop.md +77 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/handling-reports.md +15 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/preflight.md +26 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/resuming.md +12 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/role-scout.md +18 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/role-worker.md +19 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/scripts/review-package +64 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/scripts/sdd-repo +54 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/scripts/sdd-workspace +110 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/scripts/task-brief +108 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/task-reviewer-prompt.md +209 -0
- package/assets/skills/workflow/agemon-test-driven-development/LICENSE +21 -0
- package/assets/skills/workflow/agemon-test-driven-development/NOTICE.md +14 -0
- package/assets/skills/workflow/agemon-test-driven-development/SKILL.md +330 -0
- package/assets/skills/workflow/agemon-test-driven-development/writing-good-tests.md +198 -0
- package/assets/skills/workflow/agemon-using-git-worktrees/LICENSE +21 -0
- package/assets/skills/workflow/agemon-using-git-worktrees/NOTICE.md +13 -0
- package/assets/skills/workflow/agemon-using-git-worktrees/SKILL.md +167 -0
- package/assets/skills/workflow/agemon-writing-plans/LICENSE +21 -0
- package/assets/skills/workflow/agemon-writing-plans/NOTICE.md +13 -0
- package/assets/skills/workflow/agemon-writing-plans/SKILL.md +204 -0
- package/assets/tools/code-review-graph-constraints.txt +1418 -0
- package/assets/tools/package-lock.json +111 -0
- package/assets/tools/package.json +6 -0
- package/dist/chunk-ZZBF3GOV.js +3451 -0
- package/dist/chunk-ZZBF3GOV.js.map +1 -0
- package/dist/fake-subprocess-IV4ML77S.js +636 -0
- package/dist/fake-subprocess-IV4ML77S.js.map +1 -0
- package/dist/index.js +23836 -1945
- package/dist/index.js.map +1 -1
- package/package.json +37 -17
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# Token Spine
|
|
2
|
+
|
|
3
|
+
Every design decision in a project references a three-layer token system established before any component is written. The layers are: **primitive** (raw values named for what they are), **semantic** (contextual meaning, switches between themes), and **component** (specific usage, created on demand). The scope is projects: throwaway prototypes and single standalone components may run on primitives alone — but the moment a second surface appears, build the spine.
|
|
4
|
+
|
|
5
|
+
This 3-layer contract and the off-system-value definition (any color, radius, or spacing value not drawn from the token system) are the evaluation source for the `token-consistency` loop preset (see `../SKILL.md` → loops.md).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The Three Layers
|
|
10
|
+
|
|
11
|
+
### Layer 1: Primitive tokens
|
|
12
|
+
|
|
13
|
+
Raw values. Named for what they ARE, not how they're used. Reusable across themes.
|
|
14
|
+
|
|
15
|
+
**Color — neutral ramp + accent ramp + semantic bases.**
|
|
16
|
+
Use OKLCH for perceptually uniform steps. See `color.md` for palette strategy and tinted-neutral rationale.
|
|
17
|
+
|
|
18
|
+
```css
|
|
19
|
+
/* Neutral ramp — warm tint, not pure gray */
|
|
20
|
+
--gray-50: oklch(98% 0.008 60);
|
|
21
|
+
--gray-100: oklch(95% 0.010 60);
|
|
22
|
+
--gray-200: oklch(90% 0.012 60);
|
|
23
|
+
--gray-300: oklch(82% 0.014 60);
|
|
24
|
+
--gray-400: oklch(70% 0.016 60);
|
|
25
|
+
--gray-500: oklch(58% 0.016 60);
|
|
26
|
+
--gray-600: oklch(46% 0.015 60);
|
|
27
|
+
--gray-700: oklch(36% 0.013 60);
|
|
28
|
+
--gray-800: oklch(26% 0.010 60);
|
|
29
|
+
--gray-900: oklch(18% 0.008 60);
|
|
30
|
+
--gray-950: oklch(12% 0.006 60);
|
|
31
|
+
|
|
32
|
+
/* Accent ramp — replace hue with your brand value */
|
|
33
|
+
--accent-50: oklch(97% 0.03 var(--accent-hue));
|
|
34
|
+
--accent-100: oklch(93% 0.06 var(--accent-hue));
|
|
35
|
+
--accent-200: oklch(86% 0.10 var(--accent-hue));
|
|
36
|
+
--accent-300: oklch(78% 0.14 var(--accent-hue));
|
|
37
|
+
--accent-400: oklch(68% 0.18 var(--accent-hue));
|
|
38
|
+
--accent-500: oklch(58% 0.20 var(--accent-hue));
|
|
39
|
+
--accent-600: oklch(48% 0.19 var(--accent-hue));
|
|
40
|
+
--accent-700: oklch(38% 0.16 var(--accent-hue));
|
|
41
|
+
--accent-800: oklch(28% 0.12 var(--accent-hue));
|
|
42
|
+
--accent-900: oklch(20% 0.08 var(--accent-hue));
|
|
43
|
+
--accent-950: oklch(13% 0.05 var(--accent-hue));
|
|
44
|
+
|
|
45
|
+
/* Semantic color bases — for success / warning / error / info */
|
|
46
|
+
--green-400: oklch(72% 0.18 145);
|
|
47
|
+
--green-600: oklch(52% 0.18 145);
|
|
48
|
+
--amber-400: oklch(78% 0.16 70);
|
|
49
|
+
--amber-600: oklch(58% 0.16 70);
|
|
50
|
+
--red-400: oklch(65% 0.20 25);
|
|
51
|
+
--red-600: oklch(48% 0.20 25);
|
|
52
|
+
--blue-400: oklch(66% 0.16 250);
|
|
53
|
+
--blue-600: oklch(50% 0.16 250);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Spacing — 8pt scale.** Full rhythm rules and when to compress → see `layout.md`.
|
|
57
|
+
|
|
58
|
+
```css
|
|
59
|
+
--space-xs: 0.25rem; /* 4px */
|
|
60
|
+
--space-sm: 0.5rem; /* 8px */
|
|
61
|
+
--space-md: 1rem; /* 16px */
|
|
62
|
+
--space-lg: 1.5rem; /* 24px */
|
|
63
|
+
--space-xl: 2rem; /* 32px */
|
|
64
|
+
--space-2xl: 3rem; /* 48px */
|
|
65
|
+
--space-3xl: 4rem; /* 64px */
|
|
66
|
+
--space-4xl: 6rem; /* 96px */
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Type — size, weight, line-height, letter-spacing.** Full scale and font selection → see `typography.md`.
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
--text-xs: 0.75rem; /* 12px */
|
|
73
|
+
--text-sm: 0.875rem; /* 14px */
|
|
74
|
+
--text-base: 1rem; /* 16px */
|
|
75
|
+
--text-lg: 1.125rem; /* 18px */
|
|
76
|
+
--text-xl: 1.25rem; /* 20px */
|
|
77
|
+
--text-2xl: 1.5rem; /* 24px */
|
|
78
|
+
--text-3xl: 1.875rem; /* 30px */
|
|
79
|
+
--text-4xl: 2.25rem; /* 36px */
|
|
80
|
+
--text-5xl: 3rem; /* 48px */
|
|
81
|
+
|
|
82
|
+
--font-light: 300;
|
|
83
|
+
--font-regular: 400;
|
|
84
|
+
--font-medium: 500;
|
|
85
|
+
--font-semibold: 600;
|
|
86
|
+
--font-bold: 700;
|
|
87
|
+
|
|
88
|
+
--leading-none: 1;
|
|
89
|
+
--leading-tight: 1.1;
|
|
90
|
+
--leading-snug: 1.3;
|
|
91
|
+
--leading-normal: 1.5;
|
|
92
|
+
--leading-relaxed: 1.65;
|
|
93
|
+
|
|
94
|
+
--tracking-tight: -0.03em;
|
|
95
|
+
--tracking-normal: 0;
|
|
96
|
+
--tracking-wide: 0.01em;
|
|
97
|
+
--tracking-wider: 0.05em;
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Radii.**
|
|
101
|
+
|
|
102
|
+
```css
|
|
103
|
+
--radius-none: 0;
|
|
104
|
+
--radius-sm: 0.125rem; /* 2px — minimal, sharp */
|
|
105
|
+
--radius-md: 0.375rem; /* 6px — inputs, badges */
|
|
106
|
+
--radius-lg: 0.625rem; /* 10px — cards */
|
|
107
|
+
--radius-xl: 0.875rem; /* 14px — modals, large panels */
|
|
108
|
+
--radius-2xl: 1.25rem; /* 20px — expressive cards, popovers */
|
|
109
|
+
--radius-full: 9999px; /* pills, avatars */
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Shadows — layered ambient + direct.** Always stack two layers minimum. See `layout.md` for the scale and the "never flat" rule.
|
|
113
|
+
|
|
114
|
+
```css
|
|
115
|
+
--shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.05);
|
|
116
|
+
--shadow-md: 0 4px 6px oklch(0% 0 0 / 0.07),
|
|
117
|
+
0 1px 3px oklch(0% 0 0 / 0.06);
|
|
118
|
+
--shadow-lg: 0 10px 15px oklch(0% 0 0 / 0.09),
|
|
119
|
+
0 4px 6px oklch(0% 0 0 / 0.05);
|
|
120
|
+
--shadow-xl: 0 20px 25px oklch(0% 0 0 / 0.10),
|
|
121
|
+
0 8px 10px oklch(0% 0 0 / 0.04);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Motion — durations and easings.** Perceptual bands and choreography rules → see `motion.md`.
|
|
125
|
+
|
|
126
|
+
```css
|
|
127
|
+
--duration-instant: 80ms;
|
|
128
|
+
--duration-fast: 150ms;
|
|
129
|
+
--duration-normal: 250ms;
|
|
130
|
+
--duration-slow: 400ms;
|
|
131
|
+
|
|
132
|
+
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
|
133
|
+
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
134
|
+
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
135
|
+
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Z-index — semantic layers, never arbitrary numbers.**
|
|
139
|
+
|
|
140
|
+
```css
|
|
141
|
+
--z-base: 0;
|
|
142
|
+
--z-raised: 1;
|
|
143
|
+
--z-dropdown: 10;
|
|
144
|
+
--z-sticky: 20;
|
|
145
|
+
--z-modal-backdrop: 30;
|
|
146
|
+
--z-modal: 40;
|
|
147
|
+
--z-toast: 50;
|
|
148
|
+
--z-tooltip: 60;
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
> **The naming rule:** primitives are nouns about the value — `--gray-500`, `--space-md`, `--radius-lg`. Never role-named at this layer. `--button-bg` is a component token. `--text-primary` is a semantic token. Both are wrong here.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
### Layer 2: Semantic tokens
|
|
156
|
+
|
|
157
|
+
Contextual meaning. References primitives. This is the layer that switches between light and dark mode — primitives never change; semantics remap.
|
|
158
|
+
|
|
159
|
+
```css
|
|
160
|
+
:root {
|
|
161
|
+
/* Surface stack — 5 levels of elevation */
|
|
162
|
+
--surface-canvas: var(--gray-50); /* page background */
|
|
163
|
+
--surface-raised: var(--gray-100); /* cards, panels */
|
|
164
|
+
--surface-overlay: #fff; /* modals, sheets */
|
|
165
|
+
--surface-sunken: var(--gray-200); /* inset areas, code blocks */
|
|
166
|
+
--surface-inverse: var(--gray-900); /* inverted blocks, tooltips */
|
|
167
|
+
|
|
168
|
+
/* Text */
|
|
169
|
+
--text-primary: var(--gray-900);
|
|
170
|
+
--text-secondary: var(--gray-600);
|
|
171
|
+
--text-tertiary: var(--gray-400);
|
|
172
|
+
--text-on-accent: #fff;
|
|
173
|
+
--text-on-inverse: var(--gray-50);
|
|
174
|
+
--text-link: var(--accent-600);
|
|
175
|
+
--text-success: var(--green-600);
|
|
176
|
+
--text-warning: var(--amber-600);
|
|
177
|
+
--text-error: var(--red-600);
|
|
178
|
+
|
|
179
|
+
/* Border */
|
|
180
|
+
--border-subtle: oklch(0% 0 0 / 0.06);
|
|
181
|
+
--border-default: oklch(0% 0 0 / 0.12);
|
|
182
|
+
--border-strong: oklch(0% 0 0 / 0.24);
|
|
183
|
+
--border-focus: var(--accent-500);
|
|
184
|
+
--border-error: var(--red-400);
|
|
185
|
+
|
|
186
|
+
/* Accent */
|
|
187
|
+
--accent-bg: var(--accent-500);
|
|
188
|
+
--accent-bg-hover: var(--accent-600);
|
|
189
|
+
--accent-bg-active: var(--accent-700);
|
|
190
|
+
--accent-text: #fff;
|
|
191
|
+
--accent-border: var(--accent-400);
|
|
192
|
+
|
|
193
|
+
/* Status — bg / text / border per state */
|
|
194
|
+
--success-bg: oklch(96% 0.04 145);
|
|
195
|
+
--success-text: var(--green-600);
|
|
196
|
+
--success-border: var(--green-400);
|
|
197
|
+
|
|
198
|
+
--warning-bg: oklch(97% 0.04 70);
|
|
199
|
+
--warning-text: var(--amber-600);
|
|
200
|
+
--warning-border: var(--amber-400);
|
|
201
|
+
|
|
202
|
+
--error-bg: oklch(97% 0.04 25);
|
|
203
|
+
--error-text: var(--red-600);
|
|
204
|
+
--error-border: var(--red-400);
|
|
205
|
+
|
|
206
|
+
--info-bg: oklch(96% 0.04 250);
|
|
207
|
+
--info-text: var(--blue-600);
|
|
208
|
+
--info-border: var(--blue-400);
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Dark mode remaps semantics only — primitives are untouched:
|
|
213
|
+
|
|
214
|
+
```css
|
|
215
|
+
[data-theme="dark"] {
|
|
216
|
+
--surface-canvas: var(--gray-950);
|
|
217
|
+
--surface-raised: var(--gray-900);
|
|
218
|
+
--surface-overlay: var(--gray-800);
|
|
219
|
+
--surface-sunken: oklch(9% 0.008 60); /* darker than canvas */
|
|
220
|
+
--surface-inverse: var(--gray-50);
|
|
221
|
+
|
|
222
|
+
--text-primary: var(--gray-50);
|
|
223
|
+
--text-secondary: var(--gray-400);
|
|
224
|
+
--text-tertiary: var(--gray-600);
|
|
225
|
+
--text-on-inverse: var(--gray-900);
|
|
226
|
+
|
|
227
|
+
--border-subtle: oklch(100% 0 0 / 0.06);
|
|
228
|
+
--border-default: oklch(100% 0 0 / 0.12);
|
|
229
|
+
--border-strong: oklch(100% 0 0 / 0.24);
|
|
230
|
+
|
|
231
|
+
/* Accent desaturates ~12% in dark to prevent burn */
|
|
232
|
+
--accent-bg: oklch(58% 0.18 var(--accent-hue));
|
|
233
|
+
--accent-bg-hover: oklch(65% 0.18 var(--accent-hue));
|
|
234
|
+
--accent-bg-active: oklch(70% 0.18 var(--accent-hue));
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### Layer 3: Component tokens
|
|
241
|
+
|
|
242
|
+
Specific usage. References semantics. Created on demand per component — not pre-built as a blanket catalog.
|
|
243
|
+
|
|
244
|
+
```css
|
|
245
|
+
/* Example: button */
|
|
246
|
+
--button-primary-bg: var(--accent-bg);
|
|
247
|
+
--button-primary-bg-hover: var(--accent-bg-hover);
|
|
248
|
+
--button-primary-bg-active: var(--accent-bg-active);
|
|
249
|
+
--button-primary-text: var(--accent-text);
|
|
250
|
+
--button-primary-border-radius: var(--radius-md);
|
|
251
|
+
--button-primary-padding-x: var(--space-md);
|
|
252
|
+
--button-primary-padding-y: var(--space-sm);
|
|
253
|
+
|
|
254
|
+
/* Example: input */
|
|
255
|
+
--input-bg: var(--surface-canvas);
|
|
256
|
+
--input-border: var(--border-default);
|
|
257
|
+
--input-border-focus: var(--border-focus);
|
|
258
|
+
--input-border-error: var(--border-error);
|
|
259
|
+
--input-text: var(--text-primary);
|
|
260
|
+
--input-placeholder: var(--text-tertiary);
|
|
261
|
+
--input-border-radius: var(--radius-md);
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
> **When to create component tokens:** only when a component has multiple states or themes. A simple component referencing semantic tokens directly is fine — don't add a layer to prove you understand the system.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Light + Dark: Both Intentional
|
|
269
|
+
|
|
270
|
+
Dark mode is not the negation of light mode. Both are designed; neither is a fallback.
|
|
271
|
+
|
|
272
|
+
> **The intentional-dark test:** if your dark mode maps `--text-primary` from `gray-900` to `gray-100` and stops there, you inverted — you didn't design. Real dark mode rebalances the entire surface stack.
|
|
273
|
+
|
|
274
|
+
**The canvas rule.** `--surface-canvas` in dark sits between `gray-950` and `gray-900` with a slight hue tint. Pure `#000` reads as broken on any monitor with backlight bleed — it's also a cold dead black that strips warmth from everything above it.
|
|
275
|
+
|
|
276
|
+
**The accent rule.** Saturated accent colors burn on dark surfaces. Drop chroma 10-15% in OKLCH when switching to dark. The hue stays constant; only `C` shifts. This preserves brand recognition while reducing visual strain.
|
|
277
|
+
|
|
278
|
+
**The shadow rule.** Shadows are invisible on dark surfaces — black-on-near-black has no contrast. In dark mode: replace `box-shadow` depth with a `1px` border ring using `--border-default`, or a subtle top-edge highlight (`inset 0 1px 0 oklch(100% 0 0 / 0.08)`). Reserve box-shadow for colored glows only.
|
|
279
|
+
|
|
280
|
+
**The text rule.** Pure white (`#fff`) on dark backgrounds creates excessive halation on OLED screens. Use `--gray-50` or a warmer `oklch(97% 0.01 60)` as your lightest text value.
|
|
281
|
+
|
|
282
|
+
**The transition rule.** Always declare `color-scheme: light dark` for native form controls to adopt the right system rendering. Provide `prefers-color-scheme` for users without a toggle; respect the user's explicit toggle when present — never override it with system preference once the user has made a choice.
|
|
283
|
+
|
|
284
|
+
```css
|
|
285
|
+
/* Both modes in one block */
|
|
286
|
+
:root {
|
|
287
|
+
color-scheme: light dark;
|
|
288
|
+
|
|
289
|
+
/* Light defaults above */
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
@media (prefers-color-scheme: dark) {
|
|
293
|
+
:root:not([data-theme="light"]) {
|
|
294
|
+
/* Paste dark remaps here — same keys as light */
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
[data-theme="dark"] {
|
|
299
|
+
/* Explicit toggle — overrides media query */
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Token Categories Required
|
|
306
|
+
|
|
307
|
+
Every non-trivial UI needs all seven. Missing categories produce ad-hoc inline values that break theming.
|
|
308
|
+
|
|
309
|
+
| Category | Primitive examples | Semantic examples | Notes |
|
|
310
|
+
|---|---|---|---|
|
|
311
|
+
| Color | `--gray-50` → `--gray-950`, `--accent-50` → `--accent-950` | `--text-primary`, `--surface-raised`, `--accent-bg` | Light + dark both required |
|
|
312
|
+
| Spacing | `--space-xs` → `--space-4xl` | (typically used directly) | See `layout.md` for scale and rhythm rules |
|
|
313
|
+
| Type | `--text-xs` → `--text-5xl`, `--leading-tight`, `--font-medium` | `--font-display`, `--font-body`, `--font-mono` | See `typography.md` for scale and letter-spacing rules |
|
|
314
|
+
| Radii | `--radius-sm`, `--radius-md`, `--radius-lg`, `--radius-full` | `--radius-card`, `--radius-button`, `--radius-input` | Vary by element — uniform radius is the AI tell |
|
|
315
|
+
| Shadows | `--shadow-sm` → `--shadow-xl` | `--elevation-raised`, `--elevation-overlay`, `--elevation-modal` | Stack 2+ layers per shadow; dark mode requires border-ring replacement |
|
|
316
|
+
| Motion | `--duration-instant` → `--duration-slow`, `--ease-out`, `--ease-spring` | `--motion-hover`, `--motion-modal-in` | See `motion.md` for perceptual bands and choreography |
|
|
317
|
+
| Z-index | `--z-dropdown`, `--z-modal`, `--z-toast` | (typically used directly) | Semantic labels, never arbitrary numbers |
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## When to Extend vs. Replace
|
|
322
|
+
|
|
323
|
+
**If the project has a token system:**
|
|
324
|
+
- **Extend** — add the missing layer or category. The most common gap is missing semantics: primitives exist, but nothing switches for dark mode and no surface stack is defined.
|
|
325
|
+
- **Audit** — check dark mode is intentional (run the test above), semantic naming exists, all 7 categories are present.
|
|
326
|
+
- **Don't replace** unless the user explicitly asks. Token replacement is a multi-week refactor. Propose additions as patches, not rewrites.
|
|
327
|
+
|
|
328
|
+
**If the project has nothing:**
|
|
329
|
+
- **Establish primitives first** — color (neutral ramp + one accent), spacing (8pt scale), type (5 sizes + 3 weights). These three cover the majority of any UI.
|
|
330
|
+
- **Add semantics on demand** as components get built. Surface stack + text roles are almost always next.
|
|
331
|
+
- **Defer component tokens** until variant explosion — more than 2-3 states or themes — forces them.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## When the Token Spine Doesn't Apply
|
|
336
|
+
|
|
337
|
+
- **Single-page experiences** (landing pages, one-off campaign pages) — primitives + inline use is fine when nothing will be themed or reused. Semantics add no value if there's one theme and no components.
|
|
338
|
+
- **Adopted upstream systems** (Material, shadcn, Ant Design) — use the upstream tokens wholesale. Don't reinvent a parallel system alongside an existing one; that's two token systems to maintain.
|
|
339
|
+
- **Native iOS / Android** — platform tokens (`systemBackground`, `label`, `tint`) govern rendering. Custom tokens run parallel and cause drift.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Cross-References
|
|
344
|
+
|
|
345
|
+
- Spacing scale: see `layout.md` for the full table and spacing rhythm rule.
|
|
346
|
+
- Type scale: see `typography.md` for sizes, weights, scoped letter-spacing, and line-height by script.
|
|
347
|
+
- Color strategy: see `color.md` for OKLCH rationale, tinted neutrals, accent budget, and semantic palette structure.
|
|
348
|
+
- Motion durations: see `motion.md` for the duration scale, perceptual bands, and reduced-motion contract.
|
|
349
|
+
|
|
350
|
+
The spine ties these together. Each scale is its own discipline; the spine defines how they layer.
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# Typography
|
|
2
|
+
|
|
3
|
+
Type scale, font selection, readability, and weight systems.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Essentials
|
|
8
|
+
|
|
9
|
+
Apply these in all standard Latin-script web UI unless a specific context overrides:
|
|
10
|
+
|
|
11
|
+
- **`text-wrap: balance`** for headings; **`text-wrap: pretty`** for body
|
|
12
|
+
- **`font-variant-numeric: tabular-nums`** for data/numbers
|
|
13
|
+
- **Truncation handling** for dense UI; flex children need `min-w-0`
|
|
14
|
+
- **Smart punctuation**: curly quotes (`“` `”`), apostrophes (`’`), ellipsis (`…`), em-dash (`—`)
|
|
15
|
+
- **Non-breaking spaces**: `10 MB`, `⌘ K`, brand names, `$ 79/month`
|
|
16
|
+
|
|
17
|
+
**Font recommendations** — pick one family for body, optionally a second for display. In a single product surface, don't mix more than two typefaces; editorial layouts intentionally mix three or more for hierarchy.
|
|
18
|
+
|
|
19
|
+
Choose by genre and subject. These are examples to show the range, not defaults; use the project's fonts first, and say why when you pick one.
|
|
20
|
+
|
|
21
|
+
| Genre / subject | Examples |
|
|
22
|
+
|----------|-------------|
|
|
23
|
+
| Dense data and tooling | IBM Plex Sans, Source Sans 3, Atkinson Hyperlegible |
|
|
24
|
+
| Editorial and long-form | Newsreader, Source Serif 4, Literata, Alegreya |
|
|
25
|
+
| Technical or workshop feel | Space Grotesk, Barlow, Archivo |
|
|
26
|
+
| Warm, human, consumer | Nunito Sans, Figtree, Lexend |
|
|
27
|
+
| Monospace for code and IDs | JetBrains Mono, IBM Plex Mono, Commit Mono |
|
|
28
|
+
| No web font wanted | `system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif` |
|
|
29
|
+
|
|
30
|
+
**A font you would reach for on any project is a default, not a choice.** On landings, portfolios, and brand surfaces the display face carries voice — reaching for the same sans every build produces monoculture. Selection procedure for marketing display type:
|
|
31
|
+
|
|
32
|
+
1. Write three concrete brand-voice words from the brief ("warm, mechanical, opinionated" — not "modern, clean").
|
|
33
|
+
2. Note the font you'd reach for by reflex; if it's the same face your last marketing build used, reject it and rotate.
|
|
34
|
+
3. Pick for the voice words, then cross-check: "creative brief = serif" is itself a reflex — a distinctive sans display (Cabinet Grotesk, Satoshi, GT Walsheim class) can fit a creative/premium brief; choose by the voice words, not by habit. Serif display only when the brief is genuinely editorial, luxury, or publication-shaped, and rotate which serif.
|
|
35
|
+
4. Emphasize within a headline using italic or bold of the **same family** — never inject a one-word serif into a sans headline for "visual interest".
|
|
36
|
+
|
|
37
|
+
**Italic descender clearance:** italic display words containing `y g j p q` clip under `line-height: 1`. Use ≥1.1 and reserve bottom padding on the wrapper.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Type Hierarchy
|
|
42
|
+
|
|
43
|
+
Create a clear scale from most important to least. Two weights (regular + one of
|
|
44
|
+
semibold/bold) cover most products; every added weight is another hierarchy level readers
|
|
45
|
+
must decode. For long-form reading (articles, docs) the body floor is 18px — 14-16px serves
|
|
46
|
+
UI labels and controls, not sustained reading.
|
|
47
|
+
|
|
48
|
+
### The ladder is what you use, not what you define
|
|
49
|
+
|
|
50
|
+
A nine-step scale is a palette. The **ladder** is the four to six steps that actually appear
|
|
51
|
+
in the built page, and it is the ladder a reader sees. Emitting most of a modular scale
|
|
52
|
+
produces a gradient of sizes where every step is 1.2x the last — legible, forgettable, and
|
|
53
|
+
the single loudest tell of a surface built by an agent rather than designed.
|
|
54
|
+
|
|
55
|
+
Measured on four surfaces whose typography is the reason people copy them (a project tool, a
|
|
56
|
+
deploy platform, a voice API, a commerce framework), at 2120x1143:
|
|
57
|
+
|
|
58
|
+
| | A | B | C | D |
|
|
59
|
+
|---|---|---|---|---|
|
|
60
|
+
| distinct sizes rendered in the fold | 9 | **4** | 5 | **4** |
|
|
61
|
+
| sizes below 14px | 4 | **0** | 2 | 2 |
|
|
62
|
+
| display size | 64 | 64 | 48 | 64 |
|
|
63
|
+
| next size used below it | 20 | 24 | 16 | 16 |
|
|
64
|
+
| **the jump** | **3.2x** | **2.7x** | **3.0x** | **4.0x** |
|
|
65
|
+
| weight of the display type | 510 | 450-500 | 400 | 500 |
|
|
66
|
+
| distinct weights | 3 | 3 | 3 | **2** |
|
|
67
|
+
|
|
68
|
+
Three rules fall out of that table, and all three are checkable:
|
|
69
|
+
|
|
70
|
+
1. **Four to six steps, not nine.** One label size, one body size, one intermediate, one
|
|
71
|
+
section head, one display. Collapse everything else onto the nearest step. Half-pixel
|
|
72
|
+
neighbours (13px and 13.5px) are never a distinction — they are indecision.
|
|
73
|
+
2. **The display step sits 2.5x to 4x above the step below it, with nothing in between.**
|
|
74
|
+
Display type is made by the **gap**, not by the size: 56px directly above 44px reads as
|
|
75
|
+
slightly bigger text, while 76px above 30px reads as a headline. If the jump is small,
|
|
76
|
+
either raise the display size or delete the step under it.
|
|
77
|
+
3. **Display type is not bold.** None of the four sets its largest type above 510. Big and
|
|
78
|
+
bold reads cheap — a poster made in a hurry; big and medium reads like the size was
|
|
79
|
+
already enough. Reserve 600-700 for 13-16px labels and buttons, where weight is the only
|
|
80
|
+
emphasis available.
|
|
81
|
+
|
|
82
|
+
Corollary on small type: seven sizes under 14px is how a landing page ends up reading as a
|
|
83
|
+
dashboard. Two is plenty, and one of those should be the mono label size.
|
|
84
|
+
|
|
85
|
+
### Scale (a palette to choose from, not a set to emit)
|
|
86
|
+
```css
|
|
87
|
+
--text-xs: 0.75rem; /* 12px - mono labels, captions */
|
|
88
|
+
--text-sm: 0.875rem; /* 14px - secondary text */
|
|
89
|
+
--text-base: 1rem; /* 16px - body text */
|
|
90
|
+
--text-lg: 1.25rem; /* 20px - lead text */
|
|
91
|
+
--text-xl: 1.875rem; /* 30px - section heads */
|
|
92
|
+
--text-2xl: 2.75rem; /* 44px - the one big number, on data surfaces */
|
|
93
|
+
--text-3xl: 4.75rem; /* 76px - display */
|
|
94
|
+
```
|
|
95
|
+
Pick four to six of these per surface and use nothing else. A dense console legitimately
|
|
96
|
+
sits low on the ladder (11 / 13 / 16 / 22 / 64); a restaurant page legitimately skips the
|
|
97
|
+
middle entirely (12 / 15 / 30 / 88). Both are ladders. Twelve evenly-spaced steps is not.
|
|
98
|
+
|
|
99
|
+
Match the *floor* to the product type — dense apps start at 11-13px, marketing at 13-16px —
|
|
100
|
+
but the jump to display stays large in both. A console with a 2.9x jump to its one headline
|
|
101
|
+
number is right; a console with twelve steps is not.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Font Selection
|
|
106
|
+
|
|
107
|
+
### Principles
|
|
108
|
+
- **Display fonts** for headlines — distinctive, personality-rich. A font excellent for display (high contrast, tight spacing) is wrong for body text at 16px.
|
|
109
|
+
- **Body fonts** for running text — readable, neutral, well-hinted at small sizes. A workhorse body font (Charter, IBM Plex Sans) often looks bland at hero scale — that's fine, just don't ask it to do both jobs.
|
|
110
|
+
- **UI fonts** for labels and dense interfaces — optimized x-height, open apertures. Inter and Geist are UI fonts first; using them at 48px display is fine, but don't expect typographic personality.
|
|
111
|
+
- **Monospace** as intentional accent — not as lazy "dev tool" default
|
|
112
|
+
- **Variable fonts** for flexibility — one file, many weights
|
|
113
|
+
- **Subset fonts** — ship only code points/scripts you use
|
|
114
|
+
|
|
115
|
+
### Loading
|
|
116
|
+
```html
|
|
117
|
+
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
|
|
118
|
+
```
|
|
119
|
+
```css
|
|
120
|
+
@font-face {
|
|
121
|
+
font-family: 'Main';
|
|
122
|
+
src: url('/fonts/main.woff2') format('woff2');
|
|
123
|
+
font-display: swap;
|
|
124
|
+
unicode-range: U+0000-007F; /* Basic Latin only */
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**`font-synthesis: none`** on any family missing a weight or style file. Without it, the browser fakes bold by smearing the outline and fakes italic by shearing it — synthesized glyphs that ship silently to production. Setting `font-synthesis: none` makes the gap fail visibly in development (regular weight renders where bold was requested) so it gets caught before ship, instead of shipping fake glyphs users never notice as wrong but perceive as slightly off.
|
|
129
|
+
|
|
130
|
+
### Feature Control: Properties Over Raw Tags
|
|
131
|
+
|
|
132
|
+
When a high-level CSS property and a raw OpenType feature tag both produce the same visual result, take the property. **Why it matters more than it looks:** a property degrades gracefully — a fallback font that lacks the matching axis or feature just ignores the property and falls back to its own default rendering, no error, nothing visibly broken. A raw feature tag has no such fallback path; it silently stops applying, and the gap stays invisible until someone diffs the rendered output against the design.
|
|
133
|
+
|
|
134
|
+
Where this shows up in practice: `font-variant-numeric: tabular-nums slashed-zero` instead of a hand-written feature-tag equivalent, for the tabular figures this skill already asks for anywhere numbers stack in a column; `font-weight` instead of `font-variation-settings: 'wght' 600` on variable fonts; `font-variant-caps` instead of a raw `font-feature-settings` string for small caps.
|
|
135
|
+
|
|
136
|
+
### Letter-Spacing by Size
|
|
137
|
+
|
|
138
|
+
These rules apply to **Latin script, sans-serif and display faces** unless stated otherwise. Do not adjust tracking on CJK, Arabic, Devanagari, or other non-Latin scripts unless you deeply understand their typographic conventions — the font's built-in metrics handle it. Serif faces are designed with tracking already optimized across sizes; tightening them at display sizes damages their rhythm.
|
|
139
|
+
|
|
140
|
+
- **Display (≥24px), sans-serif Latin**: tighten to `-0.02em` to `-0.04em` — large sizes optically appear loose at default tracking. `tracking-tight` in Tailwind.
|
|
141
|
+
> **When it breaks:** serif faces (Playfair, Freight, Garamond) — leave at default. The built-in sidebearings were set for the size.
|
|
142
|
+
- **Body text (14-18px)**: leave `letter-spacing` alone — the font designer optimized it. This holds for all scripts and classifications.
|
|
143
|
+
- **Small text/labels (11-13px), Latin**: slight positive tracking `+0.01em` to `+0.02em` improves readability at tight optical sizes. `tracking-wide` in Tailwind.
|
|
144
|
+
> **When it breaks:** CJK labels — already have generous inter-glyph spacing; adding more creates uneven color.
|
|
145
|
+
- **ALL CAPS labels, Latin**: `+0.05em` to `+0.1em` — all-caps removes descender space and needs tracking to stay readable. `tracking-widest` in Tailwind.
|
|
146
|
+
> **When it breaks:** Not a universal Never. ALL CAPS is acceptable for small category labels (10-13px), regulatory text, and utilitarian aesthetics — just always add tracking when you do it.
|
|
147
|
+
|
|
148
|
+
### Never
|
|
149
|
+
- Use system fonts when personality matters — system stacks are fine for utilitarian UI but they signal "no design intent" in brand-facing contexts
|
|
150
|
+
- Mix more than 2-3 typefaces **in a single product surface** — editorial layouts (magazines, marketing pages) intentionally exceed this for typographic hierarchy
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Readability
|
|
155
|
+
|
|
156
|
+
### Line Length
|
|
157
|
+
- **Prose body text**: 45-75 characters per line (ideal: 66). Use `max-width: 65ch` on text containers.
|
|
158
|
+
> **When it breaks:** UI labels, buttons, table cells, and dense data layouts tolerate much shorter or longer lines. The 65ch rule is for continuous reading, not UI components.
|
|
159
|
+
|
|
160
|
+
### Line Height
|
|
161
|
+
|
|
162
|
+
Line height is script- and x-height-dependent — no single value works universally.
|
|
163
|
+
|
|
164
|
+
- **Body text (14-18px), Latin**: 1.5 to 1.65. Tall x-height fonts (Inter, Geist) tolerate the lower end; short x-height faces (Garamond, Freight) may need slightly tighter — test visually.
|
|
165
|
+
- **Display headlines (≥24px)**: 1.05 to 1.2. Headlines need to feel tight; a 1.5 line-height on a 48px heading looks airy and unintentional.
|
|
166
|
+
- **UI labels and dense interfaces**: 1.3 to 1.4. Enough air to avoid collision, not so much that the interface feels sparse.
|
|
167
|
+
- **CJK scripts**: 1.7 to 1.85 — CJK glyphs have different vertical metrics and need more inter-line clearance than Latin at the same size.
|
|
168
|
+
> **When it breaks:** Applying 1.5 body line-height to display text; applying CJK ratios to Latin body text (creates too much vertical space).
|
|
169
|
+
|
|
170
|
+
### Text Wrapping
|
|
171
|
+
```css
|
|
172
|
+
h1, h2, h3, h4 { text-wrap: balance; }
|
|
173
|
+
p, li, dd { text-wrap: pretty; }
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
- **`text-wrap: balance`** — even line lengths for headings
|
|
177
|
+
- **`text-wrap: pretty`** — avoids widows/orphans in body text
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Data Typography
|
|
182
|
+
|
|
183
|
+
```css
|
|
184
|
+
/* Tabular numbers for data alignment */
|
|
185
|
+
.data-value { font-variant-numeric: tabular-nums; }
|
|
186
|
+
|
|
187
|
+
/* Or use a monospace font for data-heavy tables */
|
|
188
|
+
.data-table { font-family: var(--font-mono, monospace); }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
- **`tabular-nums`** for any numbers that align vertically in columns (tables, prices, stats) — this is a near-universal rule for data UI; the exception is decorative numerals in display headings where proportional figures look better
|
|
192
|
+
- **Truncate dense UI**: `truncate` or `line-clamp-*`
|
|
193
|
+
- **Flex children need `min-w-0`** to allow truncation
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Text Handling
|
|
198
|
+
|
|
199
|
+
### Content Overflow
|
|
200
|
+
```css
|
|
201
|
+
/* Single line truncation */
|
|
202
|
+
.truncate {
|
|
203
|
+
overflow: hidden;
|
|
204
|
+
text-overflow: ellipsis;
|
|
205
|
+
white-space: nowrap;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* Multi-line clamp */
|
|
209
|
+
.line-clamp-3 {
|
|
210
|
+
display: -webkit-box;
|
|
211
|
+
-webkit-line-clamp: 3;
|
|
212
|
+
-webkit-box-orient: vertical;
|
|
213
|
+
overflow: hidden;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* Flex children MUST have min-w-0 */
|
|
217
|
+
.flex-child {
|
|
218
|
+
min-width: 0; /* allows text to truncate */
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Special Characters
|
|
223
|
+
- **Curly quotes**: " " not " "
|
|
224
|
+
- **Ellipsis character**: … not ...
|
|
225
|
+
- **Non-breaking spaces**: `10 MB`, `⌘ K`, brand names
|
|
226
|
+
- **`scroll-margin-top`** on headings for anchor links
|
|
227
|
+
|
|
228
|
+
### Resilience
|
|
229
|
+
- Layouts handle short, average, AND very long content
|
|
230
|
+
- Handle empty strings without broken UI
|
|
231
|
+
- Locale-aware: `Intl.DateTimeFormat`, `Intl.NumberFormat`
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Cap-Height Trimming & Underlines
|
|
236
|
+
|
|
237
|
+
- **`text-box: trim-both cap alphabetic`** strips out the half-leading a browser adds above and below the glyph outlines — that reserved sliver is what makes a single-line label inside a pill, chip, or button look like it's drifted below true center instead of sitting on it. Until support is universal, the old manual counter-measure still works: nudge the text node with a small negative margin or padding tuned to the font's own metrics.
|
|
238
|
+
- **`text-underline-position: from-font`** and **`text-decoration-thickness: from-font`** pull the underline's offset and weight from the font file's own metrics instead of the browser's generic guess — closer underlines on script-adjacent faces, correctly-weighted underlines on heavier display fonts.
|
|
239
|
+
- **Reserve dotted underlines for "more info" affordances** — glossary terms, `<abbr>`, inline definitions — not for links. A dotted underline reads as "hover for detail," and putting it on a normal link signals the wrong interaction.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Anti-aliasing
|
|
244
|
+
|
|
245
|
+
- **Root smoothing (macOS):** apply `-webkit-font-smoothing: antialiased` + `-moz-osx-font-smoothing: grayscale` once on `html` (Tailwind: `antialiased` on the root element). macOS renders text heavier than intended by default; this thins it for crisper text. Set it ONCE at the root — never per-element, or smoothed and unsmoothed text end up with visibly different weights. No-op on other platforms, safe to apply universally.
|
|
246
|
+
- Scaling text via `transform` can change smoothing
|
|
247
|
+
- Prefer animating a wrapper instead of text node directly
|
|
248
|
+
- If artifacts persist: `translateZ(0)` or `will-change: transform` to promote layer
|