ima2-gen 2.0.15 → 2.0.16

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.
Files changed (125) hide show
  1. package/README.md +30 -0
  2. package/bin/commands/skill.js +336 -17
  3. package/bin/ima2.js +22 -2
  4. package/bin/lib/doctor-checks.js +6 -4
  5. package/config.js +1 -0
  6. package/docs/CLI.md +25 -3
  7. package/docs/PROMPT_STUDIO.ko.md +29 -0
  8. package/docs/PROMPT_STUDIO.md +31 -0
  9. package/docs/migration/runtime-test-inventory.md +7 -1
  10. package/lib/agentImageVideoGen.js +8 -0
  11. package/lib/agentQueueStore.js +36 -10
  12. package/lib/agentQueueWorker.js +79 -7
  13. package/lib/agentRuntime.js +2 -0
  14. package/lib/assetLifecycle.js +40 -8
  15. package/lib/canvasVersionStore.js +86 -0
  16. package/lib/cardNewsGenerator.js +37 -3
  17. package/lib/cardNewsJobStore.js +10 -0
  18. package/lib/cardNewsManifestStore.js +6 -12
  19. package/lib/cardNewsPath.js +25 -0
  20. package/lib/db.js +2 -0
  21. package/lib/generatePipeline.js +474 -0
  22. package/lib/generationInputValidation.js +32 -0
  23. package/lib/grokImageCore.js +18 -1
  24. package/lib/historyIndex.js +11 -4
  25. package/lib/historyList.js +3 -0
  26. package/lib/imageMetadata.js +3 -0
  27. package/lib/inflight.js +30 -3
  28. package/lib/multimodePipeline.js +462 -0
  29. package/lib/nodeGeneration.js +440 -0
  30. package/lib/nodeValidation.js +23 -0
  31. package/lib/oauthProxy/generators.js +3 -246
  32. package/lib/oauthProxy/multimodeGenerators.js +251 -0
  33. package/lib/routeHelpers.js +9 -2
  34. package/package.json +2 -2
  35. package/routes/agent.js +4 -4
  36. package/routes/canvasVersions.js +21 -1
  37. package/routes/cardNews.js +2 -1
  38. package/routes/edit.js +25 -9
  39. package/routes/events.js +5 -1
  40. package/routes/generate.js +2 -481
  41. package/routes/keys.js +31 -39
  42. package/routes/multimode.js +2 -502
  43. package/routes/nodes.js +3 -448
  44. package/routes/video.js +12 -3
  45. package/routes/videoExtended.js +19 -4
  46. package/server.js +53 -1
  47. package/skills/ima2/SKILL.md +204 -0
  48. package/skills/ima2-front/SKILL.md +611 -0
  49. package/skills/ima2-front/references/a11y-patterns.md +134 -0
  50. package/skills/ima2-front/references/aesthetics.md +327 -0
  51. package/skills/ima2-front/references/anti-slop.md +241 -0
  52. package/skills/ima2-front/references/asset-requirements.md +431 -0
  53. package/skills/ima2-front/references/brand-asset-sourcing.md +122 -0
  54. package/skills/ima2-front/references/color-system.md +132 -0
  55. package/skills/ima2-front/references/consistency-locks.md +20 -0
  56. package/skills/ima2-front/references/crud-ui.md +53 -0
  57. package/skills/ima2-front/references/dropdown-layer.md +110 -0
  58. package/skills/ima2-front/references/i18n-global.md +104 -0
  59. package/skills/ima2-front/references/iterative-design.md +90 -0
  60. package/skills/ima2-front/references/korea-2026.md +174 -0
  61. package/skills/ima2-front/references/layout-discipline.md +161 -0
  62. package/skills/ima2-front/references/liquid-glass.md +181 -0
  63. package/skills/ima2-front/references/logo-sections.md +194 -0
  64. package/skills/ima2-front/references/mobile-ux.md +144 -0
  65. package/skills/ima2-front/references/performance-budget.md +106 -0
  66. package/skills/ima2-front/references/preflight-full.md +58 -0
  67. package/skills/ima2-front/references/product-density.md +53 -0
  68. package/skills/ima2-front/references/prototype-variants.md +54 -0
  69. package/skills/ima2-front/references/reference-capture.md +120 -0
  70. package/skills/ima2-front/references/responsive-viewport.md +139 -0
  71. package/skills/ima2-front/references/seo-baseline.md +123 -0
  72. package/skills/ima2-front/references/soft-3d-asset-gates.md +70 -0
  73. package/skills/ima2-front/references/stacks/astro.md +204 -0
  74. package/skills/ima2-front/references/stacks/mobile-native.md +281 -0
  75. package/skills/ima2-front/references/stacks/nextjs.md +219 -0
  76. package/skills/ima2-front/references/stacks/react.md +264 -0
  77. package/skills/ima2-front/references/stacks/svelte.md +235 -0
  78. package/skills/ima2-front/references/stacks/vanilla.md +226 -0
  79. package/skills/ima2-front/references/theme-switching.md +82 -0
  80. package/skills/ima2-front/references/top-bar.md +126 -0
  81. package/skills/ima2-front/references/typography-wrapping.md +270 -0
  82. package/skills/ima2-front/references/ux-writing-ko.md +62 -0
  83. package/skills/ima2-front/references/visual-verification.md +102 -0
  84. package/skills/ima2-uiux/SKILL.md +477 -0
  85. package/skills/ima2-uiux/references/anti-slop-judgment.md +39 -0
  86. package/skills/ima2-uiux/references/color-system.md +80 -0
  87. package/skills/ima2-uiux/references/design-isms.md +194 -0
  88. package/skills/ima2-uiux/references/design-read-example.md +33 -0
  89. package/skills/ima2-uiux/references/design-system-bootstrap.md +133 -0
  90. package/skills/ima2-uiux/references/favicon-logo.md +355 -0
  91. package/skills/ima2-uiux/references/form-patterns.md +118 -0
  92. package/skills/ima2-uiux/references/intent-discovery-ladder.md +86 -0
  93. package/skills/ima2-uiux/references/korean-design-vocabulary.md +52 -0
  94. package/skills/ima2-uiux/references/layout-macrostructures.md +54 -0
  95. package/skills/ima2-uiux/references/logo-trust-sections.md +96 -0
  96. package/skills/ima2-uiux/references/mobile-native-ux.md +207 -0
  97. package/skills/ima2-uiux/references/product-personalities.md +118 -0
  98. package/skills/ima2-uiux/references/responsive-nav.md +66 -0
  99. package/skills/ima2-uiux/references/typography-line-breaks.md +193 -0
  100. package/skills/ima2-uiux/references/ux-preflight.md +65 -0
  101. package/skills/ima2-uiux/references/ux-states.md +197 -0
  102. package/skills/ima2-uiux/references/visual-hierarchy.md +115 -0
  103. package/ui/dist/.vite/manifest.json +13 -13
  104. package/ui/dist/assets/AgentWorkspace-CtYt4SF5.js +3 -0
  105. package/ui/dist/assets/{CardNewsWorkspace-Cdxn1ohU.js → CardNewsWorkspace-DN5cVqG5.js} +1 -1
  106. package/ui/dist/assets/GenerationRequestLogPanel-DnmUQdKR.js +1 -0
  107. package/ui/dist/assets/{NodeCanvas-C67sLboA.js → NodeCanvas-CxpfIBI0.js} +1 -1
  108. package/ui/dist/assets/PromptBuilderPanel-C2R3ObtR.js +2 -0
  109. package/ui/dist/assets/{PromptImportDialog-DeQXsEEv.js → PromptImportDialog-BIxz_yEx.js} +2 -2
  110. package/ui/dist/assets/PromptImportDiscoverySection-BQTlPMME.js +1 -0
  111. package/ui/dist/assets/PromptImportFolderSection-Ds_Th9O3.js +1 -0
  112. package/ui/dist/assets/{PromptLibraryPanel-Db3xEPM_.js → PromptLibraryPanel-Rs4l45pV.js} +2 -2
  113. package/ui/dist/assets/{SettingsWorkspace-BDk_1W-V.js → SettingsWorkspace-p1AZ6uT9.js} +1 -1
  114. package/ui/dist/assets/index-0-_vgFGs.js +4 -0
  115. package/ui/dist/assets/index-Dm3pFxV4.js +23 -0
  116. package/ui/dist/assets/index-J8yDF3Ch.css +1 -0
  117. package/ui/dist/index.html +2 -2
  118. package/ui/dist/assets/AgentWorkspace-DAg_7zpY.js +0 -3
  119. package/ui/dist/assets/GenerationRequestLogPanel-C_qvEUi2.js +0 -1
  120. package/ui/dist/assets/PromptBuilderPanel-DjvVdAie.js +0 -2
  121. package/ui/dist/assets/PromptImportDiscoverySection-CrwyUKYI.js +0 -1
  122. package/ui/dist/assets/PromptImportFolderSection-CToGMqYE.js +0 -1
  123. package/ui/dist/assets/index-2oG6in1i.css +0 -1
  124. package/ui/dist/assets/index-CoxMOXAU.js +0 -23
  125. package/ui/dist/assets/index-p8egnGHk.js +0 -4
