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.
- package/README.md +30 -0
- package/bin/commands/skill.js +336 -17
- package/bin/ima2.js +22 -2
- package/bin/lib/doctor-checks.js +6 -4
- package/config.js +1 -0
- package/docs/CLI.md +25 -3
- package/docs/PROMPT_STUDIO.ko.md +29 -0
- package/docs/PROMPT_STUDIO.md +31 -0
- package/docs/migration/runtime-test-inventory.md +7 -1
- package/lib/agentImageVideoGen.js +8 -0
- package/lib/agentQueueStore.js +36 -10
- package/lib/agentQueueWorker.js +79 -7
- package/lib/agentRuntime.js +2 -0
- package/lib/assetLifecycle.js +40 -8
- package/lib/canvasVersionStore.js +86 -0
- package/lib/cardNewsGenerator.js +37 -3
- package/lib/cardNewsJobStore.js +10 -0
- package/lib/cardNewsManifestStore.js +6 -12
- package/lib/cardNewsPath.js +25 -0
- package/lib/db.js +2 -0
- package/lib/generatePipeline.js +474 -0
- package/lib/generationInputValidation.js +32 -0
- package/lib/grokImageCore.js +18 -1
- package/lib/historyIndex.js +11 -4
- package/lib/historyList.js +3 -0
- package/lib/imageMetadata.js +3 -0
- package/lib/inflight.js +30 -3
- package/lib/multimodePipeline.js +462 -0
- package/lib/nodeGeneration.js +440 -0
- package/lib/nodeValidation.js +23 -0
- package/lib/oauthProxy/generators.js +3 -246
- package/lib/oauthProxy/multimodeGenerators.js +251 -0
- package/lib/routeHelpers.js +9 -2
- package/package.json +2 -2
- package/routes/agent.js +4 -4
- package/routes/canvasVersions.js +21 -1
- package/routes/cardNews.js +2 -1
- package/routes/edit.js +25 -9
- package/routes/events.js +5 -1
- package/routes/generate.js +2 -481
- package/routes/keys.js +31 -39
- package/routes/multimode.js +2 -502
- package/routes/nodes.js +3 -448
- package/routes/video.js +12 -3
- package/routes/videoExtended.js +19 -4
- package/server.js +53 -1
- package/skills/ima2/SKILL.md +204 -0
- package/skills/ima2-front/SKILL.md +611 -0
- package/skills/ima2-front/references/a11y-patterns.md +134 -0
- package/skills/ima2-front/references/aesthetics.md +327 -0
- package/skills/ima2-front/references/anti-slop.md +241 -0
- package/skills/ima2-front/references/asset-requirements.md +431 -0
- package/skills/ima2-front/references/brand-asset-sourcing.md +122 -0
- package/skills/ima2-front/references/color-system.md +132 -0
- package/skills/ima2-front/references/consistency-locks.md +20 -0
- package/skills/ima2-front/references/crud-ui.md +53 -0
- package/skills/ima2-front/references/dropdown-layer.md +110 -0
- package/skills/ima2-front/references/i18n-global.md +104 -0
- package/skills/ima2-front/references/iterative-design.md +90 -0
- package/skills/ima2-front/references/korea-2026.md +174 -0
- package/skills/ima2-front/references/layout-discipline.md +161 -0
- package/skills/ima2-front/references/liquid-glass.md +181 -0
- package/skills/ima2-front/references/logo-sections.md +194 -0
- package/skills/ima2-front/references/mobile-ux.md +144 -0
- package/skills/ima2-front/references/performance-budget.md +106 -0
- package/skills/ima2-front/references/preflight-full.md +58 -0
- package/skills/ima2-front/references/product-density.md +53 -0
- package/skills/ima2-front/references/prototype-variants.md +54 -0
- package/skills/ima2-front/references/reference-capture.md +120 -0
- package/skills/ima2-front/references/responsive-viewport.md +139 -0
- package/skills/ima2-front/references/seo-baseline.md +123 -0
- package/skills/ima2-front/references/soft-3d-asset-gates.md +70 -0
- package/skills/ima2-front/references/stacks/astro.md +204 -0
- package/skills/ima2-front/references/stacks/mobile-native.md +281 -0
- package/skills/ima2-front/references/stacks/nextjs.md +219 -0
- package/skills/ima2-front/references/stacks/react.md +264 -0
- package/skills/ima2-front/references/stacks/svelte.md +235 -0
- package/skills/ima2-front/references/stacks/vanilla.md +226 -0
- package/skills/ima2-front/references/theme-switching.md +82 -0
- package/skills/ima2-front/references/top-bar.md +126 -0
- package/skills/ima2-front/references/typography-wrapping.md +270 -0
- package/skills/ima2-front/references/ux-writing-ko.md +62 -0
- package/skills/ima2-front/references/visual-verification.md +102 -0
- package/skills/ima2-uiux/SKILL.md +477 -0
- package/skills/ima2-uiux/references/anti-slop-judgment.md +39 -0
- package/skills/ima2-uiux/references/color-system.md +80 -0
- package/skills/ima2-uiux/references/design-isms.md +194 -0
- package/skills/ima2-uiux/references/design-read-example.md +33 -0
- package/skills/ima2-uiux/references/design-system-bootstrap.md +133 -0
- package/skills/ima2-uiux/references/favicon-logo.md +355 -0
- package/skills/ima2-uiux/references/form-patterns.md +118 -0
- package/skills/ima2-uiux/references/intent-discovery-ladder.md +86 -0
- package/skills/ima2-uiux/references/korean-design-vocabulary.md +52 -0
- package/skills/ima2-uiux/references/layout-macrostructures.md +54 -0
- package/skills/ima2-uiux/references/logo-trust-sections.md +96 -0
- package/skills/ima2-uiux/references/mobile-native-ux.md +207 -0
- package/skills/ima2-uiux/references/product-personalities.md +118 -0
- package/skills/ima2-uiux/references/responsive-nav.md +66 -0
- package/skills/ima2-uiux/references/typography-line-breaks.md +193 -0
- package/skills/ima2-uiux/references/ux-preflight.md +65 -0
- package/skills/ima2-uiux/references/ux-states.md +197 -0
- package/skills/ima2-uiux/references/visual-hierarchy.md +115 -0
- package/ui/dist/.vite/manifest.json +13 -13
- package/ui/dist/assets/AgentWorkspace-CtYt4SF5.js +3 -0
- package/ui/dist/assets/{CardNewsWorkspace-Cdxn1ohU.js → CardNewsWorkspace-DN5cVqG5.js} +1 -1
- package/ui/dist/assets/GenerationRequestLogPanel-DnmUQdKR.js +1 -0
- package/ui/dist/assets/{NodeCanvas-C67sLboA.js → NodeCanvas-CxpfIBI0.js} +1 -1
- package/ui/dist/assets/PromptBuilderPanel-C2R3ObtR.js +2 -0
- package/ui/dist/assets/{PromptImportDialog-DeQXsEEv.js → PromptImportDialog-BIxz_yEx.js} +2 -2
- package/ui/dist/assets/PromptImportDiscoverySection-BQTlPMME.js +1 -0
- package/ui/dist/assets/PromptImportFolderSection-Ds_Th9O3.js +1 -0
- package/ui/dist/assets/{PromptLibraryPanel-Db3xEPM_.js → PromptLibraryPanel-Rs4l45pV.js} +2 -2
- package/ui/dist/assets/{SettingsWorkspace-BDk_1W-V.js → SettingsWorkspace-p1AZ6uT9.js} +1 -1
- package/ui/dist/assets/index-0-_vgFGs.js +4 -0
- package/ui/dist/assets/index-Dm3pFxV4.js +23 -0
- package/ui/dist/assets/index-J8yDF3Ch.css +1 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/AgentWorkspace-DAg_7zpY.js +0 -3
- package/ui/dist/assets/GenerationRequestLogPanel-C_qvEUi2.js +0 -1
- package/ui/dist/assets/PromptBuilderPanel-DjvVdAie.js +0 -2
- package/ui/dist/assets/PromptImportDiscoverySection-CrwyUKYI.js +0 -1
- package/ui/dist/assets/PromptImportFolderSection-CToGMqYE.js +0 -1
- package/ui/dist/assets/index-2oG6in1i.css +0 -1
- package/ui/dist/assets/index-CoxMOXAU.js +0 -23
- package/ui/dist/assets/index-p8egnGHk.js +0 -4
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Brand Asset Sourcing — Logos, Icons & SVGs
|
|
2
|
+
|
|
3
|
+
How to source, use, and handle brand logos in integration/partner sections.
|
|
4
|
+
For anti-slop detection of generic icon substitution, see the Iconography Audit section in `anti-slop.md`.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## The Problem with Generic Icons
|
|
9
|
+
|
|
10
|
+
Using generic stroke icons (Lucide, Heroicons, Feather) as substitutes for brand logos is **always wrong**. A checkmark circle is not Kubernetes. A rectangle is not Docker. A layer stack is not AWS.
|
|
11
|
+
|
|
12
|
+
Brand logos are recognition signals. Generic substitutes look lazy, undermine trust, and signal AI-generated design.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Official Brand SVG Sources (MIT Licensed)
|
|
17
|
+
|
|
18
|
+
| Library | Coverage | Best For | URL |
|
|
19
|
+
|---------|----------|----------|-----|
|
|
20
|
+
| **Simple Icons** | 3,400+ brands | Broadest coverage, monochrome SVG + official hex | simpleicons.org |
|
|
21
|
+
| **SVGL** | 400+ icons | Light/dark variants, public API | svgl.app |
|
|
22
|
+
| **theSVG** | 4,000+ brands | Multi-variant (color, mono, wordmark), MCP integration | thesvg.org |
|
|
23
|
+
|
|
24
|
+
All MIT-licensed. Safe for integration sections.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install simple-icons # All 3400+ SVGs as JS objects
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Production recommendation:** Self-host SVGs rather than CDN for performance and reliability.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Company Press Kits
|
|
35
|
+
|
|
36
|
+
When libraries don't have the brand:
|
|
37
|
+
- Search for "[Company] press kit" or "[Company] brand guidelines"
|
|
38
|
+
- CNCF artwork repo for Kubernetes, Prometheus, etc.
|
|
39
|
+
- AWS icons at aws-icons.com
|
|
40
|
+
- Brandfetch for aggregated brand assets
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Legal: Fair Use for Integration Sections
|
|
45
|
+
|
|
46
|
+
Using brand logos in "integrates with" or "trusted by" sections is generally safe under nominative fair use if:
|
|
47
|
+
|
|
48
|
+
1. **Necessary** — The brand can't be identified without the mark
|
|
49
|
+
2. **Not confusing** — No suggestion of endorsement or affiliation
|
|
50
|
+
3. **Proportional** — Logo is small, in supporting role
|
|
51
|
+
|
|
52
|
+
**Safe:** "We support Kubernetes deployments" with small logo
|
|
53
|
+
**Risky:** "Official Kubernetes Partner" with large featured logo
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## AI Agent Strategy: What To Do When You Can't Access Real Assets
|
|
58
|
+
|
|
59
|
+
### Strategy 1: Use Official Libraries (Preferred)
|
|
60
|
+
|
|
61
|
+
If the brand exists in Simple Icons, SVGL, or theSVG, reference the CDN URL or npm package directly.
|
|
62
|
+
|
|
63
|
+
### Strategy 2: Placeholder with Explicit TODO
|
|
64
|
+
|
|
65
|
+
```html
|
|
66
|
+
<!-- TODO: Replace with official [BrandName] SVG
|
|
67
|
+
Source: [BrandName] press kit or simpleicons.org
|
|
68
|
+
Do NOT ship with this placeholder. -->
|
|
69
|
+
<div class="logo-placeholder" aria-label="BrandName">
|
|
70
|
+
<span>BrandName</span>
|
|
71
|
+
</div>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Strategy 3: Ask the User
|
|
75
|
+
|
|
76
|
+
Report which brands are available in libraries and which need manual sourcing.
|
|
77
|
+
|
|
78
|
+
### What Agents Must NEVER Do
|
|
79
|
+
|
|
80
|
+
- Silently substitute generic stroke icons for brand logos
|
|
81
|
+
- Ship without flagging missing brand assets
|
|
82
|
+
- Use approximate icon shapes ("close enough")
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Fallback Hierarchy
|
|
87
|
+
|
|
88
|
+
| Priority | Approach | When |
|
|
89
|
+
|----------|----------|------|
|
|
90
|
+
| 1 | Official library SVG (Simple Icons, SVGL) | Brand exists in library |
|
|
91
|
+
| 2 | Company press kit SVG | Brand not in library, press kit exists |
|
|
92
|
+
| 3 | Text-only label | No SVG available |
|
|
93
|
+
| 4 | Brand color + text | Visually distinctive without logo |
|
|
94
|
+
| 5 | Placeholder + TODO | Temporary, must be resolved before production |
|
|
95
|
+
|
|
96
|
+
**Text-only is ALWAYS better than a generic icon.** A wrong icon is worse than no icon.
|
|
97
|
+
|
|
98
|
+
Integration logo walls use brand assets, not icon rows. See also `asset-requirements.md`.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Dark Mode Handling
|
|
103
|
+
|
|
104
|
+
```css
|
|
105
|
+
[data-theme="dark"] .logo-item img {
|
|
106
|
+
filter: brightness(0) invert(1);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
For multi-variant support, prefer SVGL or theSVG which ship separate light/dark SVGs.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Captured Reference Material vs Shippable Assets
|
|
115
|
+
|
|
116
|
+
Assets harvested from other sites (HTML, CSS, imagery, fonts) via
|
|
117
|
+
`reference-capture.md` are ANALYSIS-ONLY: they ground structure analysis and
|
|
118
|
+
ima2 mockup references, and they never ship. Webfont binaries are never copied
|
|
119
|
+
(license-restricted by default). Shippable brand assets come only from the
|
|
120
|
+
channels in this file (press kits, Simple Icons/SVGL, licensed libraries), and
|
|
121
|
+
nominative fair use covers shipped integration logos only. Every capture needs
|
|
122
|
+
the provenance manifest defined in `reference-capture.md`.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Color System — Token Implementation Mechanics
|
|
2
|
+
|
|
3
|
+
Implementation owner for color tokens: layering, modern color functions,
|
|
4
|
+
framework wiring, and contrast verification. Palette GENERATION and judgment
|
|
5
|
+
(hue budget, scales, tools) are owned by
|
|
6
|
+
`dev-uiux-design/references/color-system.md` — read it for what colors to
|
|
7
|
+
pick; read this for how to ship them. Runtime theme selection, FOWT
|
|
8
|
+
prevention, and toggle behavior stay in `theme-switching.md`.
|
|
9
|
+
Feature facts below verified 2026-07-07 (MDN/Tailwind/shadcn/W3C, Tier 2).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Token Layering (FE-COLOR-TOKEN-01, DEFAULT)
|
|
14
|
+
|
|
15
|
+
Three layers, referenced downward only:
|
|
16
|
+
|
|
17
|
+
1. **Primitive** — raw scale values, no meaning: `--blue-600`, `--gray-100`.
|
|
18
|
+
2. **Semantic** — meaning, theme-switchable: `--background`, `--primary`,
|
|
19
|
+
`--primary-foreground`, `--border`, `--danger`.
|
|
20
|
+
3. **Component** — scoped knobs derived from semantic: `--button-bg`,
|
|
21
|
+
`--card-border`.
|
|
22
|
+
|
|
23
|
+
Rules: components consume SEMANTIC tokens (or their own component tokens),
|
|
24
|
+
never primitives; hardcoded colors in component CSS are a review finding
|
|
25
|
+
(theme-ready enforcement); dark/alt themes redefine SEMANTIC tokens only.
|
|
26
|
+
|
|
27
|
+
```css
|
|
28
|
+
:root {
|
|
29
|
+
/* primitives */
|
|
30
|
+
--blue-600: oklch(0.58 0.22 260);
|
|
31
|
+
/* semantic */
|
|
32
|
+
--background: oklch(1 0 0);
|
|
33
|
+
--primary: var(--blue-600);
|
|
34
|
+
--primary-foreground: oklch(0.99 0 0);
|
|
35
|
+
}
|
|
36
|
+
.dark {
|
|
37
|
+
--background: oklch(0.145 0 0);
|
|
38
|
+
--primary: oklch(0.70 0.18 260);
|
|
39
|
+
}
|
|
40
|
+
.button-primary {
|
|
41
|
+
--button-bg: var(--primary);
|
|
42
|
+
--button-bg-hover: color-mix(in oklch, var(--primary) 88%, black);
|
|
43
|
+
background: var(--button-bg);
|
|
44
|
+
color: var(--primary-foreground);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Accent Surface Emphasis (FE-COLOR-ACCENT-SURFACE-01, DEFAULT, verified 2026-07-09)
|
|
49
|
+
|
|
50
|
+
Emphasized/highlighted panels on opaque functional UI use a FLAT emphasis
|
|
51
|
+
channel, never a gradient fill (see `anti-slop.md` FE-GRADIENT-02). Pick exactly
|
|
52
|
+
one channel per surface:
|
|
53
|
+
|
|
54
|
+
1. **Flat alpha/step tint** — accent at ~4-8% over the surface, or a dedicated
|
|
55
|
+
low-step token. Radix uses accent steps 3-5 for component backgrounds and
|
|
56
|
+
6-8 for borders; Primer ships `--bgColor-accent-muted: #ddf4ff` with
|
|
57
|
+
`--borderColor-accent-muted: #54aeff66`; shadcn defines flat
|
|
58
|
+
`--accent: oklch(0.97 0 0)` (dark `oklch(0.269 0 0)`) surfaces.
|
|
59
|
+
2. **Border/ring emphasis** — neutral surface, accent moves to the edge:
|
|
60
|
+
selected -> `border-color: var(--accent-border)` (Geist pattern), or
|
|
61
|
+
Tailwind-style `ring-2` + shadow for an emphasized tier.
|
|
62
|
+
3. **Left/top accent bar** — neutral panel body, brand color confined to a
|
|
63
|
+
small stable indicator (`border-left: 3px solid var(--brand)`; Stripe Apps
|
|
64
|
+
pattern).
|
|
65
|
+
4. **Elevation** — shadow tokens (`--shadow-resting-*` / `--shadow-floating-*`,
|
|
66
|
+
Primer pattern) instead of decorative fills.
|
|
67
|
+
5. **Semantic status token** — `background/border/text` role triplets per
|
|
68
|
+
status (information/success/warning/danger; Atlassian pattern) when the
|
|
69
|
+
emphasis carries meaning.
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
/* flat tint + border, derived from semantic tokens — no wash */
|
|
73
|
+
.panel-emphasis {
|
|
74
|
+
background: color-mix(in oklch, var(--primary) 6%, var(--background));
|
|
75
|
+
border: 1px solid color-mix(in oklch, var(--primary) 30%, var(--border));
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Field note (live-measured 2026-07-09): Toss/Kakao/Naver/Channel Talk/Daangn all
|
|
80
|
+
style functional highlighted cards as flat solid/pastel tints with border 0-1px
|
|
81
|
+
and little or no shadow; gradients appear only in hero backgrounds and
|
|
82
|
+
illustration mockups.
|
|
83
|
+
|
|
84
|
+
## Modern Color Functions (baseline status 2026-07-07)
|
|
85
|
+
|
|
86
|
+
- `oklch()` — Baseline 2023. Default authoring space for new palettes:
|
|
87
|
+
perceptually uniform lightness, predictable scale steps.
|
|
88
|
+
- `color-mix(in oklch, ...)` — Baseline 2023. Derive hover/pressed/disabled
|
|
89
|
+
states from semantic tokens instead of hardcoding shade variants.
|
|
90
|
+
- `light-dark(<light>, <dark>)` — Baseline 2024; requires `color-scheme:
|
|
91
|
+
light dark`. Use for BROWSER-controlled two-mode color. For app-controlled
|
|
92
|
+
or multi-theme systems, use `.dark`/`[data-theme]` semantic redefinition
|
|
93
|
+
instead (see `theme-switching.md` for the runtime side).
|
|
94
|
+
- `@supports (color: oklch(0.6 0.2 250))` is the feature gate primitive.
|
|
95
|
+
|
|
96
|
+
## Fallback Discipline (FE-COLOR-FALLBACK-01, DEFAULT)
|
|
97
|
+
|
|
98
|
+
`var(--token, fallback)` does NOT rescue a declaration whose variable holds an
|
|
99
|
+
unsupported color function — the whole declaration is discarded at
|
|
100
|
+
computed-value time. Gate by feature, not by var fallback:
|
|
101
|
+
|
|
102
|
+
```css
|
|
103
|
+
:root { --primary: #2563eb; } /* universal fallback */
|
|
104
|
+
@supports (color: oklch(0.6 0.2 250)) {
|
|
105
|
+
:root { --primary: oklch(0.58 0.22 260); } /* modern override */
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or precompile fallbacks (PostCSS) when the toolchain already does so. Either
|
|
110
|
+
way, the fallback lives at the PRIMITIVE layer so semantic/component layers
|
|
111
|
+
stay function-agnostic.
|
|
112
|
+
|
|
113
|
+
## Framework Wiring
|
|
114
|
+
|
|
115
|
+
- **Tailwind v4** — CSS-first tokens via `@theme` (`--color-*` variables);
|
|
116
|
+
do not reintroduce JS config for colors. Semantic tokens defined in
|
|
117
|
+
`:root`/`.dark` map into utilities via `@theme inline`.
|
|
118
|
+
- **shadcn/ui** — current convention is semantic CSS variables in OKLCH
|
|
119
|
+
mapped through `@theme inline`; follow the project's `components.json`
|
|
120
|
+
tokens; edit themes with tweakcn (see the uiux toolbox) rather than
|
|
121
|
+
hand-tuning hex.
|
|
122
|
+
|
|
123
|
+
## Contrast Verification (FE-COLOR-CONTRAST-01, STRICT)
|
|
124
|
+
|
|
125
|
+
Implementation gate pointing at the §7 accessibility baseline (WCAG AA
|
|
126
|
+
contrast is already STRICT there): every text/background SEMANTIC pair — in
|
|
127
|
+
EVERY theme — is verified against WCAG 2.2 AA (4.5:1 normal, 3:1 large/UI).
|
|
128
|
+
`color-mix()`-derived states count as new pairs; verify them, not just the
|
|
129
|
+
base. APCA/Lc is a useful advisory second check for perceptual readability
|
|
130
|
+
(WCAG 3 is still a Working Draft as of 2026-07-07) — it does not replace the
|
|
131
|
+
WCAG 2.2 gate. Translucent surfaces: worst-case-background rule in
|
|
132
|
+
`liquid-glass.md` FE-LIQUID-A11Y-01 applies.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Consistency Locks (MANDATORY)
|
|
2
|
+
|
|
3
|
+
## Color Consistency Lock
|
|
4
|
+
Once accent color is chosen for a page, it is used on the WHOLE page.
|
|
5
|
+
- Warm-grey site does not get blue CTA in section 7
|
|
6
|
+
- Rose-accented site does not get teal badge in footer
|
|
7
|
+
- Pick one accent, lock it, audit every component
|
|
8
|
+
|
|
9
|
+
## Shape Consistency Lock
|
|
10
|
+
Pick ONE corner-radius scale per page:
|
|
11
|
+
- All-sharp (radius 0)
|
|
12
|
+
- All-soft (radius 12-16px)
|
|
13
|
+
- All-pill (full radius for interactive)
|
|
14
|
+
Mixed systems only with documented rule (e.g., "buttons=pill, cards=16px, inputs=8px")
|
|
15
|
+
|
|
16
|
+
## Page Theme Lock
|
|
17
|
+
ONE theme (light/dark/auto) for the whole page. No section inversions.
|
|
18
|
+
- Section-level background tints within same family OK (zinc-950 next to zinc-900)
|
|
19
|
+
- Flipping to amber-50 in middle of zinc-950 page = broken
|
|
20
|
+
- Exception: one deliberate "color block story" transition per page, if brief demands
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# CRUD UI Basics — Ordinary Screen Slice
|
|
2
|
+
|
|
3
|
+
On-demand reference for C2 list/detail/form screens. These are product surfaces, not
|
|
4
|
+
marketing pages — objective UX states matter; visual styling follows the repo's existing
|
|
5
|
+
system (style presets are STYLE_SAMPLE, never requirements).
|
|
6
|
+
|
|
7
|
+
## State coverage (DEFAULT — the actual quality bar)
|
|
8
|
+
|
|
9
|
+
Every data-driven view handles all of:
|
|
10
|
+
|
|
11
|
+
| State | List view | Form/mutation |
|
|
12
|
+
|-------|-----------|---------------|
|
|
13
|
+
| Loading | Skeleton/spinner consistent with repo pattern | Disabled submit + pending indicator |
|
|
14
|
+
| Empty | Honest empty state with the next action | — |
|
|
15
|
+
| Error | Retryable error with message | Field-level + form-level errors, input preserved |
|
|
16
|
+
| Permission-denied | Hidden or explained, per product convention | Action disabled with reason |
|
|
17
|
+
| Success | Data rendered, stable ordering | Confirmation + navigation/refresh per repo pattern |
|
|
18
|
+
|
|
19
|
+
Missing states are review findings; pixel styling differences are not.
|
|
20
|
+
|
|
21
|
+
## List + detail
|
|
22
|
+
|
|
23
|
+
- Reuse the repo's existing table/list component and data-fetch pattern (query lib, store,
|
|
24
|
+
fetch wrapper) — do not introduce a new data layer for one screen.
|
|
25
|
+
- Pagination/sort/filter UI only when the API provides it and the product needs it.
|
|
26
|
+
- Detail view: deep-linkable when routing exists; 404/permission states handled.
|
|
27
|
+
|
|
28
|
+
## Forms + mutations
|
|
29
|
+
|
|
30
|
+
Form `<select>` and picker controls participate in the project dropdown design
|
|
31
|
+
layer (`dropdown-layer.md` FE-DROPDOWN-LAYER-01): one unified skin over
|
|
32
|
+
behavior-correct primitives, with labels, errors, autofill, and keyboard
|
|
33
|
+
operability fully preserved.
|
|
34
|
+
|
|
35
|
+
- Validation mirrors the API schema; client-side checks are UX sugar, the server stays the
|
|
36
|
+
source of truth.
|
|
37
|
+
- Submit: prevent double-fire, show pending, surface server errors back into the form.
|
|
38
|
+
- Destructive actions (delete) get an explicit confirm step; irreversible-data deletes are
|
|
39
|
+
an ESCALATE product decision, not a UI default.
|
|
40
|
+
- Optimistic updates only where the repo already does them.
|
|
41
|
+
|
|
42
|
+
## Objective UX gates (STRICT/DEFAULT — separate from taste)
|
|
43
|
+
|
|
44
|
+
- Keyboard: form fully operable by keyboard; visible focus states.
|
|
45
|
+
- Labels: every input has an accessible label; errors are announced/associated.
|
|
46
|
+
- Contrast meets the repo's accessibility baseline.
|
|
47
|
+
|
|
48
|
+
## Verification (C2 default)
|
|
49
|
+
|
|
50
|
+
- UI smoke for the changed screen (manual click-through or one Playwright run when UI risk
|
|
51
|
+
is real — risk-tier rule, not a universal blocker).
|
|
52
|
+
- One negative check: a failing submit shows errors without losing input.
|
|
53
|
+
- See `dev-testing/references/core/crud-test-matrix.md`.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Dropdown Design Layer - Implementation Guide
|
|
2
|
+
|
|
3
|
+
Canonical owner for the unified dropdown DESIGN LAYER: visual skin and scope.
|
|
4
|
+
ARIA and keyboard patterns stay in `a11y-patterns.md`; material rules stay in
|
|
5
|
+
`liquid-glass.md`; mobile sheet behavior stays in `mobile-ux.md`; form workflow
|
|
6
|
+
gates stay in `crud-ui.md`.
|
|
7
|
+
---
|
|
8
|
+
## Unified Skin (FE-DROPDOWN-LAYER-01, DEFAULT)
|
|
9
|
+
On projects with a custom design surface, recommend one unified custom dropdown
|
|
10
|
+
design layer over browser-default dropdowns: ONE visual skin across nav menus,
|
|
11
|
+
filter dropdowns, form `<select>`, comboboxes, search suggestions, date pickers,
|
|
12
|
+
and mobile pickers.
|
|
13
|
+
The shared skin contract:
|
|
14
|
+
- Near-opaque solid surface, following the bar-spawned surface rule in
|
|
15
|
+
`liquid-glass.md` `FE-LIQUID-STATE-01`.
|
|
16
|
+
- Blur-free by default; do not inherit top-bar transparency states.
|
|
17
|
+
- Radius tier from the project scale, usually 12-20px for panels.
|
|
18
|
+
- One shadow language for elevation; avoid stacking multiple nested shadows.
|
|
19
|
+
- Typography aligned to the product UI scale, not decorative hero type.
|
|
20
|
+
- Short, calm motion: opacity/translate only, usually 120-180ms.
|
|
21
|
+
- Item hover, active, selected, and focus states use fill/tint, not rest-state
|
|
22
|
+
capsule borders inside the panel.
|
|
23
|
+
|
|
24
|
+
Dropdown panels follow the same fills-not-borders convention as
|
|
25
|
+
`FE-PILL-NEST-01` (whose canonical scope is pill containers with radius
|
|
26
|
+
>= 24px / the 9999px chrome class): child rows and controls render no capsule
|
|
27
|
+
borders or outlines at rest, even though panels themselves sit in the 12-20px
|
|
28
|
+
radius tier. Hover, active, selected, and `aria-current` fills remain legal.
|
|
29
|
+
## Skin Is Not Behavior
|
|
30
|
+
One SKIN does not mean one ARIA pattern.
|
|
31
|
+
Behavior comes from a behavior-correct headless or proven primitive selected
|
|
32
|
+
for the pattern: menu, listbox/select, combobox, date picker, or the repository's
|
|
33
|
+
equivalent. Prefer Radix, React Aria, Base UI, mature design system primitives,
|
|
34
|
+
or the existing local primitive layer.
|
|
35
|
+
|
|
36
|
+
Hand-rolled dropdown behavior is banned for production UI. Do not invent focus
|
|
37
|
+
management, typeahead, roving tabindex, escape handling, or outside-click
|
|
38
|
+
closing from scratch.
|
|
39
|
+
## Design System Precedence
|
|
40
|
+
Design System Detection in `dev-frontend/SKILL.md` Section 12 wins.
|
|
41
|
+
When MUI, Carbon, Fluent, Ant Design, Chakra, Mantine, Polaris, or a comparable
|
|
42
|
+
system governs the project, unify by theming that system's menus, selects,
|
|
43
|
+
popovers, comboboxes, and pickers. Do not rebuild them just to get a custom
|
|
44
|
+
skin unless the project already has an approved headless replacement path.
|
|
45
|
+
## Scope Table
|
|
46
|
+
| Surface | Primitive | Skin notes |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| Nav menu | Menu / navigation menu primitive | Near-opaque spawned panel; tap path required for hover menus; no glass transparency. |
|
|
49
|
+
| Filter dropdown | Menu, listbox, or popover with controls | Same panel shell; preserve checkbox/radio state clarity and dense scanning. |
|
|
50
|
+
| Form select | Select / listbox primitive | Skin trigger and panel while preserving label, error, autofill, name/value, and keyboard behavior. |
|
|
51
|
+
| Combobox / search | Combobox primitive | Same panel shell; suggestions, loading, empty, and selected states share item tokens. |
|
|
52
|
+
| Date picker | Date picker / calendar primitive | Same outer shell; calendar grid may use its own selected-day fill and focus ring. |
|
|
53
|
+
| Mobile picker | Sheet / drawer / native-safe picker primitive | Same skin translated to a bottom sheet; no hover dependency or nested scrolling. |
|
|
54
|
+
## Mobile Contract
|
|
55
|
+
Mobile uses the same dropdown skin as the bottom sheet surface. Hover-spawned
|
|
56
|
+
desktop menus need a tap alternative on touch devices. Use a sheet, drawer,
|
|
57
|
+
popover picker, or proven mobile picker primitive with correct focus, dismissal,
|
|
58
|
+
and scroll locking. Avoid nested scrolling: the sheet owns the scroll area, and
|
|
59
|
+
internal option lists are bounded only when the primitive handles them cleanly.
|
|
60
|
+
See `mobile-ux.md`.
|
|
61
|
+
## Form Semantics
|
|
62
|
+
Skinned form selects still behave like form controls. They keep visible and
|
|
63
|
+
programmatic labels, helper text, validation errors, disabled/read-only states,
|
|
64
|
+
autofill where relevant, keyboard operability, and stable submission semantics.
|
|
65
|
+
The visual layer must not break `crud-ui.md` gates: users can scan a form, see
|
|
66
|
+
required/error states, tab through fields, open a select, choose, recover from
|
|
67
|
+
errors, and submit without pointer-only behavior.
|
|
68
|
+
## CSS Tokens (STYLE_SAMPLE)
|
|
69
|
+
```css
|
|
70
|
+
:root {
|
|
71
|
+
--dropdown-surface: rgb(255 255 255 / 0.96);
|
|
72
|
+
--dropdown-border: rgb(17 24 39 / 0.08);
|
|
73
|
+
--dropdown-radius: 16px;
|
|
74
|
+
--dropdown-shadow: 0 18px 48px rgb(15 23 42 / 0.16);
|
|
75
|
+
--dropdown-hover: rgb(15 23 42 / 0.06);
|
|
76
|
+
--dropdown-active: rgb(15 23 42 / 0.10);
|
|
77
|
+
--dropdown-focus: rgb(37 99 235 / 0.22);
|
|
78
|
+
--dropdown-motion: 140ms ease;
|
|
79
|
+
}
|
|
80
|
+
.dropdown-surface {
|
|
81
|
+
background: var(--dropdown-surface);
|
|
82
|
+
color: rgb(17 24 39);
|
|
83
|
+
border: 1px solid var(--dropdown-border);
|
|
84
|
+
border-radius: var(--dropdown-radius);
|
|
85
|
+
box-shadow: var(--dropdown-shadow);
|
|
86
|
+
font: inherit;
|
|
87
|
+
}
|
|
88
|
+
.dropdown-item {
|
|
89
|
+
border: 0;
|
|
90
|
+
border-radius: 8px;
|
|
91
|
+
background: transparent;
|
|
92
|
+
transition: background-color var(--dropdown-motion), color var(--dropdown-motion);
|
|
93
|
+
}
|
|
94
|
+
.dropdown-item:hover,
|
|
95
|
+
.dropdown-item[data-highlighted] { background: var(--dropdown-hover); }
|
|
96
|
+
.dropdown-item[aria-selected="true"],
|
|
97
|
+
.dropdown-item[data-state="checked"] { background: var(--dropdown-active); }
|
|
98
|
+
.dropdown-item:focus-visible {
|
|
99
|
+
outline: 2px solid var(--dropdown-focus);
|
|
100
|
+
outline-offset: 2px;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
## Verification Hooks
|
|
104
|
+
Check the keyboard path per primitive: tab entry/exit, arrows where expected,
|
|
105
|
+
typeahead or text input behavior, escape close, trigger focus return, and form
|
|
106
|
+
submission for selects.
|
|
107
|
+
Render the dropdown over the busiest background it can cover and verify normal
|
|
108
|
+
contrast, item state contrast, focus visibility, and shadow separation.
|
|
109
|
+
On mobile, verify the sheet or picker tap path, scroll locking, no nested scroll
|
|
110
|
+
trap, safe-area spacing, and reduced-motion behavior.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Internationalization (i18n) Global
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
src/locales/
|
|
7
|
+
ko.json — Korean
|
|
8
|
+
en.json — English
|
|
9
|
+
i18n.ts — config + loader
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
- All user-facing strings in locale files — never hardcode in components
|
|
13
|
+
- ICU message format for pluralization and interpolation
|
|
14
|
+
- Namespace by feature: `{ "auth": { "login": "로그인" } }`
|
|
15
|
+
- Fallback chain: user preference → browser locale → default locale
|
|
16
|
+
- Libraries: `next-intl` (Next.js), `react-intl`, `i18next` (agnostic)
|
|
17
|
+
|
|
18
|
+
## RTL Layout
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<html dir="rtl" lang="ar">
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Use CSS logical properties everywhere:
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
margin-inline-start: 1rem; /* not margin-left */
|
|
28
|
+
padding-inline-end: 0.5rem; /* not padding-right */
|
|
29
|
+
text-align: start; /* not left */
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- Flexbox `row` and Grid auto-reverse in RTL — no changes needed
|
|
33
|
+
- Directional icons (arrows, progress): `transform: scaleX(-1)` in RTL
|
|
34
|
+
- Non-directional icons (search, close): no change
|
|
35
|
+
- Numbers always LTR: `direction: ltr; unicode-bidi: embed`
|
|
36
|
+
- Never use `float: left/right` — use flexbox/grid
|
|
37
|
+
|
|
38
|
+
## Pluralization
|
|
39
|
+
|
|
40
|
+
| Language | Forms | Example |
|
|
41
|
+
|----------|-------|---------|
|
|
42
|
+
| English | one, other | 1 item, 2 items |
|
|
43
|
+
| Korean | other | 1개, 2개 |
|
|
44
|
+
| Arabic | zero, one, two, few, many, other | 6 forms |
|
|
45
|
+
| Russian | one, few, many, other | 4 forms |
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{ "items": "{count, plural, =0 {No items} one {# item} other {# items}}" }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- Never concatenate for pluralization (`count + " items"`)
|
|
52
|
+
- Test with 0, 1, 2, 5, 21 (catches most plural bugs)
|
|
53
|
+
|
|
54
|
+
## Date, Number, Currency
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
new Intl.DateTimeFormat('ko-KR', { dateStyle: 'long' }).format(date)
|
|
58
|
+
// → "2026년 6월 8일"
|
|
59
|
+
|
|
60
|
+
new Intl.NumberFormat('ko-KR', { style: 'currency', currency: 'KRW' }).format(50000)
|
|
61
|
+
// → "₩50,000"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- Always use `Intl.DateTimeFormat` / `Intl.NumberFormat`
|
|
65
|
+
- Currency symbol position varies by locale
|
|
66
|
+
- Decimal separator varies: `.` (en), `,` (de, fr)
|
|
67
|
+
- Relative dates: `Intl.RelativeTimeFormat`
|
|
68
|
+
|
|
69
|
+
## Locale Switching UI
|
|
70
|
+
|
|
71
|
+
- Dropdown in footer or settings
|
|
72
|
+
- Show name in own script: "한국어", "English", "日本語"
|
|
73
|
+
- Never use flags for languages (flags = countries, not languages)
|
|
74
|
+
- Persist: localStorage + URL prefix (`/ko/about`, `/en/about`)
|
|
75
|
+
- URL prefix strategy is best for SEO
|
|
76
|
+
- Never auto-redirect by IP without an override
|
|
77
|
+
|
|
78
|
+
## Content Expansion
|
|
79
|
+
|
|
80
|
+
| Language | vs English | Risk |
|
|
81
|
+
|----------|-----------|------|
|
|
82
|
+
| German | +30% | Button/label overflow |
|
|
83
|
+
| Finnish | +30-40% | Same |
|
|
84
|
+
| Arabic | +20-25% | Plus RTL |
|
|
85
|
+
| Chinese | -30 to -50% | Characters wider |
|
|
86
|
+
|
|
87
|
+
- Design with 40% expansion headroom
|
|
88
|
+
- Test with German pseudo-locale
|
|
89
|
+
- Never fixed `width` on text containers — use `min-width` + flex
|
|
90
|
+
- `text-overflow: ellipsis` + `title` tooltip as last resort
|
|
91
|
+
|
|
92
|
+
## Pre-flight
|
|
93
|
+
|
|
94
|
+
- [ ] All user-facing text in locale files, not hardcoded
|
|
95
|
+
- [ ] CSS uses logical properties (`margin-inline-start`)
|
|
96
|
+
- [ ] Dates/numbers use `Intl` API
|
|
97
|
+
- [ ] Buttons/labels have 40% expansion headroom
|
|
98
|
+
- [ ] Language switcher uses language names, not flags
|
|
99
|
+
|
|
100
|
+
## Cross-references
|
|
101
|
+
|
|
102
|
+
- Korean-specific: `korea-2026.md`
|
|
103
|
+
- Korean UX writing: `ux-writing-ko.md`
|
|
104
|
+
- CJK wrapping: `typography-wrapping.md`
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Iterative Design — LLM Limitations & Multi-Round Process
|
|
2
|
+
|
|
3
|
+
How to overcome the statistical convergence problem inherent in LLM-generated design.
|
|
4
|
+
Adapted from b1rdmania/claude-brand-skills enhanced frontend-design skill.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## The Convergence Problem
|
|
9
|
+
|
|
10
|
+
Every design choice gravitates toward the statistical center of training data — the average of "good design."
|
|
11
|
+
This produces competent, polished work that looks like EVERY other competent, polished work.
|
|
12
|
+
|
|
13
|
+
### Why This Happens
|
|
14
|
+
- **No visual feedback loop** — Writing HTML/CSS as text tokens. No perception of beauty or distinction.
|
|
15
|
+
- **Optimized for coherence** — Training rewards consistency, polish, completeness. Deliberately rule-breaking design fights the model's weights.
|
|
16
|
+
- **Can't feel tension** — Great experimental design creates productive discomfort. The model can't calibrate this.
|
|
17
|
+
- **No taste** — Taste is judgment not reducible to rules. "This feels corporate" or "this needs to breathe" are embodied calls that can only be approximated with heuristics — and heuristics converge to the mean.
|
|
18
|
+
- **Can generate divergence, can't evaluate it** — Can produce 10 structurally different layouts but genuinely cannot tell which one is "surprising AND right."
|
|
19
|
+
|
|
20
|
+
### What This Means
|
|
21
|
+
User direction and references are NOT optional — they ARE the design.
|
|
22
|
+
The model is the hand, not the eye. User taste, references, and gut reactions push output somewhere it would never go alone.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## The Multi-Round Process
|
|
27
|
+
|
|
28
|
+
**CRITICAL**: Never treat this as single-pass (brief → design → done). That guarantees convergence.
|
|
29
|
+
|
|
30
|
+
For runnable implementation mechanics, read `prototype-variants.md`: this file owns
|
|
31
|
+
creative divergence; that file owns `?variant=` routing, switchers, verification, and
|
|
32
|
+
prototype cleanup after a winner is selected.
|
|
33
|
+
|
|
34
|
+
### Round 1: Diverge
|
|
35
|
+
Generate 3-5 **structurally different** variants. Not color/font swaps — fundamentally different:
|
|
36
|
+
- Different spatial logic
|
|
37
|
+
- Different rhythm and composition
|
|
38
|
+
- Different dominant aesthetic
|
|
39
|
+
- Each variant names which design convention it's "fighting"
|
|
40
|
+
|
|
41
|
+
### Round 2: Kill
|
|
42
|
+
User makes **binary decisions**: Alive or Dead.
|
|
43
|
+
**NO blending** — blending is averaging. Averaging is convergence.
|
|
44
|
+
|
|
45
|
+
Precedence: this Alive/Dead process governs POST-CODE iteration rounds. The
|
|
46
|
+
pre-code concept stage is owned by `ima2-uiux` UX-CONCEPT-GEN-01, whose
|
|
47
|
+
mockup SYNTHESIS rule applies there and does not conflict with this ban.
|
|
48
|
+
|
|
49
|
+
### Round 3: Mutate
|
|
50
|
+
Within the surviving direction, introduce deliberate "breaks":
|
|
51
|
+
- Named violations of design convention
|
|
52
|
+
- Specific rules being intentionally broken
|
|
53
|
+
- User picks which breaks work
|
|
54
|
+
|
|
55
|
+
### Round 4+: Repeat
|
|
56
|
+
Each cycle moves further from center.
|
|
57
|
+
User selections are the creative act. The model is the generator.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## User Guidance
|
|
62
|
+
|
|
63
|
+
The user should:
|
|
64
|
+
1. **Provide reference images/sites** — especially from OUTSIDE the same industry. A restaurant menu layout applied to fintech is more distinctive than "experimental fintech."
|
|
65
|
+
2. **Name what they hate** — "I hate card grids" eliminates a convergence attractor better than "make it interesting."
|
|
66
|
+
3. **Expect multiple rounds** — First output is most average. Each "kill this, keep that, push further" cycle moves away from center.
|
|
67
|
+
4. **Kill boldly** — If a variant feels safe or familiar, it IS. Unfamiliarity feels wrong before it feels right.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Upgrade Techniques Library
|
|
72
|
+
|
|
73
|
+
High-impact techniques for replacing generic patterns:
|
|
74
|
+
|
|
75
|
+
### Typography
|
|
76
|
+
- **Variable font animation** — Interpolate weight/width on scroll or hover
|
|
77
|
+
- **Outlined-to-fill transitions** — Text starts as stroke, fills with color on entry
|
|
78
|
+
- **Text mask reveals** — Large type as a window to video/animation behind it
|
|
79
|
+
|
|
80
|
+
### Layout
|
|
81
|
+
- **Broken grid / asymmetry** — Overlapping, bleeding off-screen, offset with calculated randomness
|
|
82
|
+
- **Whitespace maximization** — Aggressive negative space forcing focus on single element
|
|
83
|
+
- **Parallax card stacks** — Sections stick and physically stack during scroll
|
|
84
|
+
- **Split-screen scroll** — Two halves sliding in opposite directions
|
|
85
|
+
|
|
86
|
+
### Surfaces
|
|
87
|
+
- **True glassmorphism** — see `liquid-glass.md` (recipes + gates); the tell of fake glass is `backdrop-blur` with no edge refraction
|
|
88
|
+
- **Spotlight borders** — Card borders illuminating dynamically under cursor
|
|
89
|
+
- **Grain/noise overlays** — Fixed `pointer-events-none` overlay breaking digital flatness
|
|
90
|
+
- **Colored tinted shadows** — Shadows carrying background hue, not generic black
|