@@ -0,0 +1,226 @@
1
+ # Vanilla Stack — HTML + CSS + JS (No Framework)
2
+
3
+ Rules for building production-quality frontends without React/Vue/etc.
4
+ Read `core/aesthetics.md` + `core/anti-slop.md` first.
5
+
6
+ ---
7
+
8
+ ## Core Principle: Zero Dependencies
9
+
10
+ Single self-contained HTML files with inline CSS/JS. No npm, no build tools, no bundler.
11
+ The file IS the deliverable.
12
+
13
+ ---
14
+
15
+ ## Structure
16
+
17
+ ```html
18
+ <!DOCTYPE html>
19
+ <html lang="ko">
20
+ <head>
21
+ <meta charset="UTF-8" />
22
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
23
+ <title>Page Title</title>
24
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
25
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;500;700&display=swap" rel="stylesheet" />
26
+ <style>
27
+ /* === DESIGN TOKENS === */
28
+ :root {
29
+ --color-primary: #0ea5e9;
30
+ --color-surface: #fafafa;
31
+ --color-text: #18181b;
32
+ --color-muted: #71717a;
33
+ --font-display: 'Outfit', sans-serif;
34
+ --font-body: 'Outfit', sans-serif;
35
+ --radius: 0.75rem;
36
+ --max-width: 1200px;
37
+ }
38
+
39
+ /* === RESET === */
40
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
41
+ body { font-family: var(--font-body); color: var(--color-text); background: var(--color-surface); }
42
+
43
+ /* === LAYOUT === */
44
+ /* ... */
45
+
46
+ /* === COMPONENTS === */
47
+ /* ... */
48
+
49
+ /* === ANIMATIONS === */
50
+ /* ... */
51
+
52
+ /* === RESPONSIVE === */
53
+ @media (max-width: 768px) { /* ... */ }
54
+
55
+ /* === REDUCED MOTION === */
56
+ @media (prefers-reduced-motion: reduce) {
57
+ *, *::before, *::after {
58
+ animation-duration: 0.01ms !important;
59
+ transition-duration: 0.01ms !important;
60
+ }
61
+ }
62
+ </style>
63
+ </head>
64
+ <body>
65
+ <!-- Semantic HTML -->
66
+ <script>
67
+ // Minimal JS — progressive enhancement only
68
+ </script>
69
+ </body>
70
+ </html>
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Typography
76
+
77
+ Use fonts from **Google Fonts** or **Fontshare** — never system fonts.
78
+
79
+ ```html
80
+ <!-- Fontshare (free, high quality) -->
81
+ <link href="https://api.fontshare.com/v2/css?f[]=satoshi@400;500;700&display=swap" rel="stylesheet" />
82
+
83
+ <!-- Google Fonts -->
84
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;500;700&display=swap" rel="stylesheet" />
85
+ ```
86
+
87
+ ### Fluid Typography (Mandatory)
88
+ ```css
89
+ h1 { font-size: clamp(2rem, 1rem + 3.6vw, 4rem); }
90
+ h2 { font-size: clamp(1.5rem, 1rem + 1.4vw, 2.25rem); }
91
+ p { font-size: clamp(1rem, 0.95rem + 0.2vw, 1.125rem); }
92
+ ```
93
+
94
+ **NEVER** use fixed `px` for text. Always `clamp()`.
95
+
96
+ ---
97
+
98
+ ## CSS Animation (Preferred over JS)
99
+
100
+ ### Staggered Reveal on Load
101
+ ```css
102
+ .reveal {
103
+ opacity: 0;
104
+ transform: translateY(20px);
105
+ animation: fadeUp 0.6s ease forwards;
106
+ }
107
+ .reveal:nth-child(1) { animation-delay: 0.1s; }
108
+ .reveal:nth-child(2) { animation-delay: 0.2s; }
109
+ .reveal:nth-child(3) { animation-delay: 0.3s; }
110
+
111
+ @keyframes fadeUp {
112
+ to { opacity: 1; transform: translateY(0); }
113
+ }
114
+ ```
115
+
116
+ ### CSS Custom Property for Stagger Index
117
+ ```css
118
+ .reveal {
119
+ animation-delay: calc(var(--index, 0) * 100ms);
120
+ }
121
+ ```
122
+ ```html
123
+ <div class="reveal" style="--index: 0">First</div>
124
+ <div class="reveal" style="--index: 1">Second</div>
125
+ ```
126
+
127
+ ### Hover Effects
128
+ ```css
129
+ .card {
130
+ transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1),
131
+ box-shadow 0.3s ease;
132
+ }
133
+ .card:hover {
134
+ transform: translateY(-4px);
135
+ box-shadow: 0 20px 40px -15px rgba(0,0,0,0.08);
136
+ }
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Viewport Fitting (Critical for Full-Page Layouts)
142
+
143
+ ```css
144
+ .section-full {
145
+ min-height: 100dvh; /* NOT 100vh — iOS Safari breaks */
146
+ display: grid;
147
+ place-items: center;
148
+ overflow: hidden;
149
+ }
150
+ ```
151
+
152
+ **Content Density Limits per Section:**
153
+
154
+ | Type | Maximum |
155
+ | ------------ | --------------------------------------- |
156
+ | Hero | 1 heading + 1 subtitle + 1 CTA |
157
+ | Content | 1 heading + 4-6 bullets OR 2 paragraphs |
158
+ | Feature grid | 1 heading + 6 cards max (2×3) |
159
+ | Quote | 1 quote (max 3 lines) + attribution |
160
+
161
+ Content exceeds limits? Split into multiple sections.
162
+
163
+ ---
164
+
165
+ ## Responsive Layout
166
+
167
+ ```css
168
+ /* Mobile-first */
169
+ .grid {
170
+ display: grid;
171
+ gap: 1.5rem;
172
+ grid-template-columns: 1fr;
173
+ }
174
+
175
+ @media (min-width: 768px) {
176
+ .grid { grid-template-columns: repeat(2, 1fr); }
177
+ }
178
+
179
+ @media (min-width: 1024px) {
180
+ .grid { grid-template-columns: repeat(3, 1fr); }
181
+ }
182
+
183
+ /* Container */
184
+ .container {
185
+ width: 100%;
186
+ max-width: var(--max-width);
187
+ margin: 0 auto;
188
+ padding: 0 1rem;
189
+ }
190
+ ```
191
+
192
+ **NEVER** use `calc()` flexbox math. Always CSS Grid.
193
+
194
+ ---
195
+
196
+ ## Progressive Enhancement
197
+
198
+ 1. Content readable without JS
199
+ 2. Layout works without CSS animations
200
+ 3. JS adds interactivity, not structure
201
+ 4. Use `<noscript>` for critical JS-dependent features
202
+
203
+ ---
204
+
205
+ ## Semantic HTML (Mandatory)
206
+
207
+ ```html
208
+ <header>...</header>
209
+ <nav aria-label="Main navigation">...</nav>
210
+ <main id="main-content">
211
+ <section aria-labelledby="features-heading">
212
+ <h2 id="features-heading">Features</h2>
213
+ </section>
214
+ </main>
215
+ <footer>...</footer>
216
+ ```
217
+
218
+ Use `<button>` for actions, `<a>` for navigation. Never `<div onclick>`.
219
+
220
+ ---
221
+
222
+ ## File Delivery
223
+
224
+ Output a single `.html` file. All CSS in `<style>`, all JS in `<script>`.
225
+ Every section needs `/* === SECTION NAME === */` comments.
226
+ The file should be openable directly in a browser — no build step.
@@ -0,0 +1,82 @@
1
+ # Theme / Dark Mode
2
+
3
+ ## Implementation
4
+
5
+ Use `data-theme` attribute on `<html>`, not class-based toggle.
6
+
7
+ ```css
8
+ :root {
9
+ --bg-primary: oklch(98% 0 0);
10
+ --text-primary: oklch(15% 0 0);
11
+ }
12
+
13
+ :root[data-theme="dark"] {
14
+ --bg-primary: oklch(12% 0 0);
15
+ --text-primary: oklch(92% 0 0);
16
+ }
17
+
18
+ @media (prefers-color-scheme: dark) {
19
+ :root:not([data-theme]) {
20
+ --bg-primary: oklch(12% 0 0);
21
+ --text-primary: oklch(92% 0 0);
22
+ }
23
+ }
24
+ ```
25
+
26
+ - `data-theme` takes precedence over media query
27
+ - System preference is the fallback when no explicit choice
28
+ - All colors MUST use CSS custom properties
29
+ (token layering + `oklch()`/`light-dark()` mechanics: `color-system.md`)
30
+
31
+ ## Flash of Wrong Theme (FOWT) Prevention
32
+
33
+ ```html
34
+ <script>
35
+ (function() {
36
+ var t = localStorage.getItem('theme');
37
+ if (t === 'dark' || t === 'light') {
38
+ document.documentElement.setAttribute('data-theme', t);
39
+ }
40
+ })();
41
+ </script>
42
+ ```
43
+
44
+ - Inline in `<head>`, before any stylesheet (< 200 bytes)
45
+ - SSR: read theme cookie server-side, set `data-theme` in HTML response
46
+
47
+ ## Toggle Component
48
+
49
+ Three states: Light → Dark → System → Light.
50
+
51
+ - Store: `localStorage.setItem('theme', 'dark' | 'light' | 'system')`
52
+ - `system` removes `data-theme`, lets media query decide
53
+ - Accessible: `role="button"`, `aria-label="Switch to dark theme"`
54
+ - Position: header or settings, never hidden in submenu
55
+
56
+ ## Theme Transition
57
+
58
+ ```css
59
+ :root[data-theme-transitioning] * {
60
+ transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease !important;
61
+ }
62
+ ```
63
+
64
+ - Add transitioning attribute on toggle, remove after 200ms
65
+ - Only transition color properties
66
+ - Respect `prefers-reduced-motion`: skip transition
67
+ - Never animate on page load
68
+
69
+ ## Component Checklist
70
+
71
+ - [ ] All colors use custom properties
72
+ - [ ] Shadows lighter in dark mode
73
+ - [ ] White-background images get border in dark mode
74
+ - [ ] SVG icons use `currentColor`
75
+ - [ ] Borders use surface-level difference in dark mode
76
+ - [ ] Charts/data-viz legible in both themes
77
+ - [ ] Form inputs have sufficient contrast in both themes
78
+
79
+ ## Cross-references
80
+
81
+ - Dark token derivation: `dev-uiux-design/references/color-system.md`
82
+ - One theme per page: `consistency-locks.md`
@@ -0,0 +1,126 @@
1
+ # Top Bar Composition - Implementation Guide
2
+
3
+ Canonical owner for top-bar composition: geometry, slots, scroll-state
4
+ contract, spawned surfaces, and verification hooks. Material recipes live in
5
+ `liquid-glass.md`; do not duplicate opacity/blur recipes here. The top-bar
6
+ domain GATE lives in this file (FE-TOPBAR-DOMAIN-01 below); broader brand/
7
+ style judgment beyond that gate lives in `ima2-uiux`.
8
+
9
+ ---
10
+
11
+ ## Domain Gate (FE-TOPBAR-DOMAIN-01, STRICT)
12
+
13
+ Liquid pill top bars are for expressive surfaces: landing, campaign,
14
+ editorial, portfolio, brand, and visual product pages.
15
+
16
+ Dashboards, admin, finance, government, B2B repeated-work tools, auth,
17
+ payment, security, and developer consoles keep standard solid headers by
18
+ default. Their chrome should be predictable, dense, and readable before it is
19
+ expressive.
20
+
21
+ ## Geometry
22
+
23
+ Prefer a floating detached pill bar only when the first viewport can support it.
24
+ The bar must have a capped max-width, top inset, safe-area handling, and a
25
+ single outer capsule radius (`9999px` or >= 24px).
26
+
27
+ | Surface | Geometry | Notes |
28
+ | --- | --- | --- |
29
+ | Landing / campaign / portfolio | Floating detached pill | Legal when the hero has a calm bar zone and enough top breathing room. |
30
+ | Editorial / brand story | Floating pill or quiet full-width | Choose based on reading comfort and hero image complexity. |
31
+ | Consumer app shell | Full-width or compact solid header | Use pill only for promotional/home surfaces, not repeated workflows. |
32
+ | Dashboard / admin / finance / gov / B2B tool | Full-width solid header | Avoid detached liquid chrome; preserve scanning and task speed. |
33
+
34
+ STYLE_SAMPLE:
35
+
36
+ ```css
37
+ .top-bar {
38
+ position: sticky;
39
+ top: max(12px, env(safe-area-inset-top));
40
+ z-index: 40;
41
+ width: min(calc(100% - 32px), 1120px);
42
+ margin-inline: auto;
43
+ border-radius: 9999px;
44
+ }
45
+ ```
46
+
47
+ ## Slots
48
+
49
+ Keep the bar sparse enough that the pill still reads as one piece of chrome:
50
+
51
+ - Logo: use the real brand SVG; see `brand-asset-sourcing.md`.
52
+ - Navigation: 2-5 links. More destinations move into a menu or full navigation
53
+ surface.
54
+ - Controls: only include controls that earn their place in the first viewport
55
+ (for example theme, language, account, or search when essential).
56
+ - CTA: one filled pill CTA is allowed. It must not create a row of competing
57
+ primary actions.
58
+
59
+ Mobile collapses to logo + menu trigger. The menu opens a sheet or drawer with
60
+ a complete tap path; do not rely on hover behavior on touch devices.
61
+
62
+ ## Scroll State (FE-TOPBAR-STATE-01, DEFAULT)
63
+
64
+ Top bars may be scroll-adaptive:
65
+
66
+ - At top: a lighter material state around 70-80% opacity is allowed only over a
67
+ hero authored with a calm bar zone behind the chrome.
68
+ - Scrolled: use the near-opaque 85-95% opacity range and keep blur when the
69
+ selected material state calls for it.
70
+ - Transition: animate `background-color` and `opacity` only. Do not morph size,
71
+ width, radius, or layout on blurred bars.
72
+ - Accessibility supremacy: `FE-LIQUID-A11Y-01` in `liquid-glass.md` overrides
73
+ every state here. Reduced-transparency, increased-contrast, unsupported
74
+ `backdrop-filter`, or failed worst-case contrast collapses all states to
75
+ solid or near-opaque.
76
+
77
+ STYLE_SAMPLE:
78
+
79
+ ```css
80
+ .top-bar {
81
+ transition: background-color 180ms ease, opacity 180ms ease;
82
+ }
83
+ ```
84
+
85
+ ## Hover Surfaces (FE-TOPBAR-HOVER-01, DEFAULT)
86
+
87
+ Any surface spawned from the bar is unconditionally near-opaque, blur-free, and
88
+ solid: dropdown, mega-menu, popover, account menu, language picker, or search
89
+ panel. Content must remain legible over the busiest background that can appear
90
+ behind it.
91
+
92
+ Hover surfaces also need a tap path. Mobile uses the same visual skin where
93
+ appropriate, but the interaction becomes a sheet, drawer, or proven picker
94
+ primitive with correct ARIA and keyboard behavior.
95
+
96
+ ## Child Visuals
97
+
98
+ Nested pill visuals are governed by `FE-PILL-NEST-01` in `liquid-glass.md`.
99
+ Inside pill chrome, child controls render no capsule borders or outlines at
100
+ rest. Solid fills are not restricted by that rule; use hierarchy and accent
101
+ budget to decide how many strong fills the bar can carry.
102
+
103
+ Use fill or tint, not rest-state capsule borders, for `aria-current` and active
104
+ navigation state.
105
+
106
+ ## Accessibility
107
+
108
+ The full bar and every spawned surface must be keyboard reachable:
109
+
110
+ - Tab order enters the logo, links, controls, CTA, and spawned surfaces in a
111
+ predictable path.
112
+ - Escape closes spawned surfaces and returns focus to the trigger.
113
+ - Arrow-key behavior follows the underlying primitive pattern for menu,
114
+ combobox, listbox, or picker.
115
+ - Sticky chrome never hides focused content; apply `scroll-margin-top` or
116
+ equivalent offsets to in-page targets.
117
+ - Skip links remain visible and usable with the sticky bar present.
118
+
119
+ ## Verification Hooks
120
+
121
+ Screenshot or otherwise inspect:
122
+
123
+ - At-top and scrolled states over their real hero/background.
124
+ - A bar-spawned hover surface over the busiest possible background.
125
+ - Reduced-transparency / increased-contrast collapse to solid or near-opaque.
126
+ - Mobile logo + menu trigger and the resulting sheet or drawer tap path.
@@ -0,0 +1,270 @@
1
+ # Typography Wrapping — CSS Text Control
2
+
3
+ Production CSS for text wrapping, line breaks, orphan prevention, and readable line lengths.
4
+ Apply globally in resets or design system base styles.
5
+
6
+ ---
7
+
8
+ ## Global Production Template (2026 Standard)
9
+
10
+ ```css
11
+ /* Headings — balance for visual hierarchy */
12
+ h1, h2, h3, h4, h5, h6,
13
+ blockquote, figcaption, .hero-title {
14
+ text-wrap: balance;
15
+ }
16
+
17
+ /* Short descriptors (1-3 lines) — balance, NOT pretty */
18
+ .hero-desc, .card-desc, .feature-desc,
19
+ .caption, .subtitle, .blurb {
20
+ text-wrap: balance;
21
+ }
22
+
23
+ /* Body text (4+ lines) — pretty for orphan prevention */
24
+ p, li, dt, dd, .prose {
25
+ text-wrap: pretty;
26
+ }
27
+
28
+ /* Editable content — stable for no-reflow typing */
29
+ [contenteditable], .live-text {
30
+ text-wrap: stable;
31
+ }
32
+
33
+ /* Readable line lengths */
34
+ h1 { max-width: 50ch; }
35
+ h2 { max-width: 55ch; }
36
+ h3 { max-width: 60ch; }
37
+ p, li, article, .prose { max-width: 65ch; }
38
+
39
+ /* Korean: wrap by 어절 (word), never mid-word. Scope to ko ONLY —
40
+ global keep-all degrades Chinese/Japanese wrapping (verified 2026-07-07,
41
+ MDN + Naver SmartStudio). */
42
+ [lang|="ko"] {
43
+ word-break: keep-all;
44
+ overflow-wrap: break-word; /* escape hatch for long 어절 in narrow boxes */
45
+ }
46
+
47
+ /* URLs and unbreakable strings */
48
+ a[href], code {
49
+ overflow-wrap: break-word;
50
+ }
51
+
52
+ /* Never-wrap elements */
53
+ .cta-label, .badge, .nav-link, .tag {
54
+ white-space: nowrap;
55
+ }
56
+ ```
57
+
58
+ **Fallback for older browsers:**
59
+ ```css
60
+ @supports not (text-wrap: balance) {
61
+ h1, h2, h3 { max-width: min(90vw, 45ch); }
62
+ }
63
+ ```
64
+
65
+ ---
66
+
67
+ ## `text-wrap: balance`
68
+
69
+ Distributes characters evenly across lines. Prevents long first line + stubby orphan last line.
70
+
71
+ **When to use:** Headings, captions, blockquotes, hero titles, card titles.
72
+ **When NOT to use:** Body paragraphs (performance cost, limited to ~6 lines in Chromium, 10 in Firefox).
73
+
74
+ **Tailwind:** `text-balance`
75
+
76
+ Test with both centered AND left-aligned headings. Combine with `max-width` in `ch` units for best results.
77
+
78
+ ---
79
+
80
+ ## `text-wrap: pretty`
81
+
82
+ Higher-quality algorithm focused on the last few lines. Prevents typographic orphans.
83
+
84
+ **When to use:** Body copy, articles, prose, content-heavy sections.
85
+ **Tailwind:** `text-pretty`
86
+
87
+ ---
88
+
89
+ ## `text-wrap: stable`
90
+
91
+ Prevents reflow of previous lines during editing. Content before the cursor stays fixed.
92
+
93
+ **When to use:** `contenteditable`, note-taking fields, real-time collaborative editing, live chat input.
94
+
95
+ ---
96
+
97
+ ## Short Descriptors — `balance`, not `pretty`
98
+
99
+ Text that is 1-3 lines long (hero subtitle, card description, caption, feature blurb) is NOT a body paragraph. `text-wrap: pretty` has no meaningful effect on 1-3 lines — it targets the tail of long paragraphs.
100
+
101
+ **Use `text-wrap: balance` for all short descriptors.**
102
+
103
+ ```css
104
+ /* Short descriptors — balance for orphan-free wrapping */
105
+ .hero-desc, .card-desc, .feature-desc,
106
+ .caption, .subtitle, .blurb {
107
+ text-wrap: balance;
108
+ }
109
+ ```
110
+
111
+ Add these to the Global Production Template alongside headings.
112
+
113
+ ### `-webkit-line-clamp` disables `text-wrap`
114
+
115
+ When `-webkit-line-clamp` is active, the browser uses a legacy layout mode. `text-wrap: balance` and `pretty` have **zero effect**. If you need truncation with ellipsis, rely on `max-width` to control where breaks land — `text-wrap` cannot help.
116
+
117
+ ---
118
+
119
+ ## `max-width` in `ch` Units
120
+
121
+ | Element | Recommended `max-width` | Rationale |
122
+ |---------|------------------------|-----------|
123
+ | Hero title | 40–45ch | Short, punchy, fits viewport |
124
+ | **Hero subtitle/desc** | **35–40ch** | **Short descriptor — prevent orphans in 1-2 lines** |
125
+ | Section title | 50–55ch | Room for longer phrases |
126
+ | Card title | 30–35ch | Compact containers |
127
+ | **Card description** | **30–35ch** | **Short descriptor — tight containers amplify orphans** |
128
+ | **Caption / label** | **25–30ch** | **Short descriptor** |
129
+ | Body paragraph | 60–65ch | Optimal readability (45–75ch range) |
130
+ | Article/prose | 65ch | Standard reading measure |
131
+
132
+ Combine with fluid typography:
133
+ ```css
134
+ h1 {
135
+ font-size: clamp(2rem, 5vw + 1rem, 4rem);
136
+ max-width: min(90vw, 45ch);
137
+ text-wrap: balance;
138
+ }
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Rag Control
144
+
145
+ | Problem | Solution |
146
+ |---------|----------|
147
+ | Uneven rag (jagged right edge) | `text-wrap: pretty` on paragraphs |
148
+ | Orphaned last word | `text-wrap: pretty` or `text-wrap: balance` for short blocks |
149
+ | Very long lines | `max-width: 65ch` |
150
+ | Rivers in justified text | Avoid `text-align: justify` or add `hyphens: auto` + `lang` attribute |
151
+ | Heading stubs | `text-wrap: balance` + `max-width` in `ch` |
152
+
153
+ ---
154
+
155
+ ## Korean Short Text — `pretty` Does Not Work
156
+
157
+ `text-wrap: pretty` does NOT prevent orphans in Korean text under 3 lines. The algorithm targets the tail of long paragraphs; on short Korean text with `word-break: keep-all`, orphans like "합니다.", "화.", "입니다." pass through unchanged.
158
+
159
+ **Mandatory rule for Korean short text (< 40 characters):** Always use `text-wrap: balance`. If `balance` still produces an orphan, adjust `max-width` by ±2-3ch.
160
+
161
+ ```css
162
+ /* Korean short descriptors — explicit balance override */
163
+ [lang="ko"] .hero-desc,
164
+ [lang="ko"] .card-desc,
165
+ [lang="ko"] .subtitle {
166
+ text-wrap: balance;
167
+ word-break: keep-all;
168
+ }
169
+ ```
170
+
171
+ This is the single most common Korean typography failure in AI-generated pages.
172
+
173
+ ---
174
+
175
+ ## `word-break` vs `overflow-wrap`
176
+
177
+ | Scenario | Use |
178
+ |----------|-----|
179
+ | Long URLs in narrow containers | `overflow-wrap: break-word` |
180
+ | Maximum flexibility with accurate sizing | `overflow-wrap: anywhere` |
181
+ | Aggressive character-level breaking | `word-break: break-all` |
182
+ | Korean 어절 (word) wrapping — `:lang(ko)` scope ONLY, degrades zh/ja globally | `word-break: keep-all` |
183
+ | User-generated content | `overflow-wrap: anywhere` |
184
+
185
+ **`word-break: break-word` is DEPRECATED** — use `overflow-wrap: break-word` instead.
186
+
187
+ ---
188
+
189
+ ## Responsive Heading Breaks
190
+
191
+ Do NOT use manual `<br>` tags for line breaks. They break on different viewports.
192
+
193
+ ```css
194
+ /* If you must use <br> for a specific breakpoint: */
195
+ h1 br { display: none; }
196
+ @media (min-width: 768px) { h1 br { display: block; } }
197
+ ```
198
+
199
+ **Preferred approach:** Let `text-wrap: balance` + `max-width` handle it naturally.
200
+
201
+ ---
202
+
203
+ ## `widows` and `orphans` (Print Only)
204
+
205
+ These CSS properties only work in multi-column layouts and paged media. NOT for standard web layouts.
206
+
207
+ For web, use `text-wrap: pretty` instead.
208
+
209
+ ---
210
+
211
+ ## Production Pattern
212
+
213
+ Common across Vercel, Linear, Stripe: `text-wrap: balance` on headings, `text-wrap: pretty` on body, `font-size: clamp()` for fluid scaling, tighter line-height (1.1–1.2) for headings.
214
+
215
+ For Korean-specific typography considerations, see also `korea-2026.md`.
216
+
217
+ ---
218
+
219
+ ## Natural Phrase Breaks at Any Width (FE-WRAP-NATURAL-01, DEFAULT)
220
+
221
+ Text MUST break at natural phrase boundaries — between thought units, never
222
+ mid-word/mid-phrase — and it must hold at ANY container width, not only
223
+ canonical breakpoints. Containers resize continuously (drag-resize,
224
+ split-screen, foldables, mobile URL-bar dvh changes, container-query
225
+ crossings); a heading that breaks well at 390/768/1024/1440 can still orphan
226
+ at 700px. Control break OPPORTUNITIES (`keep-all`, `max-width` in `ch`,
227
+ `text-wrap: balance`) instead of width-specific hacks (`<br>`, media-query
228
+ text swaps).
229
+
230
+ Korean facts (verified 2026-07-07, Tier-2: MDN, CSSWG Text 4, KLREQ, Chrome
231
+ DevRel, Naver SmartStudio):
232
+
233
+ - With `keep-all`, break opportunities are 어절 (space) boundaries;
234
+ `text-wrap` only CHOOSES among existing opportunities — it cannot create
235
+ Korean phrase boundaries.
236
+ - `word-break: auto-phrase` ships for JAPANESE only (Chrome 119+); do NOT
237
+ rely on it for Korean. Treat it as ja-scoped progressive enhancement.
238
+ - KLREQ line rules are real for Korean (not just Japanese kinsoku): closing
239
+ punctuation must not start a line; opening brackets must not end one;
240
+ number/symbol runs should not split.
241
+ - Advanced editorial tactic: `Intl.Segmenter("ko", {granularity: "word"})`
242
+ (Baseline 2024) + render-time `<wbr>` insertion at approved phrase
243
+ boundaries under `keep-all`. Insert at RENDER time only — ZWSP/joiners
244
+ stored in canonical content break search/copy/diff.
245
+ - Overflow risk: `keep-all` + long 어절 + narrow chips/buttons/table cells =
246
+ clipping; always pair with `overflow-wrap: break-word` (or `anywhere` for
247
+ user-generated/URL content — note it also shrinks min-content size).
248
+
249
+ ### Dynamic-Viewport Verification (checklist)
250
+
251
+ - Sweep CONTAINER widths, not device presets: 160-900px in 8-16px steps for
252
+ headings, cards, buttons, chips, sidebars, resizable panes, table cells.
253
+ - Test dvh/svh URL-bar changes, split-screen halves (640-1024px band, see
254
+ `responsive-viewport.md`), foldable-narrow panes, container-query
255
+ crossings, and 200% zoom / OS text scaling separately.
256
+ - Assert no overflow: `scrollWidth <= clientWidth` on text containers, plus
257
+ screenshots for clipping/overlap at 2-3 arbitrary mid-widths.
258
+ - Korean fixtures: long single 어절, no-space strings, mixed
259
+ Korean/Latin/number copy, URLs, punctuation-heavy lines; flag any
260
+ mid-syllable split where `keep-all` is expected.
261
+ - Fluid type uses `clamp()` with rem/em bounds — never bare `vw`/`cqi` font
262
+ sizes (zoom/user-font-size must keep working).
263
+
264
+ Judgment layer (when a break is "natural", review criteria):
265
+ `dev-uiux-design/references/typography-line-breaks.md § Dynamic Rewrap Judgment`.
266
+
267
+ ## Sources
268
+
269
+ - [MDN: text-wrap](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/text-wrap)
270
+ - [Chrome: CSS text-wrap balance](https://developer.chrome.com/docs/css-ui/css-text-wrap-balance)