hazardtln commited on
Commit
61b5cbf
Β·
0 Parent(s):

Fresh start: optimized code for Vercel/HF with PWA and Speed Fixes

Browse files
This view is limited to 50 files because it contains too many changes. Β  See raw diff
Files changed (50) hide show
  1. .agent/skills/frontend-design/LICENSE.txt +177 -0
  2. .agent/skills/frontend-design/SKILL.md +277 -0
  3. .agent/skills/ui-ux-pro-max/SKILL.md +659 -0
  4. .agent/skills/ui-ux-pro-max/data +1 -0
  5. .agent/skills/ui-ux-pro-max/scripts +1 -0
  6. .agents/skills/frontend-design/LICENSE.txt +177 -0
  7. .agents/skills/frontend-design/SKILL.md +277 -0
  8. .agents/skills/ui-ux-pro-max/SKILL.md +659 -0
  9. .agents/skills/ui-ux-pro-max/data +1 -0
  10. .agents/skills/ui-ux-pro-max/scripts +1 -0
  11. .dockerignore +16 -0
  12. .gitignore +21 -0
  13. App/backend/check.py +19 -0
  14. App/backend/download_model.py +50 -0
  15. App/backend/main.py +110 -0
  16. App/backend/requirements.txt +25 -0
  17. App/backend/startup_err.txt +0 -0
  18. App/backend/test_piper.py +14 -0
  19. App/frontend/.agent/skills/ui-ux-pro-max/SKILL.md +659 -0
  20. App/frontend/.agent/skills/ui-ux-pro-max/data +1 -0
  21. App/frontend/.agent/skills/ui-ux-pro-max/scripts +1 -0
  22. App/frontend/.agents/skills/ui-ux-pro-max/SKILL.md +659 -0
  23. App/frontend/.agents/skills/ui-ux-pro-max/data +1 -0
  24. App/frontend/.agents/skills/ui-ux-pro-max/scripts +1 -0
  25. App/frontend/.gitignore +24 -0
  26. App/frontend/README.md +16 -0
  27. App/frontend/eslint.config.js +29 -0
  28. App/frontend/index.html +25 -0
  29. App/frontend/package-lock.json +0 -0
  30. App/frontend/package.json +31 -0
  31. App/frontend/public/eReaderLogo.png +0 -0
  32. App/frontend/public/logo.png +0 -0
  33. App/frontend/public/pwa-192x192.png +0 -0
  34. App/frontend/public/pwa-192x192.svg +1 -0
  35. App/frontend/public/pwa-512x512.png +0 -0
  36. App/frontend/public/pwa-512x512.svg +1 -0
  37. App/frontend/public/vite.svg +1 -0
  38. App/frontend/skills-lock.json +10 -0
  39. App/frontend/src/App.css +42 -0
  40. App/frontend/src/App.jsx +755 -0
  41. App/frontend/src/assets/react.svg +1 -0
  42. App/frontend/src/components/AudioDock.jsx +56 -0
  43. App/frontend/src/components/BookmarksPopover.jsx +31 -0
  44. App/frontend/src/components/EReaderLogo.jsx +34 -0
  45. App/frontend/src/components/ReaderParagraph.jsx +31 -0
  46. App/frontend/src/components/SettingsPanel.jsx +150 -0
  47. App/frontend/src/components/Sidebar.jsx +80 -0
  48. App/frontend/src/components/TOCPopover.jsx +35 -0
  49. App/frontend/src/index.css +1845 -0
  50. App/frontend/src/main.jsx +10 -0
.agent/skills/frontend-design/LICENSE.txt ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
.agent/skills/frontend-design/SKILL.md ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: frontend-design
3
+ description: "Create distinctive, production-grade frontend interfaces with intentional aesthetics, high craft, and non-generic visual identity. Use when building or styling web UIs, components, pages, dashboard..."
4
+ risk: unknown
5
+ source: community
6
+ date_added: "2026-02-27"
7
+ ---
8
+
9
+ # Frontend Design (Distinctive, Production-Grade)
10
+
11
+ You are a **frontend designer-engineer**, not a layout generator.
12
+
13
+ Your goal is to create **memorable, high-craft interfaces** that:
14
+
15
+ * Avoid generic β€œAI UI” patterns
16
+ * Express a clear aesthetic point of view
17
+ * Are fully functional and production-ready
18
+ * Translate design intent directly into code
19
+
20
+ This skill prioritizes **intentional design systems**, not default frameworks.
21
+
22
+ ---
23
+
24
+ ## 1. Core Design Mandate
25
+
26
+ Every output must satisfy **all four**:
27
+
28
+ 1. **Intentional Aesthetic Direction**
29
+ A named, explicit design stance (e.g. *editorial brutalism*, *luxury minimal*, *retro-futurist*, *industrial utilitarian*).
30
+
31
+ 2. **Technical Correctness**
32
+ Real, working HTML/CSS/JS or framework code β€” not mockups.
33
+
34
+ 3. **Visual Memorability**
35
+ At least one element the user will remember 24 hours later.
36
+
37
+ 4. **Cohesive Restraint**
38
+ No random decoration. Every flourish must serve the aesthetic thesis.
39
+
40
+ ❌ No default layouts
41
+ ❌ No design-by-components
42
+ ❌ No β€œsafe” palettes or fonts
43
+ βœ… Strong opinions, well executed
44
+
45
+ ---
46
+
47
+ ## 2. Design Feasibility & Impact Index (DFII)
48
+
49
+ Before building, evaluate the design direction using DFII.
50
+
51
+ ### DFII Dimensions (1–5)
52
+
53
+ | Dimension | Question |
54
+ | ------------------------------ | ------------------------------------------------------------ |
55
+ | **Aesthetic Impact** | How visually distinctive and memorable is this direction? |
56
+ | **Context Fit** | Does this aesthetic suit the product, audience, and purpose? |
57
+ | **Implementation Feasibility** | Can this be built cleanly with available tech? |
58
+ | **Performance Safety** | Will it remain fast and accessible? |
59
+ | **Consistency Risk** | Can this be maintained across screens/components? |
60
+
61
+ ### Scoring Formula
62
+
63
+ ```
64
+ DFII = (Impact + Fit + Feasibility + Performance) βˆ’ Consistency Risk
65
+ ```
66
+
67
+ **Range:** `-5 β†’ +15`
68
+
69
+ ### Interpretation
70
+
71
+ | DFII | Meaning | Action |
72
+ | --------- | --------- | --------------------------- |
73
+ | **12–15** | Excellent | Execute fully |
74
+ | **8–11** | Strong | Proceed with discipline |
75
+ | **4–7** | Risky | Reduce scope or effects |
76
+ | **≀ 3** | Weak | Rethink aesthetic direction |
77
+
78
+ ---
79
+
80
+ ## 3. Mandatory Design Thinking Phase
81
+
82
+ Before writing code, explicitly define:
83
+
84
+ ### 1. Purpose
85
+
86
+ * What action should this interface enable?
87
+ * Is it persuasive, functional, exploratory, or expressive?
88
+
89
+ ### 2. Tone (Choose One Dominant Direction)
90
+
91
+ Examples (non-exhaustive):
92
+
93
+ * Brutalist / Raw
94
+ * Editorial / Magazine
95
+ * Luxury / Refined
96
+ * Retro-futuristic
97
+ * Industrial / Utilitarian
98
+ * Organic / Natural
99
+ * Playful / Toy-like
100
+ * Maximalist / Chaotic
101
+ * Minimalist / Severe
102
+
103
+ ⚠️ Do not blend more than **two**.
104
+
105
+ ### 3. Differentiation Anchor
106
+
107
+ Answer:
108
+
109
+ > β€œIf this were screenshotted with the logo removed, how would someone recognize it?”
110
+
111
+ This anchor must be visible in the final UI.
112
+
113
+ ---
114
+
115
+ ## 4. Aesthetic Execution Rules (Non-Negotiable)
116
+
117
+ ### Typography
118
+
119
+ * Avoid system fonts and AI-defaults (Inter, Roboto, Arial, etc.)
120
+ * Choose:
121
+
122
+ * 1 expressive display font
123
+ * 1 restrained body font
124
+ * Use typography structurally (scale, rhythm, contrast)
125
+
126
+ ### Color & Theme
127
+
128
+ * Commit to a **dominant color story**
129
+ * Use CSS variables exclusively
130
+ * Prefer:
131
+
132
+ * One dominant tone
133
+ * One accent
134
+ * One neutral system
135
+ * Avoid evenly-balanced palettes
136
+
137
+ ### Spatial Composition
138
+
139
+ * Break the grid intentionally
140
+ * Use:
141
+
142
+ * Asymmetry
143
+ * Overlap
144
+ * Negative space OR controlled density
145
+ * White space is a design element, not absence
146
+
147
+ ### Motion
148
+
149
+ * Motion must be:
150
+
151
+ * Purposeful
152
+ * Sparse
153
+ * High-impact
154
+ * Prefer:
155
+
156
+ * One strong entrance sequence
157
+ * A few meaningful hover states
158
+ * Avoid decorative micro-motion spam
159
+
160
+ ### Texture & Depth
161
+
162
+ Use when appropriate:
163
+
164
+ * Noise / grain overlays
165
+ * Gradient meshes
166
+ * Layered translucency
167
+ * Custom borders or dividers
168
+ * Shadows with narrative intent (not defaults)
169
+
170
+ ---
171
+
172
+ ## 5. Implementation Standards
173
+
174
+ ### Code Requirements
175
+
176
+ * Clean, readable, and modular
177
+ * No dead styles
178
+ * No unused animations
179
+ * Semantic HTML
180
+ * Accessible by default (contrast, focus, keyboard)
181
+
182
+ ### Framework Guidance
183
+
184
+ * **HTML/CSS**: Prefer native features, modern CSS
185
+ * **React**: Functional components, composable styles
186
+ * **Animation**:
187
+
188
+ * CSS-first
189
+ * Framer Motion only when justified
190
+
191
+ ### Complexity Matching
192
+
193
+ * Maximalist design β†’ complex code (animations, layers)
194
+ * Minimalist design β†’ extremely precise spacing & type
195
+
196
+ Mismatch = failure.
197
+
198
+ ---
199
+
200
+ ## 6. Required Output Structure
201
+
202
+ When generating frontend work:
203
+
204
+ ### 1. Design Direction Summary
205
+
206
+ * Aesthetic name
207
+ * DFII score
208
+ * Key inspiration (conceptual, not visual plagiarism)
209
+
210
+ ### 2. Design System Snapshot
211
+
212
+ * Fonts (with rationale)
213
+ * Color variables
214
+ * Spacing rhythm
215
+ * Motion philosophy
216
+
217
+ ### 3. Implementation
218
+
219
+ * Full working code
220
+ * Comments only where intent isn’t obvious
221
+
222
+ ### 4. Differentiation Callout
223
+
224
+ Explicitly state:
225
+
226
+ > β€œThis avoids generic UI by doing X instead of Y.”
227
+
228
+ ---
229
+
230
+ ## 7. Anti-Patterns (Immediate Failure)
231
+
232
+ ❌ Inter/Roboto/system fonts
233
+ ❌ Purple-on-white SaaS gradients
234
+ ❌ Default Tailwind/ShadCN layouts
235
+ ❌ Symmetrical, predictable sections
236
+ ❌ Overused AI design tropes
237
+ ❌ Decoration without intent
238
+
239
+ If the design could be mistaken for a template β†’ restart.
240
+
241
+ ---
242
+
243
+ ## 8. Integration With Other Skills
244
+
245
+ * **page-cro** β†’ Layout hierarchy & conversion flow
246
+ * **copywriting** β†’ Typography & message rhythm
247
+ * **marketing-psychology** β†’ Visual persuasion & bias alignment
248
+ * **branding** β†’ Visual identity consistency
249
+ * **ab-test-setup** β†’ Variant-safe design systems
250
+
251
+ ---
252
+
253
+ ## 9. Operator Checklist
254
+
255
+ Before finalizing output:
256
+
257
+ * [ ] Clear aesthetic direction stated
258
+ * [ ] DFII β‰₯ 8
259
+ * [ ] One memorable design anchor
260
+ * [ ] No generic fonts/colors/layouts
261
+ * [ ] Code matches design ambition
262
+ * [ ] Accessible and performant
263
+
264
+ ---
265
+
266
+ ## 10. Questions to Ask (If Needed)
267
+
268
+ 1. Who is this for, emotionally?
269
+ 2. Should this feel trustworthy, exciting, calm, or provocative?
270
+ 3. Is memorability or clarity more important?
271
+ 4. Will this scale to other pages/components?
272
+ 5. What should users *feel* in the first 3 seconds?
273
+
274
+ ---
275
+
276
+ ## When to Use
277
+ This skill is applicable to execute the workflow or actions described in the overview.
.agent/skills/ui-ux-pro-max/SKILL.md ADDED
@@ -0,0 +1,659 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: ui-ux-pro-max
3
+ description: "UI/UX design intelligence for web and mobile. Includes 50+ styles, 161 color palettes, 57 font pairings, 161 product types, 99 UX guidelines, and 25 chart types across 10 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn/ui, and HTML/CSS). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, and check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, and mobile app. Elements: button, modal, navbar, sidebar, card, table, form, and chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, and flat design. Topics: color systems, accessibility, animation, layout, typography, font pairing, spacing, interaction states, shadow, and gradient. Integrations: shadcn/ui MCP for component search and examples."
4
+ ---
5
+
6
+ # UI/UX Pro Max - Design Intelligence
7
+
8
+ Comprehensive design guide for web and mobile applications. Contains 50+ styles, 161 color palettes, 57 font pairings, 161 product types with reasoning rules, 99 UX guidelines, and 25 chart types across 10 technology stacks. Searchable database with priority-based recommendations.
9
+
10
+ ## When to Apply
11
+
12
+ This Skill should be used when the task involves **UI structure, visual design decisions, interaction patterns, or user experience quality control**.
13
+
14
+ ### Must Use
15
+
16
+ This Skill must be invoked in the following situations:
17
+
18
+ - Designing new pages (Landing Page, Dashboard, Admin, SaaS, Mobile App)
19
+ - Creating or refactoring UI components (buttons, modals, forms, tables, charts, etc.)
20
+ - Choosing color schemes, typography systems, spacing standards, or layout systems
21
+ - Reviewing UI code for user experience, accessibility, or visual consistency
22
+ - Implementing navigation structures, animations, or responsive behavior
23
+ - Making product-level design decisions (style, information hierarchy, brand expression)
24
+ - Improving perceived quality, clarity, or usability of interfaces
25
+
26
+ ### Recommended
27
+
28
+ This Skill is recommended in the following situations:
29
+
30
+ - UI looks "not professional enough" but the reason is unclear
31
+ - Receiving feedback on usability or experience
32
+ - Pre-launch UI quality optimization
33
+ - Aligning cross-platform design (Web / iOS / Android)
34
+ - Building design systems or reusable component libraries
35
+
36
+ ### Skip
37
+
38
+ This Skill is not needed in the following situations:
39
+
40
+ - Pure backend logic development
41
+ - Only involving API or database design
42
+ - Performance optimization unrelated to the interface
43
+ - Infrastructure or DevOps work
44
+ - Non-visual scripts or automation tasks
45
+
46
+ **Decision criteria**: If the task will change how a feature **looks, feels, moves, or is interacted with**, this Skill should be used.
47
+
48
+ ## Rule Categories by Priority
49
+
50
+ *For human/AI reference: follow priority 1β†’10 to decide which rule category to focus on first; use `--domain <Domain>` to query details when needed. Scripts do not read this table.*
51
+
52
+ | Priority | Category | Impact | Domain | Key Checks (Must Have) | Anti-Patterns (Avoid) |
53
+ |----------|----------|--------|--------|------------------------|------------------------|
54
+ | 1 | Accessibility | CRITICAL | `ux` | Contrast 4.5:1, Alt text, Keyboard nav, Aria-labels | Removing focus rings, Icon-only buttons without labels |
55
+ | 2 | Touch & Interaction | CRITICAL | `ux` | Min size 44Γ—44px, 8px+ spacing, Loading feedback | Reliance on hover only, Instant state changes (0ms) |
56
+ | 3 | Performance | HIGH | `ux` | WebP/AVIF, Lazy loading, Reserve space (CLS &lt; 0.1) | Layout thrashing, Cumulative Layout Shift |
57
+ | 4 | Style Selection | HIGH | `style`, `product` | Match product type, Consistency, SVG icons (no emoji) | Mixing flat & skeuomorphic randomly, Emoji as icons |
58
+ | 5 | Layout & Responsive | HIGH | `ux` | Mobile-first breakpoints, Viewport meta, No horizontal scroll | Horizontal scroll, Fixed px container widths, Disable zoom |
59
+ | 6 | Typography & Color | MEDIUM | `typography`, `color` | Base 16px, Line-height 1.5, Semantic color tokens | Text &lt; 12px body, Gray-on-gray, Raw hex in components |
60
+ | 7 | Animation | MEDIUM | `ux` | Duration 150–300ms, Motion conveys meaning, Spatial continuity | Decorative-only animation, Animating width/height, No reduced-motion |
61
+ | 8 | Forms & Feedback | MEDIUM | `ux` | Visible labels, Error near field, Helper text, Progressive disclosure | Placeholder-only label, Errors only at top, Overwhelm upfront |
62
+ | 9 | Navigation Patterns | HIGH | `ux` | Predictable back, Bottom nav ≀5, Deep linking | Overloaded nav, Broken back behavior, No deep links |
63
+ | 10 | Charts & Data | LOW | `chart` | Legends, Tooltips, Accessible colors | Relying on color alone to convey meaning |
64
+
65
+ ## Quick Reference
66
+
67
+ ### 1. Accessibility (CRITICAL)
68
+
69
+ - `color-contrast` - Minimum 4.5:1 ratio for normal text (large text 3:1); Material Design
70
+ - `focus-states` - Visible focus rings on interactive elements (2–4px; Apple HIG, MD)
71
+ - `alt-text` - Descriptive alt text for meaningful images
72
+ - `aria-labels` - aria-label for icon-only buttons; accessibilityLabel in native (Apple HIG)
73
+ - `keyboard-nav` - Tab order matches visual order; full keyboard support (Apple HIG)
74
+ - `form-labels` - Use label with for attribute
75
+ - `skip-links` - Skip to main content for keyboard users
76
+ - `heading-hierarchy` - Sequential h1β†’h6, no level skip
77
+ - `color-not-only` - Don't convey info by color alone (add icon/text)
78
+ - `dynamic-type` - Support system text scaling; avoid truncation as text grows (Apple Dynamic Type, MD)
79
+ - `reduced-motion` - Respect prefers-reduced-motion; reduce/disable animations when requested (Apple Reduced Motion API, MD)
80
+ - `voiceover-sr` - Meaningful accessibilityLabel/accessibilityHint; logical reading order for VoiceOver/screen readers (Apple HIG, MD)
81
+ - `escape-routes` - Provide cancel/back in modals and multi-step flows (Apple HIG)
82
+ - `keyboard-shortcuts` - Preserve system and a11y shortcuts; offer keyboard alternatives for drag-and-drop (Apple HIG)
83
+
84
+ ### 2. Touch & Interaction (CRITICAL)
85
+
86
+ - `touch-target-size` - Min 44Γ—44pt (Apple) / 48Γ—48dp (Material); extend hit area beyond visual bounds if needed
87
+ - `touch-spacing` - Minimum 8px/8dp gap between touch targets (Apple HIG, MD)
88
+ - `hover-vs-tap` - Use click/tap for primary interactions; don't rely on hover alone
89
+ - `loading-buttons` - Disable button during async operations; show spinner or progress
90
+ - `error-feedback` - Clear error messages near problem
91
+ - `cursor-pointer` - Add cursor-pointer to clickable elements (Web)
92
+ - `gesture-conflicts` - Avoid horizontal swipe on main content; prefer vertical scroll
93
+ - `tap-delay` - Use touch-action: manipulation to reduce 300ms delay (Web)
94
+ - `standard-gestures` - Use platform standard gestures consistently; don't redefine (e.g. swipe-back, pinch-zoom) (Apple HIG)
95
+ - `system-gestures` - Don't block system gestures (Control Center, back swipe, etc.) (Apple HIG)
96
+ - `press-feedback` - Visual feedback on press (ripple/highlight; MD state layers)
97
+ - `haptic-feedback` - Use haptic for confirmations and important actions; avoid overuse (Apple HIG)
98
+ - `gesture-alternative` - Don't rely on gesture-only interactions; always provide visible controls for critical actions
99
+ - `safe-area-awareness` - Keep primary touch targets away from notch, Dynamic Island, gesture bar and screen edges
100
+ - `no-precision-required` - Avoid requiring pixel-perfect taps on small icons or thin edges
101
+ - `swipe-clarity` - Swipe actions must show clear affordance or hint (chevron, label, tutorial)
102
+ - `drag-threshold` - Use a movement threshold before starting drag to avoid accidental drags
103
+
104
+ ### 3. Performance (HIGH)
105
+
106
+ - `image-optimization` - Use WebP/AVIF, responsive images (srcset/sizes), lazy load non-critical assets
107
+ - `image-dimension` - Declare width/height or use aspect-ratio to prevent layout shift (Core Web Vitals: CLS)
108
+ - `font-loading` - Use font-display: swap/optional to avoid invisible text (FOIT); reserve space to reduce layout shift (MD)
109
+ - `font-preload` - Preload only critical fonts; avoid overusing preload on every variant
110
+ - `critical-css` - Prioritize above-the-fold CSS (inline critical CSS or early-loaded stylesheet)
111
+ - `lazy-loading` - Lazy load non-hero components via dynamic import / route-level splitting
112
+ - `bundle-splitting` - Split code by route/feature (React Suspense / Next.js dynamic) to reduce initial load and TTI
113
+ - `third-party-scripts` - Load third-party scripts async/defer; audit and remove unnecessary ones (MD)
114
+ - `reduce-reflows` - Avoid frequent layout reads/writes; batch DOM reads then writes
115
+ - `content-jumping` - Reserve space for async content to avoid layout jumps (Core Web Vitals: CLS)
116
+ - `lazy-load-below-fold` - Use loading="lazy" for below-the-fold images and heavy media
117
+ - `virtualize-lists` - Virtualize lists with 50+ items to improve memory efficiency and scroll performance
118
+ - `main-thread-budget` - Keep per-frame work under ~16ms for 60fps; move heavy tasks off main thread (HIG, MD)
119
+ - `progressive-loading` - Use skeleton screens / shimmer instead of long blocking spinners for >1s operations (Apple HIG)
120
+ - `input-latency` - Keep input latency under ~100ms for taps/scrolls (Material responsiveness standard)
121
+ - `tap-feedback-speed` - Provide visual feedback within 100ms of tap (Apple HIG)
122
+ - `debounce-throttle` - Use debounce/throttle for high-frequency events (scroll, resize, input)
123
+ - `offline-support` - Provide offline state messaging and basic fallback (PWA / mobile)
124
+ - `network-fallback` - Offer degraded modes for slow networks (lower-res images, fewer animations)
125
+
126
+ ### 4. Style Selection (HIGH)
127
+
128
+ - `style-match` - Match style to product type (use `--design-system` for recommendations)
129
+ - `consistency` - Use same style across all pages
130
+ - `no-emoji-icons` - Use SVG icons (Heroicons, Lucide), not emojis
131
+ - `color-palette-from-product` - Choose palette from product/industry (search `--domain color`)
132
+ - `effects-match-style` - Shadows, blur, radius aligned with chosen style (glass / flat / clay etc.)
133
+ - `platform-adaptive` - Respect platform idioms (iOS HIG vs Material): navigation, controls, typography, motion
134
+ - `state-clarity` - Make hover/pressed/disabled states visually distinct while staying on-style (Material state layers)
135
+ - `elevation-consistent` - Use a consistent elevation/shadow scale for cards, sheets, modals; avoid random shadow values
136
+ - `dark-mode-pairing` - Design light/dark variants together to keep brand, contrast, and style consistent
137
+ - `icon-style-consistent` - Use one icon set/visual language (stroke width, corner radius) across the product
138
+ - `system-controls` - Prefer native/system controls over fully custom ones; only customize when branding requires it (Apple HIG)
139
+ - `blur-purpose` - Use blur to indicate background dismissal (modals, sheets), not as decoration (Apple HIG)
140
+ - `primary-action` - Each screen should have only one primary CTA; secondary actions visually subordinate (Apple HIG)
141
+
142
+ ### 5. Layout & Responsive (HIGH)
143
+
144
+ - `viewport-meta` - width=device-width initial-scale=1 (never disable zoom)
145
+ - `mobile-first` - Design mobile-first, then scale up to tablet and desktop
146
+ - `breakpoint-consistency` - Use systematic breakpoints (e.g. 375 / 768 / 1024 / 1440)
147
+ - `readable-font-size` - Minimum 16px body text on mobile (avoids iOS auto-zoom)
148
+ - `line-length-control` - Mobile 35–60 chars per line; desktop 60–75 chars
149
+ - `horizontal-scroll` - No horizontal scroll on mobile; ensure content fits viewport width
150
+ - `spacing-scale` - Use 4pt/8dp incremental spacing system (Material Design)
151
+ - `touch-density` - Keep component spacing comfortable for touch: not cramped, not causing mis-taps
152
+ - `container-width` - Consistent max-width on desktop (max-w-6xl / 7xl)
153
+ - `z-index-management` - Define layered z-index scale (e.g. 0 / 10 / 20 / 40 / 100 / 1000)
154
+ - `fixed-element-offset` - Fixed navbar/bottom bar must reserve safe padding for underlying content
155
+ - `scroll-behavior` - Avoid nested scroll regions that interfere with the main scroll experience
156
+ - `viewport-units` - Prefer min-h-dvh over 100vh on mobile
157
+ - `orientation-support` - Keep layout readable and operable in landscape mode
158
+ - `content-priority` - Show core content first on mobile; fold or hide secondary content
159
+ - `visual-hierarchy` - Establish hierarchy via size, spacing, contrast β€” not color alone
160
+
161
+ ### 6. Typography & Color (MEDIUM)
162
+
163
+ - `line-height` - Use 1.5-1.75 for body text
164
+ - `line-length` - Limit to 65-75 characters per line
165
+ - `font-pairing` - Match heading/body font personalities
166
+ - `font-scale` - Consistent type scale (e.g. 12 14 16 18 24 32)
167
+ - `contrast-readability` - Darker text on light backgrounds (e.g. slate-900 on white)
168
+ - `text-styles-system` - Use platform type system: iOS 11 Dynamic Type styles / Material 5 type roles (display, headline, title, body, label) (HIG, MD)
169
+ - `weight-hierarchy` - Use font-weight to reinforce hierarchy: Bold headings (600–700), Regular body (400), Medium labels (500) (MD)
170
+ - `color-semantic` - Define semantic color tokens (primary, secondary, error, surface, on-surface) not raw hex in components (Material color system)
171
+ - `color-dark-mode` - Dark mode uses desaturated / lighter tonal variants, not inverted colors; test contrast separately (HIG, MD)
172
+ - `color-accessible-pairs` - Foreground/background pairs must meet 4.5:1 (AA) or 7:1 (AAA); use tools to verify (WCAG, MD)
173
+ - `color-not-decorative-only` - Functional color (error red, success green) must include icon/text; avoid color-only meaning (HIG, MD)
174
+ - `truncation-strategy` - Prefer wrapping over truncation; when truncating use ellipsis and provide full text via tooltip/expand (Apple HIG)
175
+ - `letter-spacing` - Respect default letter-spacing per platform; avoid tight tracking on body text (HIG, MD)
176
+ - `number-tabular` - Use tabular/monospaced figures for data columns, prices, and timers to prevent layout shift
177
+ - `whitespace-balance` - Use whitespace intentionally to group related items and separate sections; avoid visual clutter (Apple HIG)
178
+
179
+ ### 7. Animation (MEDIUM)
180
+
181
+ - `duration-timing` - Use 150–300ms for micro-interactions; complex transitions ≀400ms; avoid >500ms (MD)
182
+ - `transform-performance` - Use transform/opacity only; avoid animating width/height/top/left
183
+ - `loading-states` - Show skeleton or progress indicator when loading exceeds 300ms
184
+ - `excessive-motion` - Animate 1-2 key elements per view max
185
+ - `easing` - Use ease-out for entering, ease-in for exiting; avoid linear for UI transitions
186
+ - `motion-meaning` - Every animation must express a cause-effect relationship, not just be decorative (Apple HIG)
187
+ - `state-transition` - State changes (hover / active / expanded / collapsed / modal) should animate smoothly, not snap
188
+ - `continuity` - Page/screen transitions should maintain spatial continuity (shared element, directional slide) (Apple HIG)
189
+ - `parallax-subtle` - Use parallax sparingly; must respect reduced-motion and not cause disorientation (Apple HIG)
190
+ - `spring-physics` - Prefer spring/physics-based curves over linear or cubic-bezier for natural feel (Apple HIG fluid animations)
191
+ - `exit-faster-than-enter` - Exit animations shorter than enter (~60–70% of enter duration) to feel responsive (MD motion)
192
+ - `stagger-sequence` - Stagger list/grid item entrance by 30–50ms per item; avoid all-at-once or too-slow reveals (MD)
193
+ - `shared-element-transition` - Use shared element / hero transitions for visual continuity between screens (MD, HIG)
194
+ - `interruptible` - Animations must be interruptible; user tap/gesture cancels in-progress animation immediately (Apple HIG)
195
+ - `no-blocking-animation` - Never block user input during an animation; UI must stay interactive (Apple HIG)
196
+ - `fade-crossfade` - Use crossfade for content replacement within the same container (MD)
197
+ - `scale-feedback` - Subtle scale (0.95–1.05) on press for tappable cards/buttons; restore on release (HIG, MD)
198
+ - `gesture-feedback` - Drag, swipe, and pinch must provide real-time visual response tracking the finger (MD Motion)
199
+ - `hierarchy-motion` - Use translate/scale direction to express hierarchy: enter from below = deeper, exit upward = back (MD)
200
+ - `motion-consistency` - Unify duration/easing tokens globally; all animations share the same rhythm and feel
201
+ - `opacity-threshold` - Fading elements should not linger below opacity 0.2; either fade fully or remain visible
202
+ - `modal-motion` - Modals/sheets should animate from their trigger source (scale+fade or slide-in) for spatial context (HIG, MD)
203
+ - `navigation-direction` - Forward navigation animates left/up; backward animates right/down β€” keep direction logically consistent (HIG)
204
+ - `layout-shift-avoid` - Animations must not cause layout reflow or CLS; use transform for position changes
205
+
206
+ ### 8. Forms & Feedback (MEDIUM)
207
+
208
+ - `input-labels` - Visible label per input (not placeholder-only)
209
+ - `error-placement` - Show error below the related field
210
+ - `submit-feedback` - Loading then success/error state on submit
211
+ - `required-indicators` - Mark required fields (e.g. asterisk)
212
+ - `empty-states` - Helpful message and action when no content
213
+ - `toast-dismiss` - Auto-dismiss toasts in 3-5s
214
+ - `confirmation-dialogs` - Confirm before destructive actions
215
+ - `input-helper-text` - Provide persistent helper text below complex inputs, not just placeholder (Material Design)
216
+ - `disabled-states` - Disabled elements use reduced opacity (0.38–0.5) + cursor change + semantic attribute (MD)
217
+ - `progressive-disclosure` - Reveal complex options progressively; don't overwhelm users upfront (Apple HIG)
218
+ - `inline-validation` - Validate on blur (not keystroke); show error only after user finishes input (MD)
219
+ - `input-type-keyboard` - Use semantic input types (email, tel, number) to trigger the correct mobile keyboard (HIG, MD)
220
+ - `password-toggle` - Provide show/hide toggle for password fields (MD)
221
+ - `autofill-support` - Use autocomplete / textContentType attributes so the system can autofill (HIG, MD)
222
+ - `undo-support` - Allow undo for destructive or bulk actions (e.g. "Undo delete" toast) (Apple HIG)
223
+ - `success-feedback` - Confirm completed actions with brief visual feedback (checkmark, toast, color flash) (MD)
224
+ - `error-recovery` - Error messages must include a clear recovery path (retry, edit, help link) (HIG, MD)
225
+ - `multi-step-progress` - Multi-step flows show step indicator or progress bar; allow back navigation (MD)
226
+ - `form-autosave` - Long forms should auto-save drafts to prevent data loss on accidental dismissal (Apple HIG)
227
+ - `sheet-dismiss-confirm` - Confirm before dismissing a sheet/modal with unsaved changes (Apple HIG)
228
+ - `error-clarity` - Error messages must state cause + how to fix (not just "Invalid input") (HIG, MD)
229
+ - `field-grouping` - Group related fields logically (fieldset/legend or visual grouping) (MD)
230
+ - `read-only-distinction` - Read-only state should be visually and semantically different from disabled (MD)
231
+ - `focus-management` - After submit error, auto-focus the first invalid field (WCAG, MD)
232
+ - `error-summary` - For multiple errors, show summary at top with anchor links to each field (WCAG)
233
+ - `touch-friendly-input` - Mobile input height β‰₯44px to meet touch target requirements (Apple HIG)
234
+ - `destructive-emphasis` - Destructive actions use semantic danger color (red) and are visually separated from primary actions (HIG, MD)
235
+ - `toast-accessibility` - Toasts must not steal focus; use aria-live="polite" for screen reader announcement (WCAG)
236
+ - `aria-live-errors` - Form errors use aria-live region or role="alert" to notify screen readers (WCAG)
237
+ - `contrast-feedback` - Error and success state colors must meet 4.5:1 contrast ratio (WCAG, MD)
238
+ - `timeout-feedback` - Request timeout must show clear feedback with retry option (MD)
239
+
240
+ ### 9. Navigation Patterns (HIGH)
241
+
242
+ - `bottom-nav-limit` - Bottom navigation max 5 items; use labels with icons (Material Design)
243
+ - `drawer-usage` - Use drawer/sidebar for secondary navigation, not primary actions (Material Design)
244
+ - `back-behavior` - Back navigation must be predictable and consistent; preserve scroll/state (Apple HIG, MD)
245
+ - `deep-linking` - All key screens must be reachable via deep link / URL for sharing and notifications (Apple HIG, MD)
246
+ - `tab-bar-ios` - iOS: use bottom Tab Bar for top-level navigation (Apple HIG)
247
+ - `top-app-bar-android` - Android: use Top App Bar with navigation icon for primary structure (Material Design)
248
+ - `nav-label-icon` - Navigation items must have both icon and text label; icon-only nav harms discoverability (MD)
249
+ - `nav-state-active` - Current location must be visually highlighted (color, weight, indicator) in navigation (HIG, MD)
250
+ - `nav-hierarchy` - Primary nav (tabs/bottom bar) vs secondary nav (drawer/settings) must be clearly separated (MD)
251
+ - `modal-escape` - Modals and sheets must offer a clear close/dismiss affordance; swipe-down to dismiss on mobile (Apple HIG)
252
+ - `search-accessible` - Search must be easily reachable (top bar or tab); provide recent/suggested queries (MD)
253
+ - `breadcrumb-web` - Web: use breadcrumbs for 3+ level deep hierarchies to aid orientation (MD)
254
+ - `state-preservation` - Navigating back must restore previous scroll position, filter state, and input (HIG, MD)
255
+ - `gesture-nav-support` - Support system gesture navigation (iOS swipe-back, Android predictive back) without conflict (HIG, MD)
256
+ - `tab-badge` - Use badges on nav items sparingly to indicate unread/pending; clear after user visits (HIG, MD)
257
+ - `overflow-menu` - When actions exceed available space, use overflow/more menu instead of cramming (MD)
258
+ - `bottom-nav-top-level` - Bottom nav is for top-level screens only; never nest sub-navigation inside it (MD)
259
+ - `adaptive-navigation` - Large screens (β‰₯1024px) prefer sidebar; small screens use bottom/top nav (Material Adaptive)
260
+ - `back-stack-integrity` - Never silently reset the navigation stack or unexpectedly jump to home (HIG, MD)
261
+ - `navigation-consistency` - Navigation placement must stay the same across all pages; don't change by page type
262
+ - `avoid-mixed-patterns` - Don't mix Tab + Sidebar + Bottom Nav at the same hierarchy level
263
+ - `modal-vs-navigation` - Modals must not be used for primary navigation flows; they break the user's path (HIG)
264
+ - `focus-on-route-change` - After page transition, move focus to main content region for screen reader users (WCAG)
265
+ - `persistent-nav` - Core navigation must remain reachable from deep pages; don't hide it entirely in sub-flows (HIG, MD)
266
+ - `destructive-nav-separation` - Dangerous actions (delete account, logout) must be visually and spatially separated from normal nav items (HIG, MD)
267
+ - `empty-nav-state` - When a nav destination is unavailable, explain why instead of silently hiding it (MD)
268
+
269
+ ### 10. Charts & Data (LOW)
270
+
271
+ - `chart-type` - Match chart type to data type (trend β†’ line, comparison β†’ bar, proportion β†’ pie/donut)
272
+ - `color-guidance` - Use accessible color palettes; avoid red/green only pairs for colorblind users (WCAG, MD)
273
+ - `data-table` - Provide table alternative for accessibility; charts alone are not screen-reader friendly (WCAG)
274
+ - `pattern-texture` - Supplement color with patterns, textures, or shapes so data is distinguishable without color (WCAG, MD)
275
+ - `legend-visible` - Always show legend; position near the chart, not detached below a scroll fold (MD)
276
+ - `tooltip-on-interact` - Provide tooltips/data labels on hover (Web) or tap (mobile) showing exact values (HIG, MD)
277
+ - `axis-labels` - Label axes with units and readable scale; avoid truncated or rotated labels on mobile
278
+ - `responsive-chart` - Charts must reflow or simplify on small screens (e.g. horizontal bar instead of vertical, fewer ticks)
279
+ - `empty-data-state` - Show meaningful empty state when no data exists ("No data yet" + guidance), not a blank chart (MD)
280
+ - `loading-chart` - Use skeleton or shimmer placeholder while chart data loads; don't show an empty axis frame
281
+ - `animation-optional` - Chart entrance animations must respect prefers-reduced-motion; data should be readable immediately (HIG)
282
+ - `large-dataset` - For 1000+ data points, aggregate or sample; provide drill-down for detail instead of rendering all (MD)
283
+ - `number-formatting` - Use locale-aware formatting for numbers, dates, currencies on axes and labels (HIG, MD)
284
+ - `touch-target-chart` - Interactive chart elements (points, segments) must have β‰₯44pt tap area or expand on touch (Apple HIG)
285
+ - `no-pie-overuse` - Avoid pie/donut for >5 categories; switch to bar chart for clarity
286
+ - `contrast-data` - Data lines/bars vs background β‰₯3:1; data text labels β‰₯4.5:1 (WCAG)
287
+ - `legend-interactive` - Legends should be clickable to toggle series visibility (MD)
288
+ - `direct-labeling` - For small datasets, label values directly on the chart to reduce eye travel
289
+ - `tooltip-keyboard` - Tooltip content must be keyboard-reachable and not rely on hover alone (WCAG)
290
+ - `sortable-table` - Data tables must support sorting with aria-sort indicating current sort state (WCAG)
291
+ - `axis-readability` - Axis ticks must not be cramped; maintain readable spacing, auto-skip on small screens
292
+ - `data-density` - Limit information density per chart to avoid cognitive overload; split into multiple charts if needed
293
+ - `trend-emphasis` - Emphasize data trends over decoration; avoid heavy gradients/shadows that obscure the data
294
+ - `gridline-subtle` - Grid lines should be low-contrast (e.g. gray-200) so they don't compete with data
295
+ - `focusable-elements` - Interactive chart elements (points, bars, slices) must be keyboard-navigable (WCAG)
296
+ - `screen-reader-summary` - Provide a text summary or aria-label describing the chart's key insight for screen readers (WCAG)
297
+ - `error-state-chart` - Data load failure must show error message with retry action, not a broken/empty chart
298
+ - `export-option` - For data-heavy products, offer CSV/image export of chart data
299
+ - `drill-down-consistency` - Drill-down interactions must maintain a clear back-path and hierarchy breadcrumb
300
+ - `time-scale-clarity` - Time series charts must clearly label time granularity (day/week/month) and allow switching
301
+
302
+ ## How to Use
303
+
304
+ Search specific domains using the CLI tool below.
305
+
306
+ ---
307
+
308
+ ## Prerequisites
309
+
310
+ Check if Python is installed:
311
+
312
+ ```bash
313
+ python3 --version || python --version
314
+ ```
315
+
316
+ If Python is not installed, install it based on user's OS:
317
+
318
+ **macOS:**
319
+ ```bash
320
+ brew install python3
321
+ ```
322
+
323
+ **Ubuntu/Debian:**
324
+ ```bash
325
+ sudo apt update && sudo apt install python3
326
+ ```
327
+
328
+ **Windows:**
329
+ ```powershell
330
+ winget install Python.Python.3.12
331
+ ```
332
+
333
+ ---
334
+
335
+ ## How to Use This Skill
336
+
337
+ Use this skill when the user requests any of the following:
338
+
339
+ | Scenario | Trigger Examples | Start From |
340
+ |----------|-----------------|------------|
341
+ | **New project / page** | "Build a landing page", "Build a dashboard" | Step 1 β†’ Step 2 (design system) |
342
+ | **New component** | "Create a pricing card", "Add a modal" | Step 3 (domain search: style, ux) |
343
+ | **Choose style / color / font** | "What style fits a fintech app?", "Recommend a color palette" | Step 2 (design system) |
344
+ | **Review existing UI** | "Review this page for UX issues", "Check accessibility" | Quick Reference checklist above |
345
+ | **Fix a UI bug** | "Button hover is broken", "Layout shifts on load" | Quick Reference β†’ relevant section |
346
+ | **Improve / optimize** | "Make this faster", "Improve mobile experience" | Step 3 (domain search: ux, react) |
347
+ | **Implement dark mode** | "Add dark mode support" | Step 3 (domain: style "dark mode") |
348
+ | **Add charts / data viz** | "Add an analytics dashboard chart" | Step 3 (domain: chart) |
349
+ | **Stack best practices** | "React performance tips"、"SwiftUI navigation" | Step 4 (stack search) |
350
+
351
+ Follow this workflow:
352
+
353
+ ### Step 1: Analyze User Requirements
354
+
355
+ Extract key information from user request:
356
+ - **Product type**: Entertainment (social, video, music, gaming), Tool (scanner, editor, converter), Productivity (task manager, notes, calendar), or hybrid
357
+ - **Target audience**: C-end consumer users; consider age group, usage context (commute, leisure, work)
358
+ - **Style keywords**: playful, vibrant, minimal, dark mode, content-first, immersive, etc.
359
+ - **Stack**: React Native (this project's only tech stack)
360
+
361
+ ### Step 2: Generate Design System (REQUIRED)
362
+
363
+ **Always start with `--design-system`** to get comprehensive recommendations with reasoning:
364
+
365
+ ```bash
366
+ python3 skills/ui-ux-pro-max/scripts/search.py "<product_type> <industry> <keywords>" --design-system [-p "Project Name"]
367
+ ```
368
+
369
+ This command:
370
+ 1. Searches domains in parallel (product, style, color, landing, typography)
371
+ 2. Applies reasoning rules from `ui-reasoning.csv` to select best matches
372
+ 3. Returns complete design system: pattern, style, colors, typography, effects
373
+ 4. Includes anti-patterns to avoid
374
+
375
+ **Example:**
376
+ ```bash
377
+ python3 skills/ui-ux-pro-max/scripts/search.py "beauty spa wellness service" --design-system -p "Serenity Spa"
378
+ ```
379
+
380
+ ### Step 2b: Persist Design System (Master + Overrides Pattern)
381
+
382
+ To save the design system for **hierarchical retrieval across sessions**, add `--persist`:
383
+
384
+ ```bash
385
+ python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name"
386
+ ```
387
+
388
+ This creates:
389
+ - `design-system/MASTER.md` β€” Global Source of Truth with all design rules
390
+ - `design-system/pages/` β€” Folder for page-specific overrides
391
+
392
+ **With page-specific override:**
393
+ ```bash
394
+ python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name" --page "dashboard"
395
+ ```
396
+
397
+ This also creates:
398
+ - `design-system/pages/dashboard.md` β€” Page-specific deviations from Master
399
+
400
+ **How hierarchical retrieval works:**
401
+ 1. When building a specific page (e.g., "Checkout"), first check `design-system/pages/checkout.md`
402
+ 2. If the page file exists, its rules **override** the Master file
403
+ 3. If not, use `design-system/MASTER.md` exclusively
404
+
405
+ **Context-aware retrieval prompt:**
406
+ ```
407
+ I am building the [Page Name] page. Please read design-system/MASTER.md.
408
+ Also check if design-system/pages/[page-name].md exists.
409
+ If the page file exists, prioritize its rules.
410
+ If not, use the Master rules exclusively.
411
+ Now, generate the code...
412
+ ```
413
+
414
+ ### Step 3: Supplement with Detailed Searches (as needed)
415
+
416
+ After getting the design system, use domain searches to get additional details:
417
+
418
+ ```bash
419
+ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --domain <domain> [-n <max_results>]
420
+ ```
421
+
422
+ **When to use detailed searches:**
423
+
424
+ | Need | Domain | Example |
425
+ |------|--------|---------|
426
+ | Product type patterns | `product` | `--domain product "entertainment social"` |
427
+ | More style options | `style` | `--domain style "glassmorphism dark"` |
428
+ | Color palettes | `color` | `--domain color "entertainment vibrant"` |
429
+ | Font pairings | `typography` | `--domain typography "playful modern"` |
430
+ | Chart recommendations | `chart` | `--domain chart "real-time dashboard"` |
431
+ | UX best practices | `ux` | `--domain ux "animation accessibility"` |
432
+ | Alternative fonts | `typography` | `--domain typography "elegant luxury"` |
433
+ | Individual Google Fonts | `google-fonts` | `--domain google-fonts "sans serif popular variable"` |
434
+ | Landing structure | `landing` | `--domain landing "hero social-proof"` |
435
+ | React Native perf | `react` | `--domain react "rerender memo list"` |
436
+ | App interface a11y | `web` | `--domain web "accessibilityLabel touch safe-areas"` |
437
+ | AI prompt / CSS keywords | `prompt` | `--domain prompt "minimalism"` |
438
+
439
+ ### Step 4: Stack Guidelines (React Native)
440
+
441
+ Get React Native implementation-specific best practices:
442
+
443
+ ```bash
444
+ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
445
+ ```
446
+
447
+ ---
448
+
449
+ ## Search Reference
450
+
451
+ ### Available Domains
452
+
453
+ | Domain | Use For | Example Keywords |
454
+ |--------|---------|------------------|
455
+ | `product` | Product type recommendations | SaaS, e-commerce, portfolio, healthcare, beauty, service |
456
+ | `style` | UI styles, colors, effects | glassmorphism, minimalism, dark mode, brutalism |
457
+ | `typography` | Font pairings, Google Fonts | elegant, playful, professional, modern |
458
+ | `color` | Color palettes by product type | saas, ecommerce, healthcare, beauty, fintech, service |
459
+ | `landing` | Page structure, CTA strategies | hero, hero-centric, testimonial, pricing, social-proof |
460
+ | `chart` | Chart types, library recommendations | trend, comparison, timeline, funnel, pie |
461
+ | `ux` | Best practices, anti-patterns | animation, accessibility, z-index, loading |
462
+ | `google-fonts` | Individual Google Fonts lookup | sans serif, monospace, japanese, variable font, popular |
463
+ | `react` | React/Next.js performance | waterfall, bundle, suspense, memo, rerender, cache |
464
+ | `web` | App interface guidelines (iOS/Android/React Native) | accessibilityLabel, touch targets, safe areas, Dynamic Type |
465
+ | `prompt` | AI prompts, CSS keywords | (style name) |
466
+
467
+ ### Available Stacks
468
+
469
+ | Stack | Focus |
470
+ |-------|-------|
471
+ | `react-native` | Components, Navigation, Lists |
472
+
473
+ ---
474
+
475
+ ## Example Workflow
476
+
477
+ **User request:** "Make an AI search homepage."
478
+
479
+ ### Step 1: Analyze Requirements
480
+ - Product type: Tool (AI search engine)
481
+ - Target audience: C-end users looking for fast, intelligent search
482
+ - Style keywords: modern, minimal, content-first, dark mode
483
+ - Stack: React Native
484
+
485
+ ### Step 2: Generate Design System (REQUIRED)
486
+
487
+ ```bash
488
+ python3 skills/ui-ux-pro-max/scripts/search.py "AI search tool modern minimal" --design-system -p "AI Search"
489
+ ```
490
+
491
+ **Output:** Complete design system with pattern, style, colors, typography, effects, and anti-patterns.
492
+
493
+ ### Step 3: Supplement with Detailed Searches (as needed)
494
+
495
+ ```bash
496
+ # Get style options for a modern tool product
497
+ python3 skills/ui-ux-pro-max/scripts/search.py "minimalism dark mode" --domain style
498
+
499
+ # Get UX best practices for search interaction and loading
500
+ python3 skills/ui-ux-pro-max/scripts/search.py "search loading animation" --domain ux
501
+ ```
502
+
503
+ ### Step 4: Stack Guidelines
504
+
505
+ ```bash
506
+ python3 skills/ui-ux-pro-max/scripts/search.py "list performance navigation" --stack react-native
507
+ ```
508
+
509
+ **Then:** Synthesize design system + detailed searches and implement the design.
510
+
511
+ ---
512
+
513
+ ## Output Formats
514
+
515
+ The `--design-system` flag supports two output formats:
516
+
517
+ ```bash
518
+ # ASCII box (default) - best for terminal display
519
+ python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system
520
+
521
+ # Markdown - best for documentation
522
+ python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system -f markdown
523
+ ```
524
+
525
+ ---
526
+
527
+ ## Tips for Better Results
528
+
529
+ ### Query Strategy
530
+
531
+ - Use **multi-dimensional keywords** β€” combine product + industry + tone + density: `"entertainment social vibrant content-dense"` not just `"app"`
532
+ - Try different keywords for the same need: `"playful neon"` β†’ `"vibrant dark"` β†’ `"content-first minimal"`
533
+ - Use `--design-system` first for full recommendations, then `--domain` to deep-dive any dimension you're unsure about
534
+ - Always add `--stack react-native` for implementation-specific guidance
535
+
536
+ ### Common Sticking Points
537
+
538
+ | Problem | What to Do |
539
+ |---------|------------|
540
+ | Can't decide on style/color | Re-run `--design-system` with different keywords |
541
+ | Dark mode contrast issues | Quick Reference Β§6: `color-dark-mode` + `color-accessible-pairs` |
542
+ | Animations feel unnatural | Quick Reference Β§7: `spring-physics` + `easing` + `exit-faster-than-enter` |
543
+ | Form UX is poor | Quick Reference Β§8: `inline-validation` + `error-clarity` + `focus-management` |
544
+ | Navigation feels confusing | Quick Reference Β§9: `nav-hierarchy` + `bottom-nav-limit` + `back-behavior` |
545
+ | Layout breaks on small screens | Quick Reference Β§5: `mobile-first` + `breakpoint-consistency` |
546
+ | Performance / jank | Quick Reference Β§3: `virtualize-lists` + `main-thread-budget` + `debounce-throttle` |
547
+
548
+ ### Pre-Delivery Checklist
549
+
550
+ - Run `--domain ux "animation accessibility z-index loading"` as a UX validation pass before implementation
551
+ - Run through Quick Reference **Β§1–§3** (CRITICAL + HIGH) as a final review
552
+ - Test on 375px (small phone) and landscape orientation
553
+ - Verify behavior with **reduced-motion** enabled and **Dynamic Type** at largest size
554
+ - Check dark mode contrast independently (don't assume light mode values work)
555
+ - Confirm all touch targets β‰₯44pt and no content hidden behind safe areas
556
+
557
+ ---
558
+
559
+ ## Common Rules for Professional UI
560
+
561
+ These are frequently overlooked issues that make UI look unprofessional:
562
+ Scope notice: The rules below are for App UI (iOS/Android/React Native/Flutter), not desktop-web interaction patterns.
563
+
564
+ ### Icons & Visual Elements
565
+
566
+ | Rule | Standard | Avoid | Why It Matters |
567
+ |------|----------|--------|----------------|
568
+ | **No Emoji as Structural Icons** | Use vector-based icons (e.g., Lucide, react-native-vector-icons, @expo/vector-icons). | Using emojis (🎨 πŸš€ βš™οΈ) for navigation, settings, or system controls. | Emojis are font-dependent, inconsistent across platforms, and cannot be controlled via design tokens. |
569
+ | **Vector-Only Assets** | Use SVG or platform vector icons that scale cleanly and support theming. | Raster PNG icons that blur or pixelate. | Ensures scalability, crisp rendering, and dark/light mode adaptability. |
570
+ | **Stable Interaction States** | Use color, opacity, or elevation transitions for press states without changing layout bounds. | Layout-shifting transforms that move surrounding content or trigger visual jitter. | Prevents unstable interactions and preserves smooth motion/perceived quality on mobile. |
571
+ | **Correct Brand Logos** | Use official brand assets and follow their usage guidelines (spacing, color, clear space). | Guessing logo paths, recoloring unofficially, or modifying proportions. | Prevents brand misuse and ensures legal/platform compliance. |
572
+ | **Consistent Icon Sizing** | Define icon sizes as design tokens (e.g., icon-sm, icon-md = 24pt, icon-lg). | Mixing arbitrary values like 20pt / 24pt / 28pt randomly. | Maintains rhythm and visual hierarchy across the interface. |
573
+ | **Stroke Consistency** | Use a consistent stroke width within the same visual layer (e.g., 1.5px or 2px). | Mixing thick and thin stroke styles arbitrarily. | Inconsistent strokes reduce perceived polish and cohesion. |
574
+ | **Filled vs Outline Discipline** | Use one icon style per hierarchy level. | Mixing filled and outline icons at the same hierarchy level. | Maintains semantic clarity and stylistic coherence. |
575
+ | **Touch Target Minimum** | Minimum 44Γ—44pt interactive area (use hitSlop if icon is smaller). | Small icons without expanded tap area. | Meets accessibility and platform usability standards. |
576
+ | **Icon Alignment** | Align icons to text baseline and maintain consistent padding. | Misaligned icons or inconsistent spacing around them. | Prevents subtle visual imbalance that reduces perceived quality. |
577
+ | **Icon Contrast** | Follow WCAG contrast standards: 4.5:1 for small elements, 3:1 minimum for larger UI glyphs. | Low-contrast icons that blend into the background. | Ensures accessibility in both light and dark modes. |
578
+
579
+
580
+ ### Interaction (App)
581
+
582
+ | Rule | Do | Don't |
583
+ |------|----|----- |
584
+ | **Tap feedback** | Provide clear pressed feedback (ripple/opacity/elevation) within 80-150ms | No visual response on tap |
585
+ | **Animation timing** | Keep micro-interactions around 150-300ms with platform-native easing | Instant transitions or slow animations (>500ms) |
586
+ | **Accessibility focus** | Ensure screen reader focus order matches visual order and labels are descriptive | Unlabeled controls or confusing focus traversal |
587
+ | **Disabled state clarity** | Use disabled semantics (`disabled`/native disabled props), reduced emphasis, and no tap action | Controls that look tappable but do nothing |
588
+ | **Touch target minimum** | Keep tap areas >=44x44pt (iOS) or >=48x48dp (Android), expand hit area when icon is smaller | Tiny tap targets or icon-only hit areas without padding |
589
+ | **Gesture conflict prevention** | Keep one primary gesture per region and avoid nested tap/drag conflicts | Overlapping gestures causing accidental actions |
590
+ | **Semantic native controls** | Prefer native interactive primitives (`Button`, `Pressable`, platform equivalents) with proper accessibility roles | Generic containers used as primary controls without semantics |
591
+
592
+ ### Light/Dark Mode Contrast
593
+
594
+ | Rule | Do | Don't |
595
+ |------|----|----- |
596
+ | **Surface readability (light)** | Keep cards/surfaces clearly separated from background with sufficient opacity/elevation | Overly transparent surfaces that blur hierarchy |
597
+ | **Text contrast (light)** | Maintain body text contrast >=4.5:1 against light surfaces | Low-contrast gray body text |
598
+ | **Text contrast (dark)** | Maintain primary text contrast >=4.5:1 and secondary text >=3:1 on dark surfaces | Dark mode text that blends into background |
599
+ | **Border and divider visibility** | Ensure separators are visible in both themes (not just light mode) | Theme-specific borders disappearing in one mode |
600
+ | **State contrast parity** | Keep pressed/focused/disabled states equally distinguishable in light and dark themes | Defining interaction states for one theme only |
601
+ | **Token-driven theming** | Use semantic color tokens mapped per theme across app surfaces/text/icons | Hardcoded per-screen hex values |
602
+ | **Scrim and modal legibility** | Use a modal scrim strong enough to isolate foreground content (typically 40-60% black) | Weak scrim that leaves background visually competing |
603
+
604
+ ### Layout & Spacing
605
+
606
+ | Rule | Do | Don't |
607
+ |------|----|----- |
608
+ | **Safe-area compliance** | Respect top/bottom safe areas for all fixed headers, tab bars, and CTA bars | Placing fixed UI under notch, status bar, or gesture area |
609
+ | **System bar clearance** | Add spacing for status/navigation bars and gesture home indicator | Let tappable content collide with OS chrome |
610
+ | **Consistent content width** | Keep predictable content width per device class (phone/tablet) | Mixing arbitrary widths between screens |
611
+ | **8dp spacing rhythm** | Use a consistent 4/8dp spacing system for padding/gaps/section spacing | Random spacing increments with no rhythm |
612
+ | **Readable text measure** | Keep long-form text readable on large devices (avoid edge-to-edge paragraphs on tablets) | Full-width long text that hurts readability |
613
+ | **Section spacing hierarchy** | Define clear vertical rhythm tiers (e.g., 16/24/32/48) by hierarchy | Similar UI levels with inconsistent spacing |
614
+ | **Adaptive gutters by breakpoint** | Increase horizontal insets on larger widths and in landscape | Same narrow gutter on all device sizes/orientations |
615
+ | **Scroll and fixed element coexistence** | Add bottom/top content insets so lists are not hidden behind fixed bars | Scroll content obscured by sticky headers/footers |
616
+
617
+ ---
618
+
619
+ ## Pre-Delivery Checklist
620
+
621
+ Before delivering UI code, verify these items:
622
+ Scope notice: This checklist is for App UI (iOS/Android/React Native/Flutter).
623
+
624
+ ### Visual Quality
625
+ - [ ] No emojis used as icons (use SVG instead)
626
+ - [ ] All icons come from a consistent icon family and style
627
+ - [ ] Official brand assets are used with correct proportions and clear space
628
+ - [ ] Pressed-state visuals do not shift layout bounds or cause jitter
629
+ - [ ] Semantic theme tokens are used consistently (no ad-hoc per-screen hardcoded colors)
630
+
631
+ ### Interaction
632
+ - [ ] All tappable elements provide clear pressed feedback (ripple/opacity/elevation)
633
+ - [ ] Touch targets meet minimum size (>=44x44pt iOS, >=48x48dp Android)
634
+ - [ ] Micro-interaction timing stays in the 150-300ms range with native-feeling easing
635
+ - [ ] Disabled states are visually clear and non-interactive
636
+ - [ ] Screen reader focus order matches visual order, and interactive labels are descriptive
637
+ - [ ] Gesture regions avoid nested/conflicting interactions (tap/drag/back-swipe conflicts)
638
+
639
+ ### Light/Dark Mode
640
+ - [ ] Primary text contrast >=4.5:1 in both light and dark mode
641
+ - [ ] Secondary text contrast >=3:1 in both light and dark mode
642
+ - [ ] Dividers/borders and interaction states are distinguishable in both modes
643
+ - [ ] Modal/drawer scrim opacity is strong enough to preserve foreground legibility (typically 40-60% black)
644
+ - [ ] Both themes are tested before delivery (not inferred from a single theme)
645
+
646
+ ### Layout
647
+ - [ ] Safe areas are respected for headers, tab bars, and bottom CTA bars
648
+ - [ ] Scroll content is not hidden behind fixed/sticky bars
649
+ - [ ] Verified on small phone, large phone, and tablet (portrait + landscape)
650
+ - [ ] Horizontal insets/gutters adapt correctly by device size and orientation
651
+ - [ ] 4/8dp spacing rhythm is maintained across component, section, and page levels
652
+ - [ ] Long-form text measure remains readable on larger devices (no edge-to-edge paragraphs)
653
+
654
+ ### Accessibility
655
+ - [ ] All meaningful images/icons have accessibility labels
656
+ - [ ] Form fields have labels, hints, and clear error messages
657
+ - [ ] Color is not the only indicator
658
+ - [ ] Reduced motion and dynamic text size are supported without layout breakage
659
+ - [ ] Accessibility traits/roles/states (selected, disabled, expanded) are announced correctly
.agent/skills/ui-ux-pro-max/data ADDED
@@ -0,0 +1 @@
 
 
1
+ ../../../src/ui-ux-pro-max/data
.agent/skills/ui-ux-pro-max/scripts ADDED
@@ -0,0 +1 @@
 
 
1
+ ../../../src/ui-ux-pro-max/scripts
.agents/skills/frontend-design/LICENSE.txt ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
.agents/skills/frontend-design/SKILL.md ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: frontend-design
3
+ description: "Create distinctive, production-grade frontend interfaces with intentional aesthetics, high craft, and non-generic visual identity. Use when building or styling web UIs, components, pages, dashboard..."
4
+ risk: unknown
5
+ source: community
6
+ date_added: "2026-02-27"
7
+ ---
8
+
9
+ # Frontend Design (Distinctive, Production-Grade)
10
+
11
+ You are a **frontend designer-engineer**, not a layout generator.
12
+
13
+ Your goal is to create **memorable, high-craft interfaces** that:
14
+
15
+ * Avoid generic β€œAI UI” patterns
16
+ * Express a clear aesthetic point of view
17
+ * Are fully functional and production-ready
18
+ * Translate design intent directly into code
19
+
20
+ This skill prioritizes **intentional design systems**, not default frameworks.
21
+
22
+ ---
23
+
24
+ ## 1. Core Design Mandate
25
+
26
+ Every output must satisfy **all four**:
27
+
28
+ 1. **Intentional Aesthetic Direction**
29
+ A named, explicit design stance (e.g. *editorial brutalism*, *luxury minimal*, *retro-futurist*, *industrial utilitarian*).
30
+
31
+ 2. **Technical Correctness**
32
+ Real, working HTML/CSS/JS or framework code β€” not mockups.
33
+
34
+ 3. **Visual Memorability**
35
+ At least one element the user will remember 24 hours later.
36
+
37
+ 4. **Cohesive Restraint**
38
+ No random decoration. Every flourish must serve the aesthetic thesis.
39
+
40
+ ❌ No default layouts
41
+ ❌ No design-by-components
42
+ ❌ No β€œsafe” palettes or fonts
43
+ βœ… Strong opinions, well executed
44
+
45
+ ---
46
+
47
+ ## 2. Design Feasibility & Impact Index (DFII)
48
+
49
+ Before building, evaluate the design direction using DFII.
50
+
51
+ ### DFII Dimensions (1–5)
52
+
53
+ | Dimension | Question |
54
+ | ------------------------------ | ------------------------------------------------------------ |
55
+ | **Aesthetic Impact** | How visually distinctive and memorable is this direction? |
56
+ | **Context Fit** | Does this aesthetic suit the product, audience, and purpose? |
57
+ | **Implementation Feasibility** | Can this be built cleanly with available tech? |
58
+ | **Performance Safety** | Will it remain fast and accessible? |
59
+ | **Consistency Risk** | Can this be maintained across screens/components? |
60
+
61
+ ### Scoring Formula
62
+
63
+ ```
64
+ DFII = (Impact + Fit + Feasibility + Performance) βˆ’ Consistency Risk
65
+ ```
66
+
67
+ **Range:** `-5 β†’ +15`
68
+
69
+ ### Interpretation
70
+
71
+ | DFII | Meaning | Action |
72
+ | --------- | --------- | --------------------------- |
73
+ | **12–15** | Excellent | Execute fully |
74
+ | **8–11** | Strong | Proceed with discipline |
75
+ | **4–7** | Risky | Reduce scope or effects |
76
+ | **≀ 3** | Weak | Rethink aesthetic direction |
77
+
78
+ ---
79
+
80
+ ## 3. Mandatory Design Thinking Phase
81
+
82
+ Before writing code, explicitly define:
83
+
84
+ ### 1. Purpose
85
+
86
+ * What action should this interface enable?
87
+ * Is it persuasive, functional, exploratory, or expressive?
88
+
89
+ ### 2. Tone (Choose One Dominant Direction)
90
+
91
+ Examples (non-exhaustive):
92
+
93
+ * Brutalist / Raw
94
+ * Editorial / Magazine
95
+ * Luxury / Refined
96
+ * Retro-futuristic
97
+ * Industrial / Utilitarian
98
+ * Organic / Natural
99
+ * Playful / Toy-like
100
+ * Maximalist / Chaotic
101
+ * Minimalist / Severe
102
+
103
+ ⚠️ Do not blend more than **two**.
104
+
105
+ ### 3. Differentiation Anchor
106
+
107
+ Answer:
108
+
109
+ > β€œIf this were screenshotted with the logo removed, how would someone recognize it?”
110
+
111
+ This anchor must be visible in the final UI.
112
+
113
+ ---
114
+
115
+ ## 4. Aesthetic Execution Rules (Non-Negotiable)
116
+
117
+ ### Typography
118
+
119
+ * Avoid system fonts and AI-defaults (Inter, Roboto, Arial, etc.)
120
+ * Choose:
121
+
122
+ * 1 expressive display font
123
+ * 1 restrained body font
124
+ * Use typography structurally (scale, rhythm, contrast)
125
+
126
+ ### Color & Theme
127
+
128
+ * Commit to a **dominant color story**
129
+ * Use CSS variables exclusively
130
+ * Prefer:
131
+
132
+ * One dominant tone
133
+ * One accent
134
+ * One neutral system
135
+ * Avoid evenly-balanced palettes
136
+
137
+ ### Spatial Composition
138
+
139
+ * Break the grid intentionally
140
+ * Use:
141
+
142
+ * Asymmetry
143
+ * Overlap
144
+ * Negative space OR controlled density
145
+ * White space is a design element, not absence
146
+
147
+ ### Motion
148
+
149
+ * Motion must be:
150
+
151
+ * Purposeful
152
+ * Sparse
153
+ * High-impact
154
+ * Prefer:
155
+
156
+ * One strong entrance sequence
157
+ * A few meaningful hover states
158
+ * Avoid decorative micro-motion spam
159
+
160
+ ### Texture & Depth
161
+
162
+ Use when appropriate:
163
+
164
+ * Noise / grain overlays
165
+ * Gradient meshes
166
+ * Layered translucency
167
+ * Custom borders or dividers
168
+ * Shadows with narrative intent (not defaults)
169
+
170
+ ---
171
+
172
+ ## 5. Implementation Standards
173
+
174
+ ### Code Requirements
175
+
176
+ * Clean, readable, and modular
177
+ * No dead styles
178
+ * No unused animations
179
+ * Semantic HTML
180
+ * Accessible by default (contrast, focus, keyboard)
181
+
182
+ ### Framework Guidance
183
+
184
+ * **HTML/CSS**: Prefer native features, modern CSS
185
+ * **React**: Functional components, composable styles
186
+ * **Animation**:
187
+
188
+ * CSS-first
189
+ * Framer Motion only when justified
190
+
191
+ ### Complexity Matching
192
+
193
+ * Maximalist design β†’ complex code (animations, layers)
194
+ * Minimalist design β†’ extremely precise spacing & type
195
+
196
+ Mismatch = failure.
197
+
198
+ ---
199
+
200
+ ## 6. Required Output Structure
201
+
202
+ When generating frontend work:
203
+
204
+ ### 1. Design Direction Summary
205
+
206
+ * Aesthetic name
207
+ * DFII score
208
+ * Key inspiration (conceptual, not visual plagiarism)
209
+
210
+ ### 2. Design System Snapshot
211
+
212
+ * Fonts (with rationale)
213
+ * Color variables
214
+ * Spacing rhythm
215
+ * Motion philosophy
216
+
217
+ ### 3. Implementation
218
+
219
+ * Full working code
220
+ * Comments only where intent isn’t obvious
221
+
222
+ ### 4. Differentiation Callout
223
+
224
+ Explicitly state:
225
+
226
+ > β€œThis avoids generic UI by doing X instead of Y.”
227
+
228
+ ---
229
+
230
+ ## 7. Anti-Patterns (Immediate Failure)
231
+
232
+ ❌ Inter/Roboto/system fonts
233
+ ❌ Purple-on-white SaaS gradients
234
+ ❌ Default Tailwind/ShadCN layouts
235
+ ❌ Symmetrical, predictable sections
236
+ ❌ Overused AI design tropes
237
+ ❌ Decoration without intent
238
+
239
+ If the design could be mistaken for a template β†’ restart.
240
+
241
+ ---
242
+
243
+ ## 8. Integration With Other Skills
244
+
245
+ * **page-cro** β†’ Layout hierarchy & conversion flow
246
+ * **copywriting** β†’ Typography & message rhythm
247
+ * **marketing-psychology** β†’ Visual persuasion & bias alignment
248
+ * **branding** β†’ Visual identity consistency
249
+ * **ab-test-setup** β†’ Variant-safe design systems
250
+
251
+ ---
252
+
253
+ ## 9. Operator Checklist
254
+
255
+ Before finalizing output:
256
+
257
+ * [ ] Clear aesthetic direction stated
258
+ * [ ] DFII β‰₯ 8
259
+ * [ ] One memorable design anchor
260
+ * [ ] No generic fonts/colors/layouts
261
+ * [ ] Code matches design ambition
262
+ * [ ] Accessible and performant
263
+
264
+ ---
265
+
266
+ ## 10. Questions to Ask (If Needed)
267
+
268
+ 1. Who is this for, emotionally?
269
+ 2. Should this feel trustworthy, exciting, calm, or provocative?
270
+ 3. Is memorability or clarity more important?
271
+ 4. Will this scale to other pages/components?
272
+ 5. What should users *feel* in the first 3 seconds?
273
+
274
+ ---
275
+
276
+ ## When to Use
277
+ This skill is applicable to execute the workflow or actions described in the overview.
.agents/skills/ui-ux-pro-max/SKILL.md ADDED
@@ -0,0 +1,659 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: ui-ux-pro-max
3
+ description: "UI/UX design intelligence for web and mobile. Includes 50+ styles, 161 color palettes, 57 font pairings, 161 product types, 99 UX guidelines, and 25 chart types across 10 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn/ui, and HTML/CSS). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, and check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, and mobile app. Elements: button, modal, navbar, sidebar, card, table, form, and chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, and flat design. Topics: color systems, accessibility, animation, layout, typography, font pairing, spacing, interaction states, shadow, and gradient. Integrations: shadcn/ui MCP for component search and examples."
4
+ ---
5
+
6
+ # UI/UX Pro Max - Design Intelligence
7
+
8
+ Comprehensive design guide for web and mobile applications. Contains 50+ styles, 161 color palettes, 57 font pairings, 161 product types with reasoning rules, 99 UX guidelines, and 25 chart types across 10 technology stacks. Searchable database with priority-based recommendations.
9
+
10
+ ## When to Apply
11
+
12
+ This Skill should be used when the task involves **UI structure, visual design decisions, interaction patterns, or user experience quality control**.
13
+
14
+ ### Must Use
15
+
16
+ This Skill must be invoked in the following situations:
17
+
18
+ - Designing new pages (Landing Page, Dashboard, Admin, SaaS, Mobile App)
19
+ - Creating or refactoring UI components (buttons, modals, forms, tables, charts, etc.)
20
+ - Choosing color schemes, typography systems, spacing standards, or layout systems
21
+ - Reviewing UI code for user experience, accessibility, or visual consistency
22
+ - Implementing navigation structures, animations, or responsive behavior
23
+ - Making product-level design decisions (style, information hierarchy, brand expression)
24
+ - Improving perceived quality, clarity, or usability of interfaces
25
+
26
+ ### Recommended
27
+
28
+ This Skill is recommended in the following situations:
29
+
30
+ - UI looks "not professional enough" but the reason is unclear
31
+ - Receiving feedback on usability or experience
32
+ - Pre-launch UI quality optimization
33
+ - Aligning cross-platform design (Web / iOS / Android)
34
+ - Building design systems or reusable component libraries
35
+
36
+ ### Skip
37
+
38
+ This Skill is not needed in the following situations:
39
+
40
+ - Pure backend logic development
41
+ - Only involving API or database design
42
+ - Performance optimization unrelated to the interface
43
+ - Infrastructure or DevOps work
44
+ - Non-visual scripts or automation tasks
45
+
46
+ **Decision criteria**: If the task will change how a feature **looks, feels, moves, or is interacted with**, this Skill should be used.
47
+
48
+ ## Rule Categories by Priority
49
+
50
+ *For human/AI reference: follow priority 1β†’10 to decide which rule category to focus on first; use `--domain <Domain>` to query details when needed. Scripts do not read this table.*
51
+
52
+ | Priority | Category | Impact | Domain | Key Checks (Must Have) | Anti-Patterns (Avoid) |
53
+ |----------|----------|--------|--------|------------------------|------------------------|
54
+ | 1 | Accessibility | CRITICAL | `ux` | Contrast 4.5:1, Alt text, Keyboard nav, Aria-labels | Removing focus rings, Icon-only buttons without labels |
55
+ | 2 | Touch & Interaction | CRITICAL | `ux` | Min size 44Γ—44px, 8px+ spacing, Loading feedback | Reliance on hover only, Instant state changes (0ms) |
56
+ | 3 | Performance | HIGH | `ux` | WebP/AVIF, Lazy loading, Reserve space (CLS &lt; 0.1) | Layout thrashing, Cumulative Layout Shift |
57
+ | 4 | Style Selection | HIGH | `style`, `product` | Match product type, Consistency, SVG icons (no emoji) | Mixing flat & skeuomorphic randomly, Emoji as icons |
58
+ | 5 | Layout & Responsive | HIGH | `ux` | Mobile-first breakpoints, Viewport meta, No horizontal scroll | Horizontal scroll, Fixed px container widths, Disable zoom |
59
+ | 6 | Typography & Color | MEDIUM | `typography`, `color` | Base 16px, Line-height 1.5, Semantic color tokens | Text &lt; 12px body, Gray-on-gray, Raw hex in components |
60
+ | 7 | Animation | MEDIUM | `ux` | Duration 150–300ms, Motion conveys meaning, Spatial continuity | Decorative-only animation, Animating width/height, No reduced-motion |
61
+ | 8 | Forms & Feedback | MEDIUM | `ux` | Visible labels, Error near field, Helper text, Progressive disclosure | Placeholder-only label, Errors only at top, Overwhelm upfront |
62
+ | 9 | Navigation Patterns | HIGH | `ux` | Predictable back, Bottom nav ≀5, Deep linking | Overloaded nav, Broken back behavior, No deep links |
63
+ | 10 | Charts & Data | LOW | `chart` | Legends, Tooltips, Accessible colors | Relying on color alone to convey meaning |
64
+
65
+ ## Quick Reference
66
+
67
+ ### 1. Accessibility (CRITICAL)
68
+
69
+ - `color-contrast` - Minimum 4.5:1 ratio for normal text (large text 3:1); Material Design
70
+ - `focus-states` - Visible focus rings on interactive elements (2–4px; Apple HIG, MD)
71
+ - `alt-text` - Descriptive alt text for meaningful images
72
+ - `aria-labels` - aria-label for icon-only buttons; accessibilityLabel in native (Apple HIG)
73
+ - `keyboard-nav` - Tab order matches visual order; full keyboard support (Apple HIG)
74
+ - `form-labels` - Use label with for attribute
75
+ - `skip-links` - Skip to main content for keyboard users
76
+ - `heading-hierarchy` - Sequential h1β†’h6, no level skip
77
+ - `color-not-only` - Don't convey info by color alone (add icon/text)
78
+ - `dynamic-type` - Support system text scaling; avoid truncation as text grows (Apple Dynamic Type, MD)
79
+ - `reduced-motion` - Respect prefers-reduced-motion; reduce/disable animations when requested (Apple Reduced Motion API, MD)
80
+ - `voiceover-sr` - Meaningful accessibilityLabel/accessibilityHint; logical reading order for VoiceOver/screen readers (Apple HIG, MD)
81
+ - `escape-routes` - Provide cancel/back in modals and multi-step flows (Apple HIG)
82
+ - `keyboard-shortcuts` - Preserve system and a11y shortcuts; offer keyboard alternatives for drag-and-drop (Apple HIG)
83
+
84
+ ### 2. Touch & Interaction (CRITICAL)
85
+
86
+ - `touch-target-size` - Min 44Γ—44pt (Apple) / 48Γ—48dp (Material); extend hit area beyond visual bounds if needed
87
+ - `touch-spacing` - Minimum 8px/8dp gap between touch targets (Apple HIG, MD)
88
+ - `hover-vs-tap` - Use click/tap for primary interactions; don't rely on hover alone
89
+ - `loading-buttons` - Disable button during async operations; show spinner or progress
90
+ - `error-feedback` - Clear error messages near problem
91
+ - `cursor-pointer` - Add cursor-pointer to clickable elements (Web)
92
+ - `gesture-conflicts` - Avoid horizontal swipe on main content; prefer vertical scroll
93
+ - `tap-delay` - Use touch-action: manipulation to reduce 300ms delay (Web)
94
+ - `standard-gestures` - Use platform standard gestures consistently; don't redefine (e.g. swipe-back, pinch-zoom) (Apple HIG)
95
+ - `system-gestures` - Don't block system gestures (Control Center, back swipe, etc.) (Apple HIG)
96
+ - `press-feedback` - Visual feedback on press (ripple/highlight; MD state layers)
97
+ - `haptic-feedback` - Use haptic for confirmations and important actions; avoid overuse (Apple HIG)
98
+ - `gesture-alternative` - Don't rely on gesture-only interactions; always provide visible controls for critical actions
99
+ - `safe-area-awareness` - Keep primary touch targets away from notch, Dynamic Island, gesture bar and screen edges
100
+ - `no-precision-required` - Avoid requiring pixel-perfect taps on small icons or thin edges
101
+ - `swipe-clarity` - Swipe actions must show clear affordance or hint (chevron, label, tutorial)
102
+ - `drag-threshold` - Use a movement threshold before starting drag to avoid accidental drags
103
+
104
+ ### 3. Performance (HIGH)
105
+
106
+ - `image-optimization` - Use WebP/AVIF, responsive images (srcset/sizes), lazy load non-critical assets
107
+ - `image-dimension` - Declare width/height or use aspect-ratio to prevent layout shift (Core Web Vitals: CLS)
108
+ - `font-loading` - Use font-display: swap/optional to avoid invisible text (FOIT); reserve space to reduce layout shift (MD)
109
+ - `font-preload` - Preload only critical fonts; avoid overusing preload on every variant
110
+ - `critical-css` - Prioritize above-the-fold CSS (inline critical CSS or early-loaded stylesheet)
111
+ - `lazy-loading` - Lazy load non-hero components via dynamic import / route-level splitting
112
+ - `bundle-splitting` - Split code by route/feature (React Suspense / Next.js dynamic) to reduce initial load and TTI
113
+ - `third-party-scripts` - Load third-party scripts async/defer; audit and remove unnecessary ones (MD)
114
+ - `reduce-reflows` - Avoid frequent layout reads/writes; batch DOM reads then writes
115
+ - `content-jumping` - Reserve space for async content to avoid layout jumps (Core Web Vitals: CLS)
116
+ - `lazy-load-below-fold` - Use loading="lazy" for below-the-fold images and heavy media
117
+ - `virtualize-lists` - Virtualize lists with 50+ items to improve memory efficiency and scroll performance
118
+ - `main-thread-budget` - Keep per-frame work under ~16ms for 60fps; move heavy tasks off main thread (HIG, MD)
119
+ - `progressive-loading` - Use skeleton screens / shimmer instead of long blocking spinners for >1s operations (Apple HIG)
120
+ - `input-latency` - Keep input latency under ~100ms for taps/scrolls (Material responsiveness standard)
121
+ - `tap-feedback-speed` - Provide visual feedback within 100ms of tap (Apple HIG)
122
+ - `debounce-throttle` - Use debounce/throttle for high-frequency events (scroll, resize, input)
123
+ - `offline-support` - Provide offline state messaging and basic fallback (PWA / mobile)
124
+ - `network-fallback` - Offer degraded modes for slow networks (lower-res images, fewer animations)
125
+
126
+ ### 4. Style Selection (HIGH)
127
+
128
+ - `style-match` - Match style to product type (use `--design-system` for recommendations)
129
+ - `consistency` - Use same style across all pages
130
+ - `no-emoji-icons` - Use SVG icons (Heroicons, Lucide), not emojis
131
+ - `color-palette-from-product` - Choose palette from product/industry (search `--domain color`)
132
+ - `effects-match-style` - Shadows, blur, radius aligned with chosen style (glass / flat / clay etc.)
133
+ - `platform-adaptive` - Respect platform idioms (iOS HIG vs Material): navigation, controls, typography, motion
134
+ - `state-clarity` - Make hover/pressed/disabled states visually distinct while staying on-style (Material state layers)
135
+ - `elevation-consistent` - Use a consistent elevation/shadow scale for cards, sheets, modals; avoid random shadow values
136
+ - `dark-mode-pairing` - Design light/dark variants together to keep brand, contrast, and style consistent
137
+ - `icon-style-consistent` - Use one icon set/visual language (stroke width, corner radius) across the product
138
+ - `system-controls` - Prefer native/system controls over fully custom ones; only customize when branding requires it (Apple HIG)
139
+ - `blur-purpose` - Use blur to indicate background dismissal (modals, sheets), not as decoration (Apple HIG)
140
+ - `primary-action` - Each screen should have only one primary CTA; secondary actions visually subordinate (Apple HIG)
141
+
142
+ ### 5. Layout & Responsive (HIGH)
143
+
144
+ - `viewport-meta` - width=device-width initial-scale=1 (never disable zoom)
145
+ - `mobile-first` - Design mobile-first, then scale up to tablet and desktop
146
+ - `breakpoint-consistency` - Use systematic breakpoints (e.g. 375 / 768 / 1024 / 1440)
147
+ - `readable-font-size` - Minimum 16px body text on mobile (avoids iOS auto-zoom)
148
+ - `line-length-control` - Mobile 35–60 chars per line; desktop 60–75 chars
149
+ - `horizontal-scroll` - No horizontal scroll on mobile; ensure content fits viewport width
150
+ - `spacing-scale` - Use 4pt/8dp incremental spacing system (Material Design)
151
+ - `touch-density` - Keep component spacing comfortable for touch: not cramped, not causing mis-taps
152
+ - `container-width` - Consistent max-width on desktop (max-w-6xl / 7xl)
153
+ - `z-index-management` - Define layered z-index scale (e.g. 0 / 10 / 20 / 40 / 100 / 1000)
154
+ - `fixed-element-offset` - Fixed navbar/bottom bar must reserve safe padding for underlying content
155
+ - `scroll-behavior` - Avoid nested scroll regions that interfere with the main scroll experience
156
+ - `viewport-units` - Prefer min-h-dvh over 100vh on mobile
157
+ - `orientation-support` - Keep layout readable and operable in landscape mode
158
+ - `content-priority` - Show core content first on mobile; fold or hide secondary content
159
+ - `visual-hierarchy` - Establish hierarchy via size, spacing, contrast β€” not color alone
160
+
161
+ ### 6. Typography & Color (MEDIUM)
162
+
163
+ - `line-height` - Use 1.5-1.75 for body text
164
+ - `line-length` - Limit to 65-75 characters per line
165
+ - `font-pairing` - Match heading/body font personalities
166
+ - `font-scale` - Consistent type scale (e.g. 12 14 16 18 24 32)
167
+ - `contrast-readability` - Darker text on light backgrounds (e.g. slate-900 on white)
168
+ - `text-styles-system` - Use platform type system: iOS 11 Dynamic Type styles / Material 5 type roles (display, headline, title, body, label) (HIG, MD)
169
+ - `weight-hierarchy` - Use font-weight to reinforce hierarchy: Bold headings (600–700), Regular body (400), Medium labels (500) (MD)
170
+ - `color-semantic` - Define semantic color tokens (primary, secondary, error, surface, on-surface) not raw hex in components (Material color system)
171
+ - `color-dark-mode` - Dark mode uses desaturated / lighter tonal variants, not inverted colors; test contrast separately (HIG, MD)
172
+ - `color-accessible-pairs` - Foreground/background pairs must meet 4.5:1 (AA) or 7:1 (AAA); use tools to verify (WCAG, MD)
173
+ - `color-not-decorative-only` - Functional color (error red, success green) must include icon/text; avoid color-only meaning (HIG, MD)
174
+ - `truncation-strategy` - Prefer wrapping over truncation; when truncating use ellipsis and provide full text via tooltip/expand (Apple HIG)
175
+ - `letter-spacing` - Respect default letter-spacing per platform; avoid tight tracking on body text (HIG, MD)
176
+ - `number-tabular` - Use tabular/monospaced figures for data columns, prices, and timers to prevent layout shift
177
+ - `whitespace-balance` - Use whitespace intentionally to group related items and separate sections; avoid visual clutter (Apple HIG)
178
+
179
+ ### 7. Animation (MEDIUM)
180
+
181
+ - `duration-timing` - Use 150–300ms for micro-interactions; complex transitions ≀400ms; avoid >500ms (MD)
182
+ - `transform-performance` - Use transform/opacity only; avoid animating width/height/top/left
183
+ - `loading-states` - Show skeleton or progress indicator when loading exceeds 300ms
184
+ - `excessive-motion` - Animate 1-2 key elements per view max
185
+ - `easing` - Use ease-out for entering, ease-in for exiting; avoid linear for UI transitions
186
+ - `motion-meaning` - Every animation must express a cause-effect relationship, not just be decorative (Apple HIG)
187
+ - `state-transition` - State changes (hover / active / expanded / collapsed / modal) should animate smoothly, not snap
188
+ - `continuity` - Page/screen transitions should maintain spatial continuity (shared element, directional slide) (Apple HIG)
189
+ - `parallax-subtle` - Use parallax sparingly; must respect reduced-motion and not cause disorientation (Apple HIG)
190
+ - `spring-physics` - Prefer spring/physics-based curves over linear or cubic-bezier for natural feel (Apple HIG fluid animations)
191
+ - `exit-faster-than-enter` - Exit animations shorter than enter (~60–70% of enter duration) to feel responsive (MD motion)
192
+ - `stagger-sequence` - Stagger list/grid item entrance by 30–50ms per item; avoid all-at-once or too-slow reveals (MD)
193
+ - `shared-element-transition` - Use shared element / hero transitions for visual continuity between screens (MD, HIG)
194
+ - `interruptible` - Animations must be interruptible; user tap/gesture cancels in-progress animation immediately (Apple HIG)
195
+ - `no-blocking-animation` - Never block user input during an animation; UI must stay interactive (Apple HIG)
196
+ - `fade-crossfade` - Use crossfade for content replacement within the same container (MD)
197
+ - `scale-feedback` - Subtle scale (0.95–1.05) on press for tappable cards/buttons; restore on release (HIG, MD)
198
+ - `gesture-feedback` - Drag, swipe, and pinch must provide real-time visual response tracking the finger (MD Motion)
199
+ - `hierarchy-motion` - Use translate/scale direction to express hierarchy: enter from below = deeper, exit upward = back (MD)
200
+ - `motion-consistency` - Unify duration/easing tokens globally; all animations share the same rhythm and feel
201
+ - `opacity-threshold` - Fading elements should not linger below opacity 0.2; either fade fully or remain visible
202
+ - `modal-motion` - Modals/sheets should animate from their trigger source (scale+fade or slide-in) for spatial context (HIG, MD)
203
+ - `navigation-direction` - Forward navigation animates left/up; backward animates right/down β€” keep direction logically consistent (HIG)
204
+ - `layout-shift-avoid` - Animations must not cause layout reflow or CLS; use transform for position changes
205
+
206
+ ### 8. Forms & Feedback (MEDIUM)
207
+
208
+ - `input-labels` - Visible label per input (not placeholder-only)
209
+ - `error-placement` - Show error below the related field
210
+ - `submit-feedback` - Loading then success/error state on submit
211
+ - `required-indicators` - Mark required fields (e.g. asterisk)
212
+ - `empty-states` - Helpful message and action when no content
213
+ - `toast-dismiss` - Auto-dismiss toasts in 3-5s
214
+ - `confirmation-dialogs` - Confirm before destructive actions
215
+ - `input-helper-text` - Provide persistent helper text below complex inputs, not just placeholder (Material Design)
216
+ - `disabled-states` - Disabled elements use reduced opacity (0.38–0.5) + cursor change + semantic attribute (MD)
217
+ - `progressive-disclosure` - Reveal complex options progressively; don't overwhelm users upfront (Apple HIG)
218
+ - `inline-validation` - Validate on blur (not keystroke); show error only after user finishes input (MD)
219
+ - `input-type-keyboard` - Use semantic input types (email, tel, number) to trigger the correct mobile keyboard (HIG, MD)
220
+ - `password-toggle` - Provide show/hide toggle for password fields (MD)
221
+ - `autofill-support` - Use autocomplete / textContentType attributes so the system can autofill (HIG, MD)
222
+ - `undo-support` - Allow undo for destructive or bulk actions (e.g. "Undo delete" toast) (Apple HIG)
223
+ - `success-feedback` - Confirm completed actions with brief visual feedback (checkmark, toast, color flash) (MD)
224
+ - `error-recovery` - Error messages must include a clear recovery path (retry, edit, help link) (HIG, MD)
225
+ - `multi-step-progress` - Multi-step flows show step indicator or progress bar; allow back navigation (MD)
226
+ - `form-autosave` - Long forms should auto-save drafts to prevent data loss on accidental dismissal (Apple HIG)
227
+ - `sheet-dismiss-confirm` - Confirm before dismissing a sheet/modal with unsaved changes (Apple HIG)
228
+ - `error-clarity` - Error messages must state cause + how to fix (not just "Invalid input") (HIG, MD)
229
+ - `field-grouping` - Group related fields logically (fieldset/legend or visual grouping) (MD)
230
+ - `read-only-distinction` - Read-only state should be visually and semantically different from disabled (MD)
231
+ - `focus-management` - After submit error, auto-focus the first invalid field (WCAG, MD)
232
+ - `error-summary` - For multiple errors, show summary at top with anchor links to each field (WCAG)
233
+ - `touch-friendly-input` - Mobile input height β‰₯44px to meet touch target requirements (Apple HIG)
234
+ - `destructive-emphasis` - Destructive actions use semantic danger color (red) and are visually separated from primary actions (HIG, MD)
235
+ - `toast-accessibility` - Toasts must not steal focus; use aria-live="polite" for screen reader announcement (WCAG)
236
+ - `aria-live-errors` - Form errors use aria-live region or role="alert" to notify screen readers (WCAG)
237
+ - `contrast-feedback` - Error and success state colors must meet 4.5:1 contrast ratio (WCAG, MD)
238
+ - `timeout-feedback` - Request timeout must show clear feedback with retry option (MD)
239
+
240
+ ### 9. Navigation Patterns (HIGH)
241
+
242
+ - `bottom-nav-limit` - Bottom navigation max 5 items; use labels with icons (Material Design)
243
+ - `drawer-usage` - Use drawer/sidebar for secondary navigation, not primary actions (Material Design)
244
+ - `back-behavior` - Back navigation must be predictable and consistent; preserve scroll/state (Apple HIG, MD)
245
+ - `deep-linking` - All key screens must be reachable via deep link / URL for sharing and notifications (Apple HIG, MD)
246
+ - `tab-bar-ios` - iOS: use bottom Tab Bar for top-level navigation (Apple HIG)
247
+ - `top-app-bar-android` - Android: use Top App Bar with navigation icon for primary structure (Material Design)
248
+ - `nav-label-icon` - Navigation items must have both icon and text label; icon-only nav harms discoverability (MD)
249
+ - `nav-state-active` - Current location must be visually highlighted (color, weight, indicator) in navigation (HIG, MD)
250
+ - `nav-hierarchy` - Primary nav (tabs/bottom bar) vs secondary nav (drawer/settings) must be clearly separated (MD)
251
+ - `modal-escape` - Modals and sheets must offer a clear close/dismiss affordance; swipe-down to dismiss on mobile (Apple HIG)
252
+ - `search-accessible` - Search must be easily reachable (top bar or tab); provide recent/suggested queries (MD)
253
+ - `breadcrumb-web` - Web: use breadcrumbs for 3+ level deep hierarchies to aid orientation (MD)
254
+ - `state-preservation` - Navigating back must restore previous scroll position, filter state, and input (HIG, MD)
255
+ - `gesture-nav-support` - Support system gesture navigation (iOS swipe-back, Android predictive back) without conflict (HIG, MD)
256
+ - `tab-badge` - Use badges on nav items sparingly to indicate unread/pending; clear after user visits (HIG, MD)
257
+ - `overflow-menu` - When actions exceed available space, use overflow/more menu instead of cramming (MD)
258
+ - `bottom-nav-top-level` - Bottom nav is for top-level screens only; never nest sub-navigation inside it (MD)
259
+ - `adaptive-navigation` - Large screens (β‰₯1024px) prefer sidebar; small screens use bottom/top nav (Material Adaptive)
260
+ - `back-stack-integrity` - Never silently reset the navigation stack or unexpectedly jump to home (HIG, MD)
261
+ - `navigation-consistency` - Navigation placement must stay the same across all pages; don't change by page type
262
+ - `avoid-mixed-patterns` - Don't mix Tab + Sidebar + Bottom Nav at the same hierarchy level
263
+ - `modal-vs-navigation` - Modals must not be used for primary navigation flows; they break the user's path (HIG)
264
+ - `focus-on-route-change` - After page transition, move focus to main content region for screen reader users (WCAG)
265
+ - `persistent-nav` - Core navigation must remain reachable from deep pages; don't hide it entirely in sub-flows (HIG, MD)
266
+ - `destructive-nav-separation` - Dangerous actions (delete account, logout) must be visually and spatially separated from normal nav items (HIG, MD)
267
+ - `empty-nav-state` - When a nav destination is unavailable, explain why instead of silently hiding it (MD)
268
+
269
+ ### 10. Charts & Data (LOW)
270
+
271
+ - `chart-type` - Match chart type to data type (trend β†’ line, comparison β†’ bar, proportion β†’ pie/donut)
272
+ - `color-guidance` - Use accessible color palettes; avoid red/green only pairs for colorblind users (WCAG, MD)
273
+ - `data-table` - Provide table alternative for accessibility; charts alone are not screen-reader friendly (WCAG)
274
+ - `pattern-texture` - Supplement color with patterns, textures, or shapes so data is distinguishable without color (WCAG, MD)
275
+ - `legend-visible` - Always show legend; position near the chart, not detached below a scroll fold (MD)
276
+ - `tooltip-on-interact` - Provide tooltips/data labels on hover (Web) or tap (mobile) showing exact values (HIG, MD)
277
+ - `axis-labels` - Label axes with units and readable scale; avoid truncated or rotated labels on mobile
278
+ - `responsive-chart` - Charts must reflow or simplify on small screens (e.g. horizontal bar instead of vertical, fewer ticks)
279
+ - `empty-data-state` - Show meaningful empty state when no data exists ("No data yet" + guidance), not a blank chart (MD)
280
+ - `loading-chart` - Use skeleton or shimmer placeholder while chart data loads; don't show an empty axis frame
281
+ - `animation-optional` - Chart entrance animations must respect prefers-reduced-motion; data should be readable immediately (HIG)
282
+ - `large-dataset` - For 1000+ data points, aggregate or sample; provide drill-down for detail instead of rendering all (MD)
283
+ - `number-formatting` - Use locale-aware formatting for numbers, dates, currencies on axes and labels (HIG, MD)
284
+ - `touch-target-chart` - Interactive chart elements (points, segments) must have β‰₯44pt tap area or expand on touch (Apple HIG)
285
+ - `no-pie-overuse` - Avoid pie/donut for >5 categories; switch to bar chart for clarity
286
+ - `contrast-data` - Data lines/bars vs background β‰₯3:1; data text labels β‰₯4.5:1 (WCAG)
287
+ - `legend-interactive` - Legends should be clickable to toggle series visibility (MD)
288
+ - `direct-labeling` - For small datasets, label values directly on the chart to reduce eye travel
289
+ - `tooltip-keyboard` - Tooltip content must be keyboard-reachable and not rely on hover alone (WCAG)
290
+ - `sortable-table` - Data tables must support sorting with aria-sort indicating current sort state (WCAG)
291
+ - `axis-readability` - Axis ticks must not be cramped; maintain readable spacing, auto-skip on small screens
292
+ - `data-density` - Limit information density per chart to avoid cognitive overload; split into multiple charts if needed
293
+ - `trend-emphasis` - Emphasize data trends over decoration; avoid heavy gradients/shadows that obscure the data
294
+ - `gridline-subtle` - Grid lines should be low-contrast (e.g. gray-200) so they don't compete with data
295
+ - `focusable-elements` - Interactive chart elements (points, bars, slices) must be keyboard-navigable (WCAG)
296
+ - `screen-reader-summary` - Provide a text summary or aria-label describing the chart's key insight for screen readers (WCAG)
297
+ - `error-state-chart` - Data load failure must show error message with retry action, not a broken/empty chart
298
+ - `export-option` - For data-heavy products, offer CSV/image export of chart data
299
+ - `drill-down-consistency` - Drill-down interactions must maintain a clear back-path and hierarchy breadcrumb
300
+ - `time-scale-clarity` - Time series charts must clearly label time granularity (day/week/month) and allow switching
301
+
302
+ ## How to Use
303
+
304
+ Search specific domains using the CLI tool below.
305
+
306
+ ---
307
+
308
+ ## Prerequisites
309
+
310
+ Check if Python is installed:
311
+
312
+ ```bash
313
+ python3 --version || python --version
314
+ ```
315
+
316
+ If Python is not installed, install it based on user's OS:
317
+
318
+ **macOS:**
319
+ ```bash
320
+ brew install python3
321
+ ```
322
+
323
+ **Ubuntu/Debian:**
324
+ ```bash
325
+ sudo apt update && sudo apt install python3
326
+ ```
327
+
328
+ **Windows:**
329
+ ```powershell
330
+ winget install Python.Python.3.12
331
+ ```
332
+
333
+ ---
334
+
335
+ ## How to Use This Skill
336
+
337
+ Use this skill when the user requests any of the following:
338
+
339
+ | Scenario | Trigger Examples | Start From |
340
+ |----------|-----------------|------------|
341
+ | **New project / page** | "Build a landing page", "Build a dashboard" | Step 1 β†’ Step 2 (design system) |
342
+ | **New component** | "Create a pricing card", "Add a modal" | Step 3 (domain search: style, ux) |
343
+ | **Choose style / color / font** | "What style fits a fintech app?", "Recommend a color palette" | Step 2 (design system) |
344
+ | **Review existing UI** | "Review this page for UX issues", "Check accessibility" | Quick Reference checklist above |
345
+ | **Fix a UI bug** | "Button hover is broken", "Layout shifts on load" | Quick Reference β†’ relevant section |
346
+ | **Improve / optimize** | "Make this faster", "Improve mobile experience" | Step 3 (domain search: ux, react) |
347
+ | **Implement dark mode** | "Add dark mode support" | Step 3 (domain: style "dark mode") |
348
+ | **Add charts / data viz** | "Add an analytics dashboard chart" | Step 3 (domain: chart) |
349
+ | **Stack best practices** | "React performance tips"、"SwiftUI navigation" | Step 4 (stack search) |
350
+
351
+ Follow this workflow:
352
+
353
+ ### Step 1: Analyze User Requirements
354
+
355
+ Extract key information from user request:
356
+ - **Product type**: Entertainment (social, video, music, gaming), Tool (scanner, editor, converter), Productivity (task manager, notes, calendar), or hybrid
357
+ - **Target audience**: C-end consumer users; consider age group, usage context (commute, leisure, work)
358
+ - **Style keywords**: playful, vibrant, minimal, dark mode, content-first, immersive, etc.
359
+ - **Stack**: React Native (this project's only tech stack)
360
+
361
+ ### Step 2: Generate Design System (REQUIRED)
362
+
363
+ **Always start with `--design-system`** to get comprehensive recommendations with reasoning:
364
+
365
+ ```bash
366
+ python3 skills/ui-ux-pro-max/scripts/search.py "<product_type> <industry> <keywords>" --design-system [-p "Project Name"]
367
+ ```
368
+
369
+ This command:
370
+ 1. Searches domains in parallel (product, style, color, landing, typography)
371
+ 2. Applies reasoning rules from `ui-reasoning.csv` to select best matches
372
+ 3. Returns complete design system: pattern, style, colors, typography, effects
373
+ 4. Includes anti-patterns to avoid
374
+
375
+ **Example:**
376
+ ```bash
377
+ python3 skills/ui-ux-pro-max/scripts/search.py "beauty spa wellness service" --design-system -p "Serenity Spa"
378
+ ```
379
+
380
+ ### Step 2b: Persist Design System (Master + Overrides Pattern)
381
+
382
+ To save the design system for **hierarchical retrieval across sessions**, add `--persist`:
383
+
384
+ ```bash
385
+ python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name"
386
+ ```
387
+
388
+ This creates:
389
+ - `design-system/MASTER.md` β€” Global Source of Truth with all design rules
390
+ - `design-system/pages/` β€” Folder for page-specific overrides
391
+
392
+ **With page-specific override:**
393
+ ```bash
394
+ python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name" --page "dashboard"
395
+ ```
396
+
397
+ This also creates:
398
+ - `design-system/pages/dashboard.md` β€” Page-specific deviations from Master
399
+
400
+ **How hierarchical retrieval works:**
401
+ 1. When building a specific page (e.g., "Checkout"), first check `design-system/pages/checkout.md`
402
+ 2. If the page file exists, its rules **override** the Master file
403
+ 3. If not, use `design-system/MASTER.md` exclusively
404
+
405
+ **Context-aware retrieval prompt:**
406
+ ```
407
+ I am building the [Page Name] page. Please read design-system/MASTER.md.
408
+ Also check if design-system/pages/[page-name].md exists.
409
+ If the page file exists, prioritize its rules.
410
+ If not, use the Master rules exclusively.
411
+ Now, generate the code...
412
+ ```
413
+
414
+ ### Step 3: Supplement with Detailed Searches (as needed)
415
+
416
+ After getting the design system, use domain searches to get additional details:
417
+
418
+ ```bash
419
+ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --domain <domain> [-n <max_results>]
420
+ ```
421
+
422
+ **When to use detailed searches:**
423
+
424
+ | Need | Domain | Example |
425
+ |------|--------|---------|
426
+ | Product type patterns | `product` | `--domain product "entertainment social"` |
427
+ | More style options | `style` | `--domain style "glassmorphism dark"` |
428
+ | Color palettes | `color` | `--domain color "entertainment vibrant"` |
429
+ | Font pairings | `typography` | `--domain typography "playful modern"` |
430
+ | Chart recommendations | `chart` | `--domain chart "real-time dashboard"` |
431
+ | UX best practices | `ux` | `--domain ux "animation accessibility"` |
432
+ | Alternative fonts | `typography` | `--domain typography "elegant luxury"` |
433
+ | Individual Google Fonts | `google-fonts` | `--domain google-fonts "sans serif popular variable"` |
434
+ | Landing structure | `landing` | `--domain landing "hero social-proof"` |
435
+ | React Native perf | `react` | `--domain react "rerender memo list"` |
436
+ | App interface a11y | `web` | `--domain web "accessibilityLabel touch safe-areas"` |
437
+ | AI prompt / CSS keywords | `prompt` | `--domain prompt "minimalism"` |
438
+
439
+ ### Step 4: Stack Guidelines (React Native)
440
+
441
+ Get React Native implementation-specific best practices:
442
+
443
+ ```bash
444
+ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
445
+ ```
446
+
447
+ ---
448
+
449
+ ## Search Reference
450
+
451
+ ### Available Domains
452
+
453
+ | Domain | Use For | Example Keywords |
454
+ |--------|---------|------------------|
455
+ | `product` | Product type recommendations | SaaS, e-commerce, portfolio, healthcare, beauty, service |
456
+ | `style` | UI styles, colors, effects | glassmorphism, minimalism, dark mode, brutalism |
457
+ | `typography` | Font pairings, Google Fonts | elegant, playful, professional, modern |
458
+ | `color` | Color palettes by product type | saas, ecommerce, healthcare, beauty, fintech, service |
459
+ | `landing` | Page structure, CTA strategies | hero, hero-centric, testimonial, pricing, social-proof |
460
+ | `chart` | Chart types, library recommendations | trend, comparison, timeline, funnel, pie |
461
+ | `ux` | Best practices, anti-patterns | animation, accessibility, z-index, loading |
462
+ | `google-fonts` | Individual Google Fonts lookup | sans serif, monospace, japanese, variable font, popular |
463
+ | `react` | React/Next.js performance | waterfall, bundle, suspense, memo, rerender, cache |
464
+ | `web` | App interface guidelines (iOS/Android/React Native) | accessibilityLabel, touch targets, safe areas, Dynamic Type |
465
+ | `prompt` | AI prompts, CSS keywords | (style name) |
466
+
467
+ ### Available Stacks
468
+
469
+ | Stack | Focus |
470
+ |-------|-------|
471
+ | `react-native` | Components, Navigation, Lists |
472
+
473
+ ---
474
+
475
+ ## Example Workflow
476
+
477
+ **User request:** "Make an AI search homepage."
478
+
479
+ ### Step 1: Analyze Requirements
480
+ - Product type: Tool (AI search engine)
481
+ - Target audience: C-end users looking for fast, intelligent search
482
+ - Style keywords: modern, minimal, content-first, dark mode
483
+ - Stack: React Native
484
+
485
+ ### Step 2: Generate Design System (REQUIRED)
486
+
487
+ ```bash
488
+ python3 skills/ui-ux-pro-max/scripts/search.py "AI search tool modern minimal" --design-system -p "AI Search"
489
+ ```
490
+
491
+ **Output:** Complete design system with pattern, style, colors, typography, effects, and anti-patterns.
492
+
493
+ ### Step 3: Supplement with Detailed Searches (as needed)
494
+
495
+ ```bash
496
+ # Get style options for a modern tool product
497
+ python3 skills/ui-ux-pro-max/scripts/search.py "minimalism dark mode" --domain style
498
+
499
+ # Get UX best practices for search interaction and loading
500
+ python3 skills/ui-ux-pro-max/scripts/search.py "search loading animation" --domain ux
501
+ ```
502
+
503
+ ### Step 4: Stack Guidelines
504
+
505
+ ```bash
506
+ python3 skills/ui-ux-pro-max/scripts/search.py "list performance navigation" --stack react-native
507
+ ```
508
+
509
+ **Then:** Synthesize design system + detailed searches and implement the design.
510
+
511
+ ---
512
+
513
+ ## Output Formats
514
+
515
+ The `--design-system` flag supports two output formats:
516
+
517
+ ```bash
518
+ # ASCII box (default) - best for terminal display
519
+ python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system
520
+
521
+ # Markdown - best for documentation
522
+ python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system -f markdown
523
+ ```
524
+
525
+ ---
526
+
527
+ ## Tips for Better Results
528
+
529
+ ### Query Strategy
530
+
531
+ - Use **multi-dimensional keywords** β€” combine product + industry + tone + density: `"entertainment social vibrant content-dense"` not just `"app"`
532
+ - Try different keywords for the same need: `"playful neon"` β†’ `"vibrant dark"` β†’ `"content-first minimal"`
533
+ - Use `--design-system` first for full recommendations, then `--domain` to deep-dive any dimension you're unsure about
534
+ - Always add `--stack react-native` for implementation-specific guidance
535
+
536
+ ### Common Sticking Points
537
+
538
+ | Problem | What to Do |
539
+ |---------|------------|
540
+ | Can't decide on style/color | Re-run `--design-system` with different keywords |
541
+ | Dark mode contrast issues | Quick Reference Β§6: `color-dark-mode` + `color-accessible-pairs` |
542
+ | Animations feel unnatural | Quick Reference Β§7: `spring-physics` + `easing` + `exit-faster-than-enter` |
543
+ | Form UX is poor | Quick Reference Β§8: `inline-validation` + `error-clarity` + `focus-management` |
544
+ | Navigation feels confusing | Quick Reference Β§9: `nav-hierarchy` + `bottom-nav-limit` + `back-behavior` |
545
+ | Layout breaks on small screens | Quick Reference Β§5: `mobile-first` + `breakpoint-consistency` |
546
+ | Performance / jank | Quick Reference Β§3: `virtualize-lists` + `main-thread-budget` + `debounce-throttle` |
547
+
548
+ ### Pre-Delivery Checklist
549
+
550
+ - Run `--domain ux "animation accessibility z-index loading"` as a UX validation pass before implementation
551
+ - Run through Quick Reference **Β§1–§3** (CRITICAL + HIGH) as a final review
552
+ - Test on 375px (small phone) and landscape orientation
553
+ - Verify behavior with **reduced-motion** enabled and **Dynamic Type** at largest size
554
+ - Check dark mode contrast independently (don't assume light mode values work)
555
+ - Confirm all touch targets β‰₯44pt and no content hidden behind safe areas
556
+
557
+ ---
558
+
559
+ ## Common Rules for Professional UI
560
+
561
+ These are frequently overlooked issues that make UI look unprofessional:
562
+ Scope notice: The rules below are for App UI (iOS/Android/React Native/Flutter), not desktop-web interaction patterns.
563
+
564
+ ### Icons & Visual Elements
565
+
566
+ | Rule | Standard | Avoid | Why It Matters |
567
+ |------|----------|--------|----------------|
568
+ | **No Emoji as Structural Icons** | Use vector-based icons (e.g., Lucide, react-native-vector-icons, @expo/vector-icons). | Using emojis (🎨 πŸš€ βš™οΈ) for navigation, settings, or system controls. | Emojis are font-dependent, inconsistent across platforms, and cannot be controlled via design tokens. |
569
+ | **Vector-Only Assets** | Use SVG or platform vector icons that scale cleanly and support theming. | Raster PNG icons that blur or pixelate. | Ensures scalability, crisp rendering, and dark/light mode adaptability. |
570
+ | **Stable Interaction States** | Use color, opacity, or elevation transitions for press states without changing layout bounds. | Layout-shifting transforms that move surrounding content or trigger visual jitter. | Prevents unstable interactions and preserves smooth motion/perceived quality on mobile. |
571
+ | **Correct Brand Logos** | Use official brand assets and follow their usage guidelines (spacing, color, clear space). | Guessing logo paths, recoloring unofficially, or modifying proportions. | Prevents brand misuse and ensures legal/platform compliance. |
572
+ | **Consistent Icon Sizing** | Define icon sizes as design tokens (e.g., icon-sm, icon-md = 24pt, icon-lg). | Mixing arbitrary values like 20pt / 24pt / 28pt randomly. | Maintains rhythm and visual hierarchy across the interface. |
573
+ | **Stroke Consistency** | Use a consistent stroke width within the same visual layer (e.g., 1.5px or 2px). | Mixing thick and thin stroke styles arbitrarily. | Inconsistent strokes reduce perceived polish and cohesion. |
574
+ | **Filled vs Outline Discipline** | Use one icon style per hierarchy level. | Mixing filled and outline icons at the same hierarchy level. | Maintains semantic clarity and stylistic coherence. |
575
+ | **Touch Target Minimum** | Minimum 44Γ—44pt interactive area (use hitSlop if icon is smaller). | Small icons without expanded tap area. | Meets accessibility and platform usability standards. |
576
+ | **Icon Alignment** | Align icons to text baseline and maintain consistent padding. | Misaligned icons or inconsistent spacing around them. | Prevents subtle visual imbalance that reduces perceived quality. |
577
+ | **Icon Contrast** | Follow WCAG contrast standards: 4.5:1 for small elements, 3:1 minimum for larger UI glyphs. | Low-contrast icons that blend into the background. | Ensures accessibility in both light and dark modes. |
578
+
579
+
580
+ ### Interaction (App)
581
+
582
+ | Rule | Do | Don't |
583
+ |------|----|----- |
584
+ | **Tap feedback** | Provide clear pressed feedback (ripple/opacity/elevation) within 80-150ms | No visual response on tap |
585
+ | **Animation timing** | Keep micro-interactions around 150-300ms with platform-native easing | Instant transitions or slow animations (>500ms) |
586
+ | **Accessibility focus** | Ensure screen reader focus order matches visual order and labels are descriptive | Unlabeled controls or confusing focus traversal |
587
+ | **Disabled state clarity** | Use disabled semantics (`disabled`/native disabled props), reduced emphasis, and no tap action | Controls that look tappable but do nothing |
588
+ | **Touch target minimum** | Keep tap areas >=44x44pt (iOS) or >=48x48dp (Android), expand hit area when icon is smaller | Tiny tap targets or icon-only hit areas without padding |
589
+ | **Gesture conflict prevention** | Keep one primary gesture per region and avoid nested tap/drag conflicts | Overlapping gestures causing accidental actions |
590
+ | **Semantic native controls** | Prefer native interactive primitives (`Button`, `Pressable`, platform equivalents) with proper accessibility roles | Generic containers used as primary controls without semantics |
591
+
592
+ ### Light/Dark Mode Contrast
593
+
594
+ | Rule | Do | Don't |
595
+ |------|----|----- |
596
+ | **Surface readability (light)** | Keep cards/surfaces clearly separated from background with sufficient opacity/elevation | Overly transparent surfaces that blur hierarchy |
597
+ | **Text contrast (light)** | Maintain body text contrast >=4.5:1 against light surfaces | Low-contrast gray body text |
598
+ | **Text contrast (dark)** | Maintain primary text contrast >=4.5:1 and secondary text >=3:1 on dark surfaces | Dark mode text that blends into background |
599
+ | **Border and divider visibility** | Ensure separators are visible in both themes (not just light mode) | Theme-specific borders disappearing in one mode |
600
+ | **State contrast parity** | Keep pressed/focused/disabled states equally distinguishable in light and dark themes | Defining interaction states for one theme only |
601
+ | **Token-driven theming** | Use semantic color tokens mapped per theme across app surfaces/text/icons | Hardcoded per-screen hex values |
602
+ | **Scrim and modal legibility** | Use a modal scrim strong enough to isolate foreground content (typically 40-60% black) | Weak scrim that leaves background visually competing |
603
+
604
+ ### Layout & Spacing
605
+
606
+ | Rule | Do | Don't |
607
+ |------|----|----- |
608
+ | **Safe-area compliance** | Respect top/bottom safe areas for all fixed headers, tab bars, and CTA bars | Placing fixed UI under notch, status bar, or gesture area |
609
+ | **System bar clearance** | Add spacing for status/navigation bars and gesture home indicator | Let tappable content collide with OS chrome |
610
+ | **Consistent content width** | Keep predictable content width per device class (phone/tablet) | Mixing arbitrary widths between screens |
611
+ | **8dp spacing rhythm** | Use a consistent 4/8dp spacing system for padding/gaps/section spacing | Random spacing increments with no rhythm |
612
+ | **Readable text measure** | Keep long-form text readable on large devices (avoid edge-to-edge paragraphs on tablets) | Full-width long text that hurts readability |
613
+ | **Section spacing hierarchy** | Define clear vertical rhythm tiers (e.g., 16/24/32/48) by hierarchy | Similar UI levels with inconsistent spacing |
614
+ | **Adaptive gutters by breakpoint** | Increase horizontal insets on larger widths and in landscape | Same narrow gutter on all device sizes/orientations |
615
+ | **Scroll and fixed element coexistence** | Add bottom/top content insets so lists are not hidden behind fixed bars | Scroll content obscured by sticky headers/footers |
616
+
617
+ ---
618
+
619
+ ## Pre-Delivery Checklist
620
+
621
+ Before delivering UI code, verify these items:
622
+ Scope notice: This checklist is for App UI (iOS/Android/React Native/Flutter).
623
+
624
+ ### Visual Quality
625
+ - [ ] No emojis used as icons (use SVG instead)
626
+ - [ ] All icons come from a consistent icon family and style
627
+ - [ ] Official brand assets are used with correct proportions and clear space
628
+ - [ ] Pressed-state visuals do not shift layout bounds or cause jitter
629
+ - [ ] Semantic theme tokens are used consistently (no ad-hoc per-screen hardcoded colors)
630
+
631
+ ### Interaction
632
+ - [ ] All tappable elements provide clear pressed feedback (ripple/opacity/elevation)
633
+ - [ ] Touch targets meet minimum size (>=44x44pt iOS, >=48x48dp Android)
634
+ - [ ] Micro-interaction timing stays in the 150-300ms range with native-feeling easing
635
+ - [ ] Disabled states are visually clear and non-interactive
636
+ - [ ] Screen reader focus order matches visual order, and interactive labels are descriptive
637
+ - [ ] Gesture regions avoid nested/conflicting interactions (tap/drag/back-swipe conflicts)
638
+
639
+ ### Light/Dark Mode
640
+ - [ ] Primary text contrast >=4.5:1 in both light and dark mode
641
+ - [ ] Secondary text contrast >=3:1 in both light and dark mode
642
+ - [ ] Dividers/borders and interaction states are distinguishable in both modes
643
+ - [ ] Modal/drawer scrim opacity is strong enough to preserve foreground legibility (typically 40-60% black)
644
+ - [ ] Both themes are tested before delivery (not inferred from a single theme)
645
+
646
+ ### Layout
647
+ - [ ] Safe areas are respected for headers, tab bars, and bottom CTA bars
648
+ - [ ] Scroll content is not hidden behind fixed/sticky bars
649
+ - [ ] Verified on small phone, large phone, and tablet (portrait + landscape)
650
+ - [ ] Horizontal insets/gutters adapt correctly by device size and orientation
651
+ - [ ] 4/8dp spacing rhythm is maintained across component, section, and page levels
652
+ - [ ] Long-form text measure remains readable on larger devices (no edge-to-edge paragraphs)
653
+
654
+ ### Accessibility
655
+ - [ ] All meaningful images/icons have accessibility labels
656
+ - [ ] Form fields have labels, hints, and clear error messages
657
+ - [ ] Color is not the only indicator
658
+ - [ ] Reduced motion and dynamic text size are supported without layout breakage
659
+ - [ ] Accessibility traits/roles/states (selected, disabled, expanded) are announced correctly
.agents/skills/ui-ux-pro-max/data ADDED
@@ -0,0 +1 @@
 
 
1
+ ../../../src/ui-ux-pro-max/data
.agents/skills/ui-ux-pro-max/scripts ADDED
@@ -0,0 +1 @@
 
 
1
+ ../../../src/ui-ux-pro-max/scripts
.dockerignore ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Exclude node_modules from frontend
2
+ App/frontend/node_modules
3
+
4
+ # Exclude models and venv from backend
5
+ App/backend/models
6
+ App/backend/venv
7
+ App/backend/__pycache__
8
+ App/backend/*.wav
9
+
10
+ # Exclude other build artifacts
11
+ dist
12
+ static
13
+ .git
14
+ .gitignore
15
+ .dockerignore
16
+ README.md
.gitignore ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Build artifacts
2
+ App/frontend/dist
3
+ App/backend/static
4
+ App/backend/build
5
+ App/backend/dist
6
+ eReader_App/
7
+ *.spec
8
+ node_modules
9
+ venv
10
+ .env*
11
+ *.pyc
12
+ __pycache__
13
+
14
+ # Models (downloaded in Docker or manually)
15
+ App/backend/models/
16
+ App/backend/*.wav
17
+
18
+ # Editor files
19
+ .vscode
20
+ .idea
21
+ .DS_Store
App/backend/check.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import wave
3
+ from piper import PiperVoice
4
+
5
+ voice = PiperVoice.load("models/en_US-lessac-medium.onnx")
6
+
7
+ audio_stream = io.BytesIO()
8
+
9
+ with wave.open(audio_stream, "wb") as wav_file:
10
+ wav_file.setnchannels(1)
11
+ wav_file.setsampwidth(2)
12
+ wav_file.setframerate(voice.config.sample_rate)
13
+ voice.synthesize("test message", wav_file)
14
+
15
+ data = audio_stream.getvalue()
16
+ print("Wav size:", len(data))
17
+ with open("test.wav", "wb") as f:
18
+ f.write(data)
19
+ print("Wrote to test.wav")
App/backend/download_model.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import urllib.request
3
+
4
+ BASE = "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0"
5
+
6
+ VOICES = [
7
+ # US English β€” faster low quality versions
8
+ {"locale": "en/en_US", "name": "lessac", "quality": "low"},
9
+ # US English β€” existing medium
10
+ {"locale": "en/en_US", "name": "lessac", "quality": "medium"},
11
+ {"locale": "en/en_US", "name": "libritts_r", "quality": "medium"},
12
+ # US English β€” new medium
13
+ {"locale": "en/en_US", "name": "joe", "quality": "medium"},
14
+ # British English β€” new
15
+ {"locale": "en/en_GB", "name": "alan", "quality": "medium"},
16
+ {"locale": "en/en_GB", "name": "northern_english_male","quality": "medium"},
17
+ {"locale": "en/en_GB", "name": "semaine", "quality": "medium"},
18
+ {"locale": "en/en_GB", "name": "southern_english_female","quality": "low"},
19
+ ]
20
+
21
+ MODEL_DIR = "models"
22
+ os.makedirs(MODEL_DIR, exist_ok=True)
23
+
24
+ def download(url, path):
25
+ print(f" Downloading {url}")
26
+ urllib.request.urlretrieve(url, path)
27
+ print(f" Saved β†’ {path}")
28
+
29
+ for v in VOICES:
30
+ locale, name, quality = v["locale"], v["name"], v["quality"]
31
+ # derive the locale tag from the path (e.g. "en/en_US" β†’ "en_US")
32
+ locale_tag = locale.split("/")[-1]
33
+ model_id = f"{locale_tag}-{name}-{quality}"
34
+ base_url = f"{BASE}/{locale}/{name}/{quality}/{model_id}"
35
+
36
+ model_path = os.path.join(MODEL_DIR, f"{model_id}.onnx")
37
+ config_path = os.path.join(MODEL_DIR, f"{model_id}.onnx.json")
38
+
39
+ print(f"\n[{model_id}]")
40
+ if not os.path.exists(model_path):
41
+ download(f"{base_url}.onnx?download=true", model_path)
42
+ else:
43
+ print(" model already present, skipping.")
44
+
45
+ if not os.path.exists(config_path):
46
+ download(f"{base_url}.onnx.json?download=true", config_path)
47
+ else:
48
+ print(" config already present, skipping.")
49
+
50
+ print("\nAll models ready.")
App/backend/main.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import io
3
+ import wave
4
+ from contextlib import asynccontextmanager
5
+ from fastapi import FastAPI
6
+ from fastapi.responses import Response
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ from fastapi.staticfiles import StaticFiles
9
+ from pydantic import BaseModel
10
+ from typing import Optional
11
+ from piper import PiperVoice
12
+ from piper.config import SynthesisConfig
13
+ import onnxruntime
14
+ import logging
15
+ import numpy as np
16
+
17
+ log = logging.getLogger("uvicorn.error")
18
+
19
+ # Monkey-patch ONNX Runtime to auto-detect best provider (GPU > CPU)
20
+ _original_inf_session = onnxruntime.InferenceSession
21
+
22
+ def _patched_inf_session(path_or_bytes, sess_options=None, providers=None, *args, **kwargs):
23
+ if providers is None or providers == ['CPUExecutionProvider']:
24
+ available = onnxruntime.get_available_providers()
25
+ preferred = [p for p in ['CUDAExecutionProvider', 'DmlExecutionProvider', 'CoreMLExecutionProvider'] if p in available]
26
+ preferred.append('CPUExecutionProvider')
27
+ providers = preferred
28
+ return _original_inf_session(path_or_bytes, sess_options, providers, *args, **kwargs)
29
+
30
+ onnxruntime.InferenceSession = _patched_inf_session
31
+
32
+ # Load models lazily
33
+ voices = {}
34
+
35
+ def get_voice(voice_id: str):
36
+ global voices
37
+ if voice_id not in voices:
38
+ model_path = f"models/{voice_id}.onnx"
39
+ if not os.path.exists(model_path):
40
+ raise Exception(f"Model not found: {model_path}. Run download_model.py")
41
+ voices[voice_id] = PiperVoice.load(model_path)
42
+ return voices[voice_id]
43
+
44
+ def synthesize_text(text: str, voice_id: str, speaker_id: Optional[int] = None) -> bytes:
45
+ """Core synthesis helper - returns raw WAV bytes."""
46
+ v = get_voice(voice_id)
47
+ audio_stream = io.BytesIO()
48
+ with wave.open(audio_stream, "wb") as wav_file:
49
+ wav_file.setnchannels(1)
50
+ wav_file.setsampwidth(2)
51
+ wav_file.setframerate(v.config.sample_rate)
52
+ syn_config = None
53
+ if speaker_id is not None and v.config.num_speakers > 1:
54
+ syn_config = SynthesisConfig(speaker_id=speaker_id)
55
+ for chunk in v.synthesize(text, syn_config=syn_config):
56
+ int16 = (np.clip(chunk.audio_float_array, -1.0, 1.0) * 32767).astype(np.int16)
57
+ wav_file.writeframes(int16.tobytes())
58
+ return audio_stream.getvalue()
59
+
60
+ @asynccontextmanager
61
+ async def lifespan(app: FastAPI):
62
+ """Startup: pre-load the default voice and JIT the ONNX model."""
63
+ log.info("Warming up TTS engine...")
64
+ try:
65
+ synthesize_text("Ready.", "en_US-lessac-low")
66
+ log.info("TTS engine warm and ready.")
67
+ except Exception as e:
68
+ log.error(f"Warmup failed: {e}")
69
+ yield # App runs here
70
+
71
+ app = FastAPI(lifespan=lifespan)
72
+
73
+ app.add_middleware(
74
+ CORSMiddleware,
75
+ allow_origins=["*"],
76
+ allow_credentials=True,
77
+ allow_methods=["*"],
78
+ allow_headers=["*"],
79
+ )
80
+
81
+ class SynthesizeRequest(BaseModel):
82
+ text: str
83
+ voice_id: str = "en_US-lessac-low"
84
+ speaker_id: Optional[int] = None
85
+
86
+ @app.post("/synthesize")
87
+ def synthesize(req: SynthesizeRequest):
88
+ audio_data = synthesize_text(req.text, req.voice_id, req.speaker_id)
89
+ return Response(content=audio_data, media_type="audio/wav")
90
+
91
+ @app.get("/ping")
92
+ def ping():
93
+ return {"status": "ok"}
94
+
95
+ @app.get("/warmup")
96
+ def warmup():
97
+ """Wake the server and ensure the model is loaded. Called on page load."""
98
+ try:
99
+ get_voice("en_US-lessac-low")
100
+ return {"status": "ready"}
101
+ except Exception as e:
102
+ return {"status": "error", "detail": str(e)}
103
+
104
+ # Serve frontend static files if they exist (Docker / single-server mode)
105
+ if os.path.exists("static"):
106
+ app.mount("/", StaticFiles(directory="static", html=True), name="static")
107
+
108
+ if __name__ == "__main__":
109
+ import uvicorn
110
+ uvicorn.run(app, host="127.0.0.1", port=8000, log_level="info")
App/backend/requirements.txt ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ annotated-doc==0.0.4
2
+ annotated-types==0.7.0
3
+ anyio==4.12.1
4
+ click==8.3.1
5
+ colorama==0.4.6
6
+ fastapi==0.133.1
7
+ flatbuffers==25.12.19
8
+ h11==0.16.0
9
+ idna==3.11
10
+ mpmath==1.3.0
11
+ numpy==2.4.2
12
+ onnxruntime==1.24.2
13
+ packaging==26.0
14
+ piper-tts==1.4.1
15
+ protobuf==6.33.5
16
+ pydantic==2.12.5
17
+ pydantic_core==2.41.5
18
+ pydub==0.25.1
19
+ python-multipart==0.0.22
20
+ starlette==0.52.1
21
+ sympy==1.14.0
22
+ typing-inspection==0.4.2
23
+ typing_extensions==4.15.0
24
+ uvicorn==0.41.0
25
+ aiofiles==24.1.0
App/backend/startup_err.txt ADDED
File without changes
App/backend/test_piper.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from piper import PiperVoice
2
+
3
+ v = PiperVoice.load("models/en_US-libritts_r-medium.onnx")
4
+ try:
5
+ chunks = list(v.synthesize("test", speaker_id=5))
6
+ print("SUCCESS with speaker_id kwarg")
7
+ except Exception as e:
8
+ print("FAILED with speaker_id kwarg:", e)
9
+
10
+ try:
11
+ chunks = list(v.synthesize("test", synthesize_args={"speaker_id": 5}))
12
+ print("SUCCESS with synthesize_args")
13
+ except Exception as e:
14
+ print("FAILED with synthesize_args:", e)
App/frontend/.agent/skills/ui-ux-pro-max/SKILL.md ADDED
@@ -0,0 +1,659 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: ui-ux-pro-max
3
+ description: "UI/UX design intelligence for web and mobile. Includes 50+ styles, 161 color palettes, 57 font pairings, 161 product types, 99 UX guidelines, and 25 chart types across 10 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn/ui, and HTML/CSS). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, and check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, and mobile app. Elements: button, modal, navbar, sidebar, card, table, form, and chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, and flat design. Topics: color systems, accessibility, animation, layout, typography, font pairing, spacing, interaction states, shadow, and gradient. Integrations: shadcn/ui MCP for component search and examples."
4
+ ---
5
+
6
+ # UI/UX Pro Max - Design Intelligence
7
+
8
+ Comprehensive design guide for web and mobile applications. Contains 50+ styles, 161 color palettes, 57 font pairings, 161 product types with reasoning rules, 99 UX guidelines, and 25 chart types across 10 technology stacks. Searchable database with priority-based recommendations.
9
+
10
+ ## When to Apply
11
+
12
+ This Skill should be used when the task involves **UI structure, visual design decisions, interaction patterns, or user experience quality control**.
13
+
14
+ ### Must Use
15
+
16
+ This Skill must be invoked in the following situations:
17
+
18
+ - Designing new pages (Landing Page, Dashboard, Admin, SaaS, Mobile App)
19
+ - Creating or refactoring UI components (buttons, modals, forms, tables, charts, etc.)
20
+ - Choosing color schemes, typography systems, spacing standards, or layout systems
21
+ - Reviewing UI code for user experience, accessibility, or visual consistency
22
+ - Implementing navigation structures, animations, or responsive behavior
23
+ - Making product-level design decisions (style, information hierarchy, brand expression)
24
+ - Improving perceived quality, clarity, or usability of interfaces
25
+
26
+ ### Recommended
27
+
28
+ This Skill is recommended in the following situations:
29
+
30
+ - UI looks "not professional enough" but the reason is unclear
31
+ - Receiving feedback on usability or experience
32
+ - Pre-launch UI quality optimization
33
+ - Aligning cross-platform design (Web / iOS / Android)
34
+ - Building design systems or reusable component libraries
35
+
36
+ ### Skip
37
+
38
+ This Skill is not needed in the following situations:
39
+
40
+ - Pure backend logic development
41
+ - Only involving API or database design
42
+ - Performance optimization unrelated to the interface
43
+ - Infrastructure or DevOps work
44
+ - Non-visual scripts or automation tasks
45
+
46
+ **Decision criteria**: If the task will change how a feature **looks, feels, moves, or is interacted with**, this Skill should be used.
47
+
48
+ ## Rule Categories by Priority
49
+
50
+ *For human/AI reference: follow priority 1β†’10 to decide which rule category to focus on first; use `--domain <Domain>` to query details when needed. Scripts do not read this table.*
51
+
52
+ | Priority | Category | Impact | Domain | Key Checks (Must Have) | Anti-Patterns (Avoid) |
53
+ |----------|----------|--------|--------|------------------------|------------------------|
54
+ | 1 | Accessibility | CRITICAL | `ux` | Contrast 4.5:1, Alt text, Keyboard nav, Aria-labels | Removing focus rings, Icon-only buttons without labels |
55
+ | 2 | Touch & Interaction | CRITICAL | `ux` | Min size 44Γ—44px, 8px+ spacing, Loading feedback | Reliance on hover only, Instant state changes (0ms) |
56
+ | 3 | Performance | HIGH | `ux` | WebP/AVIF, Lazy loading, Reserve space (CLS &lt; 0.1) | Layout thrashing, Cumulative Layout Shift |
57
+ | 4 | Style Selection | HIGH | `style`, `product` | Match product type, Consistency, SVG icons (no emoji) | Mixing flat & skeuomorphic randomly, Emoji as icons |
58
+ | 5 | Layout & Responsive | HIGH | `ux` | Mobile-first breakpoints, Viewport meta, No horizontal scroll | Horizontal scroll, Fixed px container widths, Disable zoom |
59
+ | 6 | Typography & Color | MEDIUM | `typography`, `color` | Base 16px, Line-height 1.5, Semantic color tokens | Text &lt; 12px body, Gray-on-gray, Raw hex in components |
60
+ | 7 | Animation | MEDIUM | `ux` | Duration 150–300ms, Motion conveys meaning, Spatial continuity | Decorative-only animation, Animating width/height, No reduced-motion |
61
+ | 8 | Forms & Feedback | MEDIUM | `ux` | Visible labels, Error near field, Helper text, Progressive disclosure | Placeholder-only label, Errors only at top, Overwhelm upfront |
62
+ | 9 | Navigation Patterns | HIGH | `ux` | Predictable back, Bottom nav ≀5, Deep linking | Overloaded nav, Broken back behavior, No deep links |
63
+ | 10 | Charts & Data | LOW | `chart` | Legends, Tooltips, Accessible colors | Relying on color alone to convey meaning |
64
+
65
+ ## Quick Reference
66
+
67
+ ### 1. Accessibility (CRITICAL)
68
+
69
+ - `color-contrast` - Minimum 4.5:1 ratio for normal text (large text 3:1); Material Design
70
+ - `focus-states` - Visible focus rings on interactive elements (2–4px; Apple HIG, MD)
71
+ - `alt-text` - Descriptive alt text for meaningful images
72
+ - `aria-labels` - aria-label for icon-only buttons; accessibilityLabel in native (Apple HIG)
73
+ - `keyboard-nav` - Tab order matches visual order; full keyboard support (Apple HIG)
74
+ - `form-labels` - Use label with for attribute
75
+ - `skip-links` - Skip to main content for keyboard users
76
+ - `heading-hierarchy` - Sequential h1β†’h6, no level skip
77
+ - `color-not-only` - Don't convey info by color alone (add icon/text)
78
+ - `dynamic-type` - Support system text scaling; avoid truncation as text grows (Apple Dynamic Type, MD)
79
+ - `reduced-motion` - Respect prefers-reduced-motion; reduce/disable animations when requested (Apple Reduced Motion API, MD)
80
+ - `voiceover-sr` - Meaningful accessibilityLabel/accessibilityHint; logical reading order for VoiceOver/screen readers (Apple HIG, MD)
81
+ - `escape-routes` - Provide cancel/back in modals and multi-step flows (Apple HIG)
82
+ - `keyboard-shortcuts` - Preserve system and a11y shortcuts; offer keyboard alternatives for drag-and-drop (Apple HIG)
83
+
84
+ ### 2. Touch & Interaction (CRITICAL)
85
+
86
+ - `touch-target-size` - Min 44Γ—44pt (Apple) / 48Γ—48dp (Material); extend hit area beyond visual bounds if needed
87
+ - `touch-spacing` - Minimum 8px/8dp gap between touch targets (Apple HIG, MD)
88
+ - `hover-vs-tap` - Use click/tap for primary interactions; don't rely on hover alone
89
+ - `loading-buttons` - Disable button during async operations; show spinner or progress
90
+ - `error-feedback` - Clear error messages near problem
91
+ - `cursor-pointer` - Add cursor-pointer to clickable elements (Web)
92
+ - `gesture-conflicts` - Avoid horizontal swipe on main content; prefer vertical scroll
93
+ - `tap-delay` - Use touch-action: manipulation to reduce 300ms delay (Web)
94
+ - `standard-gestures` - Use platform standard gestures consistently; don't redefine (e.g. swipe-back, pinch-zoom) (Apple HIG)
95
+ - `system-gestures` - Don't block system gestures (Control Center, back swipe, etc.) (Apple HIG)
96
+ - `press-feedback` - Visual feedback on press (ripple/highlight; MD state layers)
97
+ - `haptic-feedback` - Use haptic for confirmations and important actions; avoid overuse (Apple HIG)
98
+ - `gesture-alternative` - Don't rely on gesture-only interactions; always provide visible controls for critical actions
99
+ - `safe-area-awareness` - Keep primary touch targets away from notch, Dynamic Island, gesture bar and screen edges
100
+ - `no-precision-required` - Avoid requiring pixel-perfect taps on small icons or thin edges
101
+ - `swipe-clarity` - Swipe actions must show clear affordance or hint (chevron, label, tutorial)
102
+ - `drag-threshold` - Use a movement threshold before starting drag to avoid accidental drags
103
+
104
+ ### 3. Performance (HIGH)
105
+
106
+ - `image-optimization` - Use WebP/AVIF, responsive images (srcset/sizes), lazy load non-critical assets
107
+ - `image-dimension` - Declare width/height or use aspect-ratio to prevent layout shift (Core Web Vitals: CLS)
108
+ - `font-loading` - Use font-display: swap/optional to avoid invisible text (FOIT); reserve space to reduce layout shift (MD)
109
+ - `font-preload` - Preload only critical fonts; avoid overusing preload on every variant
110
+ - `critical-css` - Prioritize above-the-fold CSS (inline critical CSS or early-loaded stylesheet)
111
+ - `lazy-loading` - Lazy load non-hero components via dynamic import / route-level splitting
112
+ - `bundle-splitting` - Split code by route/feature (React Suspense / Next.js dynamic) to reduce initial load and TTI
113
+ - `third-party-scripts` - Load third-party scripts async/defer; audit and remove unnecessary ones (MD)
114
+ - `reduce-reflows` - Avoid frequent layout reads/writes; batch DOM reads then writes
115
+ - `content-jumping` - Reserve space for async content to avoid layout jumps (Core Web Vitals: CLS)
116
+ - `lazy-load-below-fold` - Use loading="lazy" for below-the-fold images and heavy media
117
+ - `virtualize-lists` - Virtualize lists with 50+ items to improve memory efficiency and scroll performance
118
+ - `main-thread-budget` - Keep per-frame work under ~16ms for 60fps; move heavy tasks off main thread (HIG, MD)
119
+ - `progressive-loading` - Use skeleton screens / shimmer instead of long blocking spinners for >1s operations (Apple HIG)
120
+ - `input-latency` - Keep input latency under ~100ms for taps/scrolls (Material responsiveness standard)
121
+ - `tap-feedback-speed` - Provide visual feedback within 100ms of tap (Apple HIG)
122
+ - `debounce-throttle` - Use debounce/throttle for high-frequency events (scroll, resize, input)
123
+ - `offline-support` - Provide offline state messaging and basic fallback (PWA / mobile)
124
+ - `network-fallback` - Offer degraded modes for slow networks (lower-res images, fewer animations)
125
+
126
+ ### 4. Style Selection (HIGH)
127
+
128
+ - `style-match` - Match style to product type (use `--design-system` for recommendations)
129
+ - `consistency` - Use same style across all pages
130
+ - `no-emoji-icons` - Use SVG icons (Heroicons, Lucide), not emojis
131
+ - `color-palette-from-product` - Choose palette from product/industry (search `--domain color`)
132
+ - `effects-match-style` - Shadows, blur, radius aligned with chosen style (glass / flat / clay etc.)
133
+ - `platform-adaptive` - Respect platform idioms (iOS HIG vs Material): navigation, controls, typography, motion
134
+ - `state-clarity` - Make hover/pressed/disabled states visually distinct while staying on-style (Material state layers)
135
+ - `elevation-consistent` - Use a consistent elevation/shadow scale for cards, sheets, modals; avoid random shadow values
136
+ - `dark-mode-pairing` - Design light/dark variants together to keep brand, contrast, and style consistent
137
+ - `icon-style-consistent` - Use one icon set/visual language (stroke width, corner radius) across the product
138
+ - `system-controls` - Prefer native/system controls over fully custom ones; only customize when branding requires it (Apple HIG)
139
+ - `blur-purpose` - Use blur to indicate background dismissal (modals, sheets), not as decoration (Apple HIG)
140
+ - `primary-action` - Each screen should have only one primary CTA; secondary actions visually subordinate (Apple HIG)
141
+
142
+ ### 5. Layout & Responsive (HIGH)
143
+
144
+ - `viewport-meta` - width=device-width initial-scale=1 (never disable zoom)
145
+ - `mobile-first` - Design mobile-first, then scale up to tablet and desktop
146
+ - `breakpoint-consistency` - Use systematic breakpoints (e.g. 375 / 768 / 1024 / 1440)
147
+ - `readable-font-size` - Minimum 16px body text on mobile (avoids iOS auto-zoom)
148
+ - `line-length-control` - Mobile 35–60 chars per line; desktop 60–75 chars
149
+ - `horizontal-scroll` - No horizontal scroll on mobile; ensure content fits viewport width
150
+ - `spacing-scale` - Use 4pt/8dp incremental spacing system (Material Design)
151
+ - `touch-density` - Keep component spacing comfortable for touch: not cramped, not causing mis-taps
152
+ - `container-width` - Consistent max-width on desktop (max-w-6xl / 7xl)
153
+ - `z-index-management` - Define layered z-index scale (e.g. 0 / 10 / 20 / 40 / 100 / 1000)
154
+ - `fixed-element-offset` - Fixed navbar/bottom bar must reserve safe padding for underlying content
155
+ - `scroll-behavior` - Avoid nested scroll regions that interfere with the main scroll experience
156
+ - `viewport-units` - Prefer min-h-dvh over 100vh on mobile
157
+ - `orientation-support` - Keep layout readable and operable in landscape mode
158
+ - `content-priority` - Show core content first on mobile; fold or hide secondary content
159
+ - `visual-hierarchy` - Establish hierarchy via size, spacing, contrast β€” not color alone
160
+
161
+ ### 6. Typography & Color (MEDIUM)
162
+
163
+ - `line-height` - Use 1.5-1.75 for body text
164
+ - `line-length` - Limit to 65-75 characters per line
165
+ - `font-pairing` - Match heading/body font personalities
166
+ - `font-scale` - Consistent type scale (e.g. 12 14 16 18 24 32)
167
+ - `contrast-readability` - Darker text on light backgrounds (e.g. slate-900 on white)
168
+ - `text-styles-system` - Use platform type system: iOS 11 Dynamic Type styles / Material 5 type roles (display, headline, title, body, label) (HIG, MD)
169
+ - `weight-hierarchy` - Use font-weight to reinforce hierarchy: Bold headings (600–700), Regular body (400), Medium labels (500) (MD)
170
+ - `color-semantic` - Define semantic color tokens (primary, secondary, error, surface, on-surface) not raw hex in components (Material color system)
171
+ - `color-dark-mode` - Dark mode uses desaturated / lighter tonal variants, not inverted colors; test contrast separately (HIG, MD)
172
+ - `color-accessible-pairs` - Foreground/background pairs must meet 4.5:1 (AA) or 7:1 (AAA); use tools to verify (WCAG, MD)
173
+ - `color-not-decorative-only` - Functional color (error red, success green) must include icon/text; avoid color-only meaning (HIG, MD)
174
+ - `truncation-strategy` - Prefer wrapping over truncation; when truncating use ellipsis and provide full text via tooltip/expand (Apple HIG)
175
+ - `letter-spacing` - Respect default letter-spacing per platform; avoid tight tracking on body text (HIG, MD)
176
+ - `number-tabular` - Use tabular/monospaced figures for data columns, prices, and timers to prevent layout shift
177
+ - `whitespace-balance` - Use whitespace intentionally to group related items and separate sections; avoid visual clutter (Apple HIG)
178
+
179
+ ### 7. Animation (MEDIUM)
180
+
181
+ - `duration-timing` - Use 150–300ms for micro-interactions; complex transitions ≀400ms; avoid >500ms (MD)
182
+ - `transform-performance` - Use transform/opacity only; avoid animating width/height/top/left
183
+ - `loading-states` - Show skeleton or progress indicator when loading exceeds 300ms
184
+ - `excessive-motion` - Animate 1-2 key elements per view max
185
+ - `easing` - Use ease-out for entering, ease-in for exiting; avoid linear for UI transitions
186
+ - `motion-meaning` - Every animation must express a cause-effect relationship, not just be decorative (Apple HIG)
187
+ - `state-transition` - State changes (hover / active / expanded / collapsed / modal) should animate smoothly, not snap
188
+ - `continuity` - Page/screen transitions should maintain spatial continuity (shared element, directional slide) (Apple HIG)
189
+ - `parallax-subtle` - Use parallax sparingly; must respect reduced-motion and not cause disorientation (Apple HIG)
190
+ - `spring-physics` - Prefer spring/physics-based curves over linear or cubic-bezier for natural feel (Apple HIG fluid animations)
191
+ - `exit-faster-than-enter` - Exit animations shorter than enter (~60–70% of enter duration) to feel responsive (MD motion)
192
+ - `stagger-sequence` - Stagger list/grid item entrance by 30–50ms per item; avoid all-at-once or too-slow reveals (MD)
193
+ - `shared-element-transition` - Use shared element / hero transitions for visual continuity between screens (MD, HIG)
194
+ - `interruptible` - Animations must be interruptible; user tap/gesture cancels in-progress animation immediately (Apple HIG)
195
+ - `no-blocking-animation` - Never block user input during an animation; UI must stay interactive (Apple HIG)
196
+ - `fade-crossfade` - Use crossfade for content replacement within the same container (MD)
197
+ - `scale-feedback` - Subtle scale (0.95–1.05) on press for tappable cards/buttons; restore on release (HIG, MD)
198
+ - `gesture-feedback` - Drag, swipe, and pinch must provide real-time visual response tracking the finger (MD Motion)
199
+ - `hierarchy-motion` - Use translate/scale direction to express hierarchy: enter from below = deeper, exit upward = back (MD)
200
+ - `motion-consistency` - Unify duration/easing tokens globally; all animations share the same rhythm and feel
201
+ - `opacity-threshold` - Fading elements should not linger below opacity 0.2; either fade fully or remain visible
202
+ - `modal-motion` - Modals/sheets should animate from their trigger source (scale+fade or slide-in) for spatial context (HIG, MD)
203
+ - `navigation-direction` - Forward navigation animates left/up; backward animates right/down β€” keep direction logically consistent (HIG)
204
+ - `layout-shift-avoid` - Animations must not cause layout reflow or CLS; use transform for position changes
205
+
206
+ ### 8. Forms & Feedback (MEDIUM)
207
+
208
+ - `input-labels` - Visible label per input (not placeholder-only)
209
+ - `error-placement` - Show error below the related field
210
+ - `submit-feedback` - Loading then success/error state on submit
211
+ - `required-indicators` - Mark required fields (e.g. asterisk)
212
+ - `empty-states` - Helpful message and action when no content
213
+ - `toast-dismiss` - Auto-dismiss toasts in 3-5s
214
+ - `confirmation-dialogs` - Confirm before destructive actions
215
+ - `input-helper-text` - Provide persistent helper text below complex inputs, not just placeholder (Material Design)
216
+ - `disabled-states` - Disabled elements use reduced opacity (0.38–0.5) + cursor change + semantic attribute (MD)
217
+ - `progressive-disclosure` - Reveal complex options progressively; don't overwhelm users upfront (Apple HIG)
218
+ - `inline-validation` - Validate on blur (not keystroke); show error only after user finishes input (MD)
219
+ - `input-type-keyboard` - Use semantic input types (email, tel, number) to trigger the correct mobile keyboard (HIG, MD)
220
+ - `password-toggle` - Provide show/hide toggle for password fields (MD)
221
+ - `autofill-support` - Use autocomplete / textContentType attributes so the system can autofill (HIG, MD)
222
+ - `undo-support` - Allow undo for destructive or bulk actions (e.g. "Undo delete" toast) (Apple HIG)
223
+ - `success-feedback` - Confirm completed actions with brief visual feedback (checkmark, toast, color flash) (MD)
224
+ - `error-recovery` - Error messages must include a clear recovery path (retry, edit, help link) (HIG, MD)
225
+ - `multi-step-progress` - Multi-step flows show step indicator or progress bar; allow back navigation (MD)
226
+ - `form-autosave` - Long forms should auto-save drafts to prevent data loss on accidental dismissal (Apple HIG)
227
+ - `sheet-dismiss-confirm` - Confirm before dismissing a sheet/modal with unsaved changes (Apple HIG)
228
+ - `error-clarity` - Error messages must state cause + how to fix (not just "Invalid input") (HIG, MD)
229
+ - `field-grouping` - Group related fields logically (fieldset/legend or visual grouping) (MD)
230
+ - `read-only-distinction` - Read-only state should be visually and semantically different from disabled (MD)
231
+ - `focus-management` - After submit error, auto-focus the first invalid field (WCAG, MD)
232
+ - `error-summary` - For multiple errors, show summary at top with anchor links to each field (WCAG)
233
+ - `touch-friendly-input` - Mobile input height β‰₯44px to meet touch target requirements (Apple HIG)
234
+ - `destructive-emphasis` - Destructive actions use semantic danger color (red) and are visually separated from primary actions (HIG, MD)
235
+ - `toast-accessibility` - Toasts must not steal focus; use aria-live="polite" for screen reader announcement (WCAG)
236
+ - `aria-live-errors` - Form errors use aria-live region or role="alert" to notify screen readers (WCAG)
237
+ - `contrast-feedback` - Error and success state colors must meet 4.5:1 contrast ratio (WCAG, MD)
238
+ - `timeout-feedback` - Request timeout must show clear feedback with retry option (MD)
239
+
240
+ ### 9. Navigation Patterns (HIGH)
241
+
242
+ - `bottom-nav-limit` - Bottom navigation max 5 items; use labels with icons (Material Design)
243
+ - `drawer-usage` - Use drawer/sidebar for secondary navigation, not primary actions (Material Design)
244
+ - `back-behavior` - Back navigation must be predictable and consistent; preserve scroll/state (Apple HIG, MD)
245
+ - `deep-linking` - All key screens must be reachable via deep link / URL for sharing and notifications (Apple HIG, MD)
246
+ - `tab-bar-ios` - iOS: use bottom Tab Bar for top-level navigation (Apple HIG)
247
+ - `top-app-bar-android` - Android: use Top App Bar with navigation icon for primary structure (Material Design)
248
+ - `nav-label-icon` - Navigation items must have both icon and text label; icon-only nav harms discoverability (MD)
249
+ - `nav-state-active` - Current location must be visually highlighted (color, weight, indicator) in navigation (HIG, MD)
250
+ - `nav-hierarchy` - Primary nav (tabs/bottom bar) vs secondary nav (drawer/settings) must be clearly separated (MD)
251
+ - `modal-escape` - Modals and sheets must offer a clear close/dismiss affordance; swipe-down to dismiss on mobile (Apple HIG)
252
+ - `search-accessible` - Search must be easily reachable (top bar or tab); provide recent/suggested queries (MD)
253
+ - `breadcrumb-web` - Web: use breadcrumbs for 3+ level deep hierarchies to aid orientation (MD)
254
+ - `state-preservation` - Navigating back must restore previous scroll position, filter state, and input (HIG, MD)
255
+ - `gesture-nav-support` - Support system gesture navigation (iOS swipe-back, Android predictive back) without conflict (HIG, MD)
256
+ - `tab-badge` - Use badges on nav items sparingly to indicate unread/pending; clear after user visits (HIG, MD)
257
+ - `overflow-menu` - When actions exceed available space, use overflow/more menu instead of cramming (MD)
258
+ - `bottom-nav-top-level` - Bottom nav is for top-level screens only; never nest sub-navigation inside it (MD)
259
+ - `adaptive-navigation` - Large screens (β‰₯1024px) prefer sidebar; small screens use bottom/top nav (Material Adaptive)
260
+ - `back-stack-integrity` - Never silently reset the navigation stack or unexpectedly jump to home (HIG, MD)
261
+ - `navigation-consistency` - Navigation placement must stay the same across all pages; don't change by page type
262
+ - `avoid-mixed-patterns` - Don't mix Tab + Sidebar + Bottom Nav at the same hierarchy level
263
+ - `modal-vs-navigation` - Modals must not be used for primary navigation flows; they break the user's path (HIG)
264
+ - `focus-on-route-change` - After page transition, move focus to main content region for screen reader users (WCAG)
265
+ - `persistent-nav` - Core navigation must remain reachable from deep pages; don't hide it entirely in sub-flows (HIG, MD)
266
+ - `destructive-nav-separation` - Dangerous actions (delete account, logout) must be visually and spatially separated from normal nav items (HIG, MD)
267
+ - `empty-nav-state` - When a nav destination is unavailable, explain why instead of silently hiding it (MD)
268
+
269
+ ### 10. Charts & Data (LOW)
270
+
271
+ - `chart-type` - Match chart type to data type (trend β†’ line, comparison β†’ bar, proportion β†’ pie/donut)
272
+ - `color-guidance` - Use accessible color palettes; avoid red/green only pairs for colorblind users (WCAG, MD)
273
+ - `data-table` - Provide table alternative for accessibility; charts alone are not screen-reader friendly (WCAG)
274
+ - `pattern-texture` - Supplement color with patterns, textures, or shapes so data is distinguishable without color (WCAG, MD)
275
+ - `legend-visible` - Always show legend; position near the chart, not detached below a scroll fold (MD)
276
+ - `tooltip-on-interact` - Provide tooltips/data labels on hover (Web) or tap (mobile) showing exact values (HIG, MD)
277
+ - `axis-labels` - Label axes with units and readable scale; avoid truncated or rotated labels on mobile
278
+ - `responsive-chart` - Charts must reflow or simplify on small screens (e.g. horizontal bar instead of vertical, fewer ticks)
279
+ - `empty-data-state` - Show meaningful empty state when no data exists ("No data yet" + guidance), not a blank chart (MD)
280
+ - `loading-chart` - Use skeleton or shimmer placeholder while chart data loads; don't show an empty axis frame
281
+ - `animation-optional` - Chart entrance animations must respect prefers-reduced-motion; data should be readable immediately (HIG)
282
+ - `large-dataset` - For 1000+ data points, aggregate or sample; provide drill-down for detail instead of rendering all (MD)
283
+ - `number-formatting` - Use locale-aware formatting for numbers, dates, currencies on axes and labels (HIG, MD)
284
+ - `touch-target-chart` - Interactive chart elements (points, segments) must have β‰₯44pt tap area or expand on touch (Apple HIG)
285
+ - `no-pie-overuse` - Avoid pie/donut for >5 categories; switch to bar chart for clarity
286
+ - `contrast-data` - Data lines/bars vs background β‰₯3:1; data text labels β‰₯4.5:1 (WCAG)
287
+ - `legend-interactive` - Legends should be clickable to toggle series visibility (MD)
288
+ - `direct-labeling` - For small datasets, label values directly on the chart to reduce eye travel
289
+ - `tooltip-keyboard` - Tooltip content must be keyboard-reachable and not rely on hover alone (WCAG)
290
+ - `sortable-table` - Data tables must support sorting with aria-sort indicating current sort state (WCAG)
291
+ - `axis-readability` - Axis ticks must not be cramped; maintain readable spacing, auto-skip on small screens
292
+ - `data-density` - Limit information density per chart to avoid cognitive overload; split into multiple charts if needed
293
+ - `trend-emphasis` - Emphasize data trends over decoration; avoid heavy gradients/shadows that obscure the data
294
+ - `gridline-subtle` - Grid lines should be low-contrast (e.g. gray-200) so they don't compete with data
295
+ - `focusable-elements` - Interactive chart elements (points, bars, slices) must be keyboard-navigable (WCAG)
296
+ - `screen-reader-summary` - Provide a text summary or aria-label describing the chart's key insight for screen readers (WCAG)
297
+ - `error-state-chart` - Data load failure must show error message with retry action, not a broken/empty chart
298
+ - `export-option` - For data-heavy products, offer CSV/image export of chart data
299
+ - `drill-down-consistency` - Drill-down interactions must maintain a clear back-path and hierarchy breadcrumb
300
+ - `time-scale-clarity` - Time series charts must clearly label time granularity (day/week/month) and allow switching
301
+
302
+ ## How to Use
303
+
304
+ Search specific domains using the CLI tool below.
305
+
306
+ ---
307
+
308
+ ## Prerequisites
309
+
310
+ Check if Python is installed:
311
+
312
+ ```bash
313
+ python3 --version || python --version
314
+ ```
315
+
316
+ If Python is not installed, install it based on user's OS:
317
+
318
+ **macOS:**
319
+ ```bash
320
+ brew install python3
321
+ ```
322
+
323
+ **Ubuntu/Debian:**
324
+ ```bash
325
+ sudo apt update && sudo apt install python3
326
+ ```
327
+
328
+ **Windows:**
329
+ ```powershell
330
+ winget install Python.Python.3.12
331
+ ```
332
+
333
+ ---
334
+
335
+ ## How to Use This Skill
336
+
337
+ Use this skill when the user requests any of the following:
338
+
339
+ | Scenario | Trigger Examples | Start From |
340
+ |----------|-----------------|------------|
341
+ | **New project / page** | "Build a landing page", "Build a dashboard" | Step 1 β†’ Step 2 (design system) |
342
+ | **New component** | "Create a pricing card", "Add a modal" | Step 3 (domain search: style, ux) |
343
+ | **Choose style / color / font** | "What style fits a fintech app?", "Recommend a color palette" | Step 2 (design system) |
344
+ | **Review existing UI** | "Review this page for UX issues", "Check accessibility" | Quick Reference checklist above |
345
+ | **Fix a UI bug** | "Button hover is broken", "Layout shifts on load" | Quick Reference β†’ relevant section |
346
+ | **Improve / optimize** | "Make this faster", "Improve mobile experience" | Step 3 (domain search: ux, react) |
347
+ | **Implement dark mode** | "Add dark mode support" | Step 3 (domain: style "dark mode") |
348
+ | **Add charts / data viz** | "Add an analytics dashboard chart" | Step 3 (domain: chart) |
349
+ | **Stack best practices** | "React performance tips"、"SwiftUI navigation" | Step 4 (stack search) |
350
+
351
+ Follow this workflow:
352
+
353
+ ### Step 1: Analyze User Requirements
354
+
355
+ Extract key information from user request:
356
+ - **Product type**: Entertainment (social, video, music, gaming), Tool (scanner, editor, converter), Productivity (task manager, notes, calendar), or hybrid
357
+ - **Target audience**: C-end consumer users; consider age group, usage context (commute, leisure, work)
358
+ - **Style keywords**: playful, vibrant, minimal, dark mode, content-first, immersive, etc.
359
+ - **Stack**: React Native (this project's only tech stack)
360
+
361
+ ### Step 2: Generate Design System (REQUIRED)
362
+
363
+ **Always start with `--design-system`** to get comprehensive recommendations with reasoning:
364
+
365
+ ```bash
366
+ python3 skills/ui-ux-pro-max/scripts/search.py "<product_type> <industry> <keywords>" --design-system [-p "Project Name"]
367
+ ```
368
+
369
+ This command:
370
+ 1. Searches domains in parallel (product, style, color, landing, typography)
371
+ 2. Applies reasoning rules from `ui-reasoning.csv` to select best matches
372
+ 3. Returns complete design system: pattern, style, colors, typography, effects
373
+ 4. Includes anti-patterns to avoid
374
+
375
+ **Example:**
376
+ ```bash
377
+ python3 skills/ui-ux-pro-max/scripts/search.py "beauty spa wellness service" --design-system -p "Serenity Spa"
378
+ ```
379
+
380
+ ### Step 2b: Persist Design System (Master + Overrides Pattern)
381
+
382
+ To save the design system for **hierarchical retrieval across sessions**, add `--persist`:
383
+
384
+ ```bash
385
+ python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name"
386
+ ```
387
+
388
+ This creates:
389
+ - `design-system/MASTER.md` β€” Global Source of Truth with all design rules
390
+ - `design-system/pages/` β€” Folder for page-specific overrides
391
+
392
+ **With page-specific override:**
393
+ ```bash
394
+ python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name" --page "dashboard"
395
+ ```
396
+
397
+ This also creates:
398
+ - `design-system/pages/dashboard.md` β€” Page-specific deviations from Master
399
+
400
+ **How hierarchical retrieval works:**
401
+ 1. When building a specific page (e.g., "Checkout"), first check `design-system/pages/checkout.md`
402
+ 2. If the page file exists, its rules **override** the Master file
403
+ 3. If not, use `design-system/MASTER.md` exclusively
404
+
405
+ **Context-aware retrieval prompt:**
406
+ ```
407
+ I am building the [Page Name] page. Please read design-system/MASTER.md.
408
+ Also check if design-system/pages/[page-name].md exists.
409
+ If the page file exists, prioritize its rules.
410
+ If not, use the Master rules exclusively.
411
+ Now, generate the code...
412
+ ```
413
+
414
+ ### Step 3: Supplement with Detailed Searches (as needed)
415
+
416
+ After getting the design system, use domain searches to get additional details:
417
+
418
+ ```bash
419
+ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --domain <domain> [-n <max_results>]
420
+ ```
421
+
422
+ **When to use detailed searches:**
423
+
424
+ | Need | Domain | Example |
425
+ |------|--------|---------|
426
+ | Product type patterns | `product` | `--domain product "entertainment social"` |
427
+ | More style options | `style` | `--domain style "glassmorphism dark"` |
428
+ | Color palettes | `color` | `--domain color "entertainment vibrant"` |
429
+ | Font pairings | `typography` | `--domain typography "playful modern"` |
430
+ | Chart recommendations | `chart` | `--domain chart "real-time dashboard"` |
431
+ | UX best practices | `ux` | `--domain ux "animation accessibility"` |
432
+ | Alternative fonts | `typography` | `--domain typography "elegant luxury"` |
433
+ | Individual Google Fonts | `google-fonts` | `--domain google-fonts "sans serif popular variable"` |
434
+ | Landing structure | `landing` | `--domain landing "hero social-proof"` |
435
+ | React Native perf | `react` | `--domain react "rerender memo list"` |
436
+ | App interface a11y | `web` | `--domain web "accessibilityLabel touch safe-areas"` |
437
+ | AI prompt / CSS keywords | `prompt` | `--domain prompt "minimalism"` |
438
+
439
+ ### Step 4: Stack Guidelines (React Native)
440
+
441
+ Get React Native implementation-specific best practices:
442
+
443
+ ```bash
444
+ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
445
+ ```
446
+
447
+ ---
448
+
449
+ ## Search Reference
450
+
451
+ ### Available Domains
452
+
453
+ | Domain | Use For | Example Keywords |
454
+ |--------|---------|------------------|
455
+ | `product` | Product type recommendations | SaaS, e-commerce, portfolio, healthcare, beauty, service |
456
+ | `style` | UI styles, colors, effects | glassmorphism, minimalism, dark mode, brutalism |
457
+ | `typography` | Font pairings, Google Fonts | elegant, playful, professional, modern |
458
+ | `color` | Color palettes by product type | saas, ecommerce, healthcare, beauty, fintech, service |
459
+ | `landing` | Page structure, CTA strategies | hero, hero-centric, testimonial, pricing, social-proof |
460
+ | `chart` | Chart types, library recommendations | trend, comparison, timeline, funnel, pie |
461
+ | `ux` | Best practices, anti-patterns | animation, accessibility, z-index, loading |
462
+ | `google-fonts` | Individual Google Fonts lookup | sans serif, monospace, japanese, variable font, popular |
463
+ | `react` | React/Next.js performance | waterfall, bundle, suspense, memo, rerender, cache |
464
+ | `web` | App interface guidelines (iOS/Android/React Native) | accessibilityLabel, touch targets, safe areas, Dynamic Type |
465
+ | `prompt` | AI prompts, CSS keywords | (style name) |
466
+
467
+ ### Available Stacks
468
+
469
+ | Stack | Focus |
470
+ |-------|-------|
471
+ | `react-native` | Components, Navigation, Lists |
472
+
473
+ ---
474
+
475
+ ## Example Workflow
476
+
477
+ **User request:** "Make an AI search homepage."
478
+
479
+ ### Step 1: Analyze Requirements
480
+ - Product type: Tool (AI search engine)
481
+ - Target audience: C-end users looking for fast, intelligent search
482
+ - Style keywords: modern, minimal, content-first, dark mode
483
+ - Stack: React Native
484
+
485
+ ### Step 2: Generate Design System (REQUIRED)
486
+
487
+ ```bash
488
+ python3 skills/ui-ux-pro-max/scripts/search.py "AI search tool modern minimal" --design-system -p "AI Search"
489
+ ```
490
+
491
+ **Output:** Complete design system with pattern, style, colors, typography, effects, and anti-patterns.
492
+
493
+ ### Step 3: Supplement with Detailed Searches (as needed)
494
+
495
+ ```bash
496
+ # Get style options for a modern tool product
497
+ python3 skills/ui-ux-pro-max/scripts/search.py "minimalism dark mode" --domain style
498
+
499
+ # Get UX best practices for search interaction and loading
500
+ python3 skills/ui-ux-pro-max/scripts/search.py "search loading animation" --domain ux
501
+ ```
502
+
503
+ ### Step 4: Stack Guidelines
504
+
505
+ ```bash
506
+ python3 skills/ui-ux-pro-max/scripts/search.py "list performance navigation" --stack react-native
507
+ ```
508
+
509
+ **Then:** Synthesize design system + detailed searches and implement the design.
510
+
511
+ ---
512
+
513
+ ## Output Formats
514
+
515
+ The `--design-system` flag supports two output formats:
516
+
517
+ ```bash
518
+ # ASCII box (default) - best for terminal display
519
+ python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system
520
+
521
+ # Markdown - best for documentation
522
+ python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system -f markdown
523
+ ```
524
+
525
+ ---
526
+
527
+ ## Tips for Better Results
528
+
529
+ ### Query Strategy
530
+
531
+ - Use **multi-dimensional keywords** β€” combine product + industry + tone + density: `"entertainment social vibrant content-dense"` not just `"app"`
532
+ - Try different keywords for the same need: `"playful neon"` β†’ `"vibrant dark"` β†’ `"content-first minimal"`
533
+ - Use `--design-system` first for full recommendations, then `--domain` to deep-dive any dimension you're unsure about
534
+ - Always add `--stack react-native` for implementation-specific guidance
535
+
536
+ ### Common Sticking Points
537
+
538
+ | Problem | What to Do |
539
+ |---------|------------|
540
+ | Can't decide on style/color | Re-run `--design-system` with different keywords |
541
+ | Dark mode contrast issues | Quick Reference Β§6: `color-dark-mode` + `color-accessible-pairs` |
542
+ | Animations feel unnatural | Quick Reference Β§7: `spring-physics` + `easing` + `exit-faster-than-enter` |
543
+ | Form UX is poor | Quick Reference Β§8: `inline-validation` + `error-clarity` + `focus-management` |
544
+ | Navigation feels confusing | Quick Reference Β§9: `nav-hierarchy` + `bottom-nav-limit` + `back-behavior` |
545
+ | Layout breaks on small screens | Quick Reference Β§5: `mobile-first` + `breakpoint-consistency` |
546
+ | Performance / jank | Quick Reference Β§3: `virtualize-lists` + `main-thread-budget` + `debounce-throttle` |
547
+
548
+ ### Pre-Delivery Checklist
549
+
550
+ - Run `--domain ux "animation accessibility z-index loading"` as a UX validation pass before implementation
551
+ - Run through Quick Reference **Β§1–§3** (CRITICAL + HIGH) as a final review
552
+ - Test on 375px (small phone) and landscape orientation
553
+ - Verify behavior with **reduced-motion** enabled and **Dynamic Type** at largest size
554
+ - Check dark mode contrast independently (don't assume light mode values work)
555
+ - Confirm all touch targets β‰₯44pt and no content hidden behind safe areas
556
+
557
+ ---
558
+
559
+ ## Common Rules for Professional UI
560
+
561
+ These are frequently overlooked issues that make UI look unprofessional:
562
+ Scope notice: The rules below are for App UI (iOS/Android/React Native/Flutter), not desktop-web interaction patterns.
563
+
564
+ ### Icons & Visual Elements
565
+
566
+ | Rule | Standard | Avoid | Why It Matters |
567
+ |------|----------|--------|----------------|
568
+ | **No Emoji as Structural Icons** | Use vector-based icons (e.g., Lucide, react-native-vector-icons, @expo/vector-icons). | Using emojis (🎨 πŸš€ βš™οΈ) for navigation, settings, or system controls. | Emojis are font-dependent, inconsistent across platforms, and cannot be controlled via design tokens. |
569
+ | **Vector-Only Assets** | Use SVG or platform vector icons that scale cleanly and support theming. | Raster PNG icons that blur or pixelate. | Ensures scalability, crisp rendering, and dark/light mode adaptability. |
570
+ | **Stable Interaction States** | Use color, opacity, or elevation transitions for press states without changing layout bounds. | Layout-shifting transforms that move surrounding content or trigger visual jitter. | Prevents unstable interactions and preserves smooth motion/perceived quality on mobile. |
571
+ | **Correct Brand Logos** | Use official brand assets and follow their usage guidelines (spacing, color, clear space). | Guessing logo paths, recoloring unofficially, or modifying proportions. | Prevents brand misuse and ensures legal/platform compliance. |
572
+ | **Consistent Icon Sizing** | Define icon sizes as design tokens (e.g., icon-sm, icon-md = 24pt, icon-lg). | Mixing arbitrary values like 20pt / 24pt / 28pt randomly. | Maintains rhythm and visual hierarchy across the interface. |
573
+ | **Stroke Consistency** | Use a consistent stroke width within the same visual layer (e.g., 1.5px or 2px). | Mixing thick and thin stroke styles arbitrarily. | Inconsistent strokes reduce perceived polish and cohesion. |
574
+ | **Filled vs Outline Discipline** | Use one icon style per hierarchy level. | Mixing filled and outline icons at the same hierarchy level. | Maintains semantic clarity and stylistic coherence. |
575
+ | **Touch Target Minimum** | Minimum 44Γ—44pt interactive area (use hitSlop if icon is smaller). | Small icons without expanded tap area. | Meets accessibility and platform usability standards. |
576
+ | **Icon Alignment** | Align icons to text baseline and maintain consistent padding. | Misaligned icons or inconsistent spacing around them. | Prevents subtle visual imbalance that reduces perceived quality. |
577
+ | **Icon Contrast** | Follow WCAG contrast standards: 4.5:1 for small elements, 3:1 minimum for larger UI glyphs. | Low-contrast icons that blend into the background. | Ensures accessibility in both light and dark modes. |
578
+
579
+
580
+ ### Interaction (App)
581
+
582
+ | Rule | Do | Don't |
583
+ |------|----|----- |
584
+ | **Tap feedback** | Provide clear pressed feedback (ripple/opacity/elevation) within 80-150ms | No visual response on tap |
585
+ | **Animation timing** | Keep micro-interactions around 150-300ms with platform-native easing | Instant transitions or slow animations (>500ms) |
586
+ | **Accessibility focus** | Ensure screen reader focus order matches visual order and labels are descriptive | Unlabeled controls or confusing focus traversal |
587
+ | **Disabled state clarity** | Use disabled semantics (`disabled`/native disabled props), reduced emphasis, and no tap action | Controls that look tappable but do nothing |
588
+ | **Touch target minimum** | Keep tap areas >=44x44pt (iOS) or >=48x48dp (Android), expand hit area when icon is smaller | Tiny tap targets or icon-only hit areas without padding |
589
+ | **Gesture conflict prevention** | Keep one primary gesture per region and avoid nested tap/drag conflicts | Overlapping gestures causing accidental actions |
590
+ | **Semantic native controls** | Prefer native interactive primitives (`Button`, `Pressable`, platform equivalents) with proper accessibility roles | Generic containers used as primary controls without semantics |
591
+
592
+ ### Light/Dark Mode Contrast
593
+
594
+ | Rule | Do | Don't |
595
+ |------|----|----- |
596
+ | **Surface readability (light)** | Keep cards/surfaces clearly separated from background with sufficient opacity/elevation | Overly transparent surfaces that blur hierarchy |
597
+ | **Text contrast (light)** | Maintain body text contrast >=4.5:1 against light surfaces | Low-contrast gray body text |
598
+ | **Text contrast (dark)** | Maintain primary text contrast >=4.5:1 and secondary text >=3:1 on dark surfaces | Dark mode text that blends into background |
599
+ | **Border and divider visibility** | Ensure separators are visible in both themes (not just light mode) | Theme-specific borders disappearing in one mode |
600
+ | **State contrast parity** | Keep pressed/focused/disabled states equally distinguishable in light and dark themes | Defining interaction states for one theme only |
601
+ | **Token-driven theming** | Use semantic color tokens mapped per theme across app surfaces/text/icons | Hardcoded per-screen hex values |
602
+ | **Scrim and modal legibility** | Use a modal scrim strong enough to isolate foreground content (typically 40-60% black) | Weak scrim that leaves background visually competing |
603
+
604
+ ### Layout & Spacing
605
+
606
+ | Rule | Do | Don't |
607
+ |------|----|----- |
608
+ | **Safe-area compliance** | Respect top/bottom safe areas for all fixed headers, tab bars, and CTA bars | Placing fixed UI under notch, status bar, or gesture area |
609
+ | **System bar clearance** | Add spacing for status/navigation bars and gesture home indicator | Let tappable content collide with OS chrome |
610
+ | **Consistent content width** | Keep predictable content width per device class (phone/tablet) | Mixing arbitrary widths between screens |
611
+ | **8dp spacing rhythm** | Use a consistent 4/8dp spacing system for padding/gaps/section spacing | Random spacing increments with no rhythm |
612
+ | **Readable text measure** | Keep long-form text readable on large devices (avoid edge-to-edge paragraphs on tablets) | Full-width long text that hurts readability |
613
+ | **Section spacing hierarchy** | Define clear vertical rhythm tiers (e.g., 16/24/32/48) by hierarchy | Similar UI levels with inconsistent spacing |
614
+ | **Adaptive gutters by breakpoint** | Increase horizontal insets on larger widths and in landscape | Same narrow gutter on all device sizes/orientations |
615
+ | **Scroll and fixed element coexistence** | Add bottom/top content insets so lists are not hidden behind fixed bars | Scroll content obscured by sticky headers/footers |
616
+
617
+ ---
618
+
619
+ ## Pre-Delivery Checklist
620
+
621
+ Before delivering UI code, verify these items:
622
+ Scope notice: This checklist is for App UI (iOS/Android/React Native/Flutter).
623
+
624
+ ### Visual Quality
625
+ - [ ] No emojis used as icons (use SVG instead)
626
+ - [ ] All icons come from a consistent icon family and style
627
+ - [ ] Official brand assets are used with correct proportions and clear space
628
+ - [ ] Pressed-state visuals do not shift layout bounds or cause jitter
629
+ - [ ] Semantic theme tokens are used consistently (no ad-hoc per-screen hardcoded colors)
630
+
631
+ ### Interaction
632
+ - [ ] All tappable elements provide clear pressed feedback (ripple/opacity/elevation)
633
+ - [ ] Touch targets meet minimum size (>=44x44pt iOS, >=48x48dp Android)
634
+ - [ ] Micro-interaction timing stays in the 150-300ms range with native-feeling easing
635
+ - [ ] Disabled states are visually clear and non-interactive
636
+ - [ ] Screen reader focus order matches visual order, and interactive labels are descriptive
637
+ - [ ] Gesture regions avoid nested/conflicting interactions (tap/drag/back-swipe conflicts)
638
+
639
+ ### Light/Dark Mode
640
+ - [ ] Primary text contrast >=4.5:1 in both light and dark mode
641
+ - [ ] Secondary text contrast >=3:1 in both light and dark mode
642
+ - [ ] Dividers/borders and interaction states are distinguishable in both modes
643
+ - [ ] Modal/drawer scrim opacity is strong enough to preserve foreground legibility (typically 40-60% black)
644
+ - [ ] Both themes are tested before delivery (not inferred from a single theme)
645
+
646
+ ### Layout
647
+ - [ ] Safe areas are respected for headers, tab bars, and bottom CTA bars
648
+ - [ ] Scroll content is not hidden behind fixed/sticky bars
649
+ - [ ] Verified on small phone, large phone, and tablet (portrait + landscape)
650
+ - [ ] Horizontal insets/gutters adapt correctly by device size and orientation
651
+ - [ ] 4/8dp spacing rhythm is maintained across component, section, and page levels
652
+ - [ ] Long-form text measure remains readable on larger devices (no edge-to-edge paragraphs)
653
+
654
+ ### Accessibility
655
+ - [ ] All meaningful images/icons have accessibility labels
656
+ - [ ] Form fields have labels, hints, and clear error messages
657
+ - [ ] Color is not the only indicator
658
+ - [ ] Reduced motion and dynamic text size are supported without layout breakage
659
+ - [ ] Accessibility traits/roles/states (selected, disabled, expanded) are announced correctly
App/frontend/.agent/skills/ui-ux-pro-max/data ADDED
@@ -0,0 +1 @@
 
 
1
+ ../../../src/ui-ux-pro-max/data
App/frontend/.agent/skills/ui-ux-pro-max/scripts ADDED
@@ -0,0 +1 @@
 
 
1
+ ../../../src/ui-ux-pro-max/scripts
App/frontend/.agents/skills/ui-ux-pro-max/SKILL.md ADDED
@@ -0,0 +1,659 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: ui-ux-pro-max
3
+ description: "UI/UX design intelligence for web and mobile. Includes 50+ styles, 161 color palettes, 57 font pairings, 161 product types, 99 UX guidelines, and 25 chart types across 10 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn/ui, and HTML/CSS). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, and check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, and mobile app. Elements: button, modal, navbar, sidebar, card, table, form, and chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, and flat design. Topics: color systems, accessibility, animation, layout, typography, font pairing, spacing, interaction states, shadow, and gradient. Integrations: shadcn/ui MCP for component search and examples."
4
+ ---
5
+
6
+ # UI/UX Pro Max - Design Intelligence
7
+
8
+ Comprehensive design guide for web and mobile applications. Contains 50+ styles, 161 color palettes, 57 font pairings, 161 product types with reasoning rules, 99 UX guidelines, and 25 chart types across 10 technology stacks. Searchable database with priority-based recommendations.
9
+
10
+ ## When to Apply
11
+
12
+ This Skill should be used when the task involves **UI structure, visual design decisions, interaction patterns, or user experience quality control**.
13
+
14
+ ### Must Use
15
+
16
+ This Skill must be invoked in the following situations:
17
+
18
+ - Designing new pages (Landing Page, Dashboard, Admin, SaaS, Mobile App)
19
+ - Creating or refactoring UI components (buttons, modals, forms, tables, charts, etc.)
20
+ - Choosing color schemes, typography systems, spacing standards, or layout systems
21
+ - Reviewing UI code for user experience, accessibility, or visual consistency
22
+ - Implementing navigation structures, animations, or responsive behavior
23
+ - Making product-level design decisions (style, information hierarchy, brand expression)
24
+ - Improving perceived quality, clarity, or usability of interfaces
25
+
26
+ ### Recommended
27
+
28
+ This Skill is recommended in the following situations:
29
+
30
+ - UI looks "not professional enough" but the reason is unclear
31
+ - Receiving feedback on usability or experience
32
+ - Pre-launch UI quality optimization
33
+ - Aligning cross-platform design (Web / iOS / Android)
34
+ - Building design systems or reusable component libraries
35
+
36
+ ### Skip
37
+
38
+ This Skill is not needed in the following situations:
39
+
40
+ - Pure backend logic development
41
+ - Only involving API or database design
42
+ - Performance optimization unrelated to the interface
43
+ - Infrastructure or DevOps work
44
+ - Non-visual scripts or automation tasks
45
+
46
+ **Decision criteria**: If the task will change how a feature **looks, feels, moves, or is interacted with**, this Skill should be used.
47
+
48
+ ## Rule Categories by Priority
49
+
50
+ *For human/AI reference: follow priority 1β†’10 to decide which rule category to focus on first; use `--domain <Domain>` to query details when needed. Scripts do not read this table.*
51
+
52
+ | Priority | Category | Impact | Domain | Key Checks (Must Have) | Anti-Patterns (Avoid) |
53
+ |----------|----------|--------|--------|------------------------|------------------------|
54
+ | 1 | Accessibility | CRITICAL | `ux` | Contrast 4.5:1, Alt text, Keyboard nav, Aria-labels | Removing focus rings, Icon-only buttons without labels |
55
+ | 2 | Touch & Interaction | CRITICAL | `ux` | Min size 44Γ—44px, 8px+ spacing, Loading feedback | Reliance on hover only, Instant state changes (0ms) |
56
+ | 3 | Performance | HIGH | `ux` | WebP/AVIF, Lazy loading, Reserve space (CLS &lt; 0.1) | Layout thrashing, Cumulative Layout Shift |
57
+ | 4 | Style Selection | HIGH | `style`, `product` | Match product type, Consistency, SVG icons (no emoji) | Mixing flat & skeuomorphic randomly, Emoji as icons |
58
+ | 5 | Layout & Responsive | HIGH | `ux` | Mobile-first breakpoints, Viewport meta, No horizontal scroll | Horizontal scroll, Fixed px container widths, Disable zoom |
59
+ | 6 | Typography & Color | MEDIUM | `typography`, `color` | Base 16px, Line-height 1.5, Semantic color tokens | Text &lt; 12px body, Gray-on-gray, Raw hex in components |
60
+ | 7 | Animation | MEDIUM | `ux` | Duration 150–300ms, Motion conveys meaning, Spatial continuity | Decorative-only animation, Animating width/height, No reduced-motion |
61
+ | 8 | Forms & Feedback | MEDIUM | `ux` | Visible labels, Error near field, Helper text, Progressive disclosure | Placeholder-only label, Errors only at top, Overwhelm upfront |
62
+ | 9 | Navigation Patterns | HIGH | `ux` | Predictable back, Bottom nav ≀5, Deep linking | Overloaded nav, Broken back behavior, No deep links |
63
+ | 10 | Charts & Data | LOW | `chart` | Legends, Tooltips, Accessible colors | Relying on color alone to convey meaning |
64
+
65
+ ## Quick Reference
66
+
67
+ ### 1. Accessibility (CRITICAL)
68
+
69
+ - `color-contrast` - Minimum 4.5:1 ratio for normal text (large text 3:1); Material Design
70
+ - `focus-states` - Visible focus rings on interactive elements (2–4px; Apple HIG, MD)
71
+ - `alt-text` - Descriptive alt text for meaningful images
72
+ - `aria-labels` - aria-label for icon-only buttons; accessibilityLabel in native (Apple HIG)
73
+ - `keyboard-nav` - Tab order matches visual order; full keyboard support (Apple HIG)
74
+ - `form-labels` - Use label with for attribute
75
+ - `skip-links` - Skip to main content for keyboard users
76
+ - `heading-hierarchy` - Sequential h1β†’h6, no level skip
77
+ - `color-not-only` - Don't convey info by color alone (add icon/text)
78
+ - `dynamic-type` - Support system text scaling; avoid truncation as text grows (Apple Dynamic Type, MD)
79
+ - `reduced-motion` - Respect prefers-reduced-motion; reduce/disable animations when requested (Apple Reduced Motion API, MD)
80
+ - `voiceover-sr` - Meaningful accessibilityLabel/accessibilityHint; logical reading order for VoiceOver/screen readers (Apple HIG, MD)
81
+ - `escape-routes` - Provide cancel/back in modals and multi-step flows (Apple HIG)
82
+ - `keyboard-shortcuts` - Preserve system and a11y shortcuts; offer keyboard alternatives for drag-and-drop (Apple HIG)
83
+
84
+ ### 2. Touch & Interaction (CRITICAL)
85
+
86
+ - `touch-target-size` - Min 44Γ—44pt (Apple) / 48Γ—48dp (Material); extend hit area beyond visual bounds if needed
87
+ - `touch-spacing` - Minimum 8px/8dp gap between touch targets (Apple HIG, MD)
88
+ - `hover-vs-tap` - Use click/tap for primary interactions; don't rely on hover alone
89
+ - `loading-buttons` - Disable button during async operations; show spinner or progress
90
+ - `error-feedback` - Clear error messages near problem
91
+ - `cursor-pointer` - Add cursor-pointer to clickable elements (Web)
92
+ - `gesture-conflicts` - Avoid horizontal swipe on main content; prefer vertical scroll
93
+ - `tap-delay` - Use touch-action: manipulation to reduce 300ms delay (Web)
94
+ - `standard-gestures` - Use platform standard gestures consistently; don't redefine (e.g. swipe-back, pinch-zoom) (Apple HIG)
95
+ - `system-gestures` - Don't block system gestures (Control Center, back swipe, etc.) (Apple HIG)
96
+ - `press-feedback` - Visual feedback on press (ripple/highlight; MD state layers)
97
+ - `haptic-feedback` - Use haptic for confirmations and important actions; avoid overuse (Apple HIG)
98
+ - `gesture-alternative` - Don't rely on gesture-only interactions; always provide visible controls for critical actions
99
+ - `safe-area-awareness` - Keep primary touch targets away from notch, Dynamic Island, gesture bar and screen edges
100
+ - `no-precision-required` - Avoid requiring pixel-perfect taps on small icons or thin edges
101
+ - `swipe-clarity` - Swipe actions must show clear affordance or hint (chevron, label, tutorial)
102
+ - `drag-threshold` - Use a movement threshold before starting drag to avoid accidental drags
103
+
104
+ ### 3. Performance (HIGH)
105
+
106
+ - `image-optimization` - Use WebP/AVIF, responsive images (srcset/sizes), lazy load non-critical assets
107
+ - `image-dimension` - Declare width/height or use aspect-ratio to prevent layout shift (Core Web Vitals: CLS)
108
+ - `font-loading` - Use font-display: swap/optional to avoid invisible text (FOIT); reserve space to reduce layout shift (MD)
109
+ - `font-preload` - Preload only critical fonts; avoid overusing preload on every variant
110
+ - `critical-css` - Prioritize above-the-fold CSS (inline critical CSS or early-loaded stylesheet)
111
+ - `lazy-loading` - Lazy load non-hero components via dynamic import / route-level splitting
112
+ - `bundle-splitting` - Split code by route/feature (React Suspense / Next.js dynamic) to reduce initial load and TTI
113
+ - `third-party-scripts` - Load third-party scripts async/defer; audit and remove unnecessary ones (MD)
114
+ - `reduce-reflows` - Avoid frequent layout reads/writes; batch DOM reads then writes
115
+ - `content-jumping` - Reserve space for async content to avoid layout jumps (Core Web Vitals: CLS)
116
+ - `lazy-load-below-fold` - Use loading="lazy" for below-the-fold images and heavy media
117
+ - `virtualize-lists` - Virtualize lists with 50+ items to improve memory efficiency and scroll performance
118
+ - `main-thread-budget` - Keep per-frame work under ~16ms for 60fps; move heavy tasks off main thread (HIG, MD)
119
+ - `progressive-loading` - Use skeleton screens / shimmer instead of long blocking spinners for >1s operations (Apple HIG)
120
+ - `input-latency` - Keep input latency under ~100ms for taps/scrolls (Material responsiveness standard)
121
+ - `tap-feedback-speed` - Provide visual feedback within 100ms of tap (Apple HIG)
122
+ - `debounce-throttle` - Use debounce/throttle for high-frequency events (scroll, resize, input)
123
+ - `offline-support` - Provide offline state messaging and basic fallback (PWA / mobile)
124
+ - `network-fallback` - Offer degraded modes for slow networks (lower-res images, fewer animations)
125
+
126
+ ### 4. Style Selection (HIGH)
127
+
128
+ - `style-match` - Match style to product type (use `--design-system` for recommendations)
129
+ - `consistency` - Use same style across all pages
130
+ - `no-emoji-icons` - Use SVG icons (Heroicons, Lucide), not emojis
131
+ - `color-palette-from-product` - Choose palette from product/industry (search `--domain color`)
132
+ - `effects-match-style` - Shadows, blur, radius aligned with chosen style (glass / flat / clay etc.)
133
+ - `platform-adaptive` - Respect platform idioms (iOS HIG vs Material): navigation, controls, typography, motion
134
+ - `state-clarity` - Make hover/pressed/disabled states visually distinct while staying on-style (Material state layers)
135
+ - `elevation-consistent` - Use a consistent elevation/shadow scale for cards, sheets, modals; avoid random shadow values
136
+ - `dark-mode-pairing` - Design light/dark variants together to keep brand, contrast, and style consistent
137
+ - `icon-style-consistent` - Use one icon set/visual language (stroke width, corner radius) across the product
138
+ - `system-controls` - Prefer native/system controls over fully custom ones; only customize when branding requires it (Apple HIG)
139
+ - `blur-purpose` - Use blur to indicate background dismissal (modals, sheets), not as decoration (Apple HIG)
140
+ - `primary-action` - Each screen should have only one primary CTA; secondary actions visually subordinate (Apple HIG)
141
+
142
+ ### 5. Layout & Responsive (HIGH)
143
+
144
+ - `viewport-meta` - width=device-width initial-scale=1 (never disable zoom)
145
+ - `mobile-first` - Design mobile-first, then scale up to tablet and desktop
146
+ - `breakpoint-consistency` - Use systematic breakpoints (e.g. 375 / 768 / 1024 / 1440)
147
+ - `readable-font-size` - Minimum 16px body text on mobile (avoids iOS auto-zoom)
148
+ - `line-length-control` - Mobile 35–60 chars per line; desktop 60–75 chars
149
+ - `horizontal-scroll` - No horizontal scroll on mobile; ensure content fits viewport width
150
+ - `spacing-scale` - Use 4pt/8dp incremental spacing system (Material Design)
151
+ - `touch-density` - Keep component spacing comfortable for touch: not cramped, not causing mis-taps
152
+ - `container-width` - Consistent max-width on desktop (max-w-6xl / 7xl)
153
+ - `z-index-management` - Define layered z-index scale (e.g. 0 / 10 / 20 / 40 / 100 / 1000)
154
+ - `fixed-element-offset` - Fixed navbar/bottom bar must reserve safe padding for underlying content
155
+ - `scroll-behavior` - Avoid nested scroll regions that interfere with the main scroll experience
156
+ - `viewport-units` - Prefer min-h-dvh over 100vh on mobile
157
+ - `orientation-support` - Keep layout readable and operable in landscape mode
158
+ - `content-priority` - Show core content first on mobile; fold or hide secondary content
159
+ - `visual-hierarchy` - Establish hierarchy via size, spacing, contrast β€” not color alone
160
+
161
+ ### 6. Typography & Color (MEDIUM)
162
+
163
+ - `line-height` - Use 1.5-1.75 for body text
164
+ - `line-length` - Limit to 65-75 characters per line
165
+ - `font-pairing` - Match heading/body font personalities
166
+ - `font-scale` - Consistent type scale (e.g. 12 14 16 18 24 32)
167
+ - `contrast-readability` - Darker text on light backgrounds (e.g. slate-900 on white)
168
+ - `text-styles-system` - Use platform type system: iOS 11 Dynamic Type styles / Material 5 type roles (display, headline, title, body, label) (HIG, MD)
169
+ - `weight-hierarchy` - Use font-weight to reinforce hierarchy: Bold headings (600–700), Regular body (400), Medium labels (500) (MD)
170
+ - `color-semantic` - Define semantic color tokens (primary, secondary, error, surface, on-surface) not raw hex in components (Material color system)
171
+ - `color-dark-mode` - Dark mode uses desaturated / lighter tonal variants, not inverted colors; test contrast separately (HIG, MD)
172
+ - `color-accessible-pairs` - Foreground/background pairs must meet 4.5:1 (AA) or 7:1 (AAA); use tools to verify (WCAG, MD)
173
+ - `color-not-decorative-only` - Functional color (error red, success green) must include icon/text; avoid color-only meaning (HIG, MD)
174
+ - `truncation-strategy` - Prefer wrapping over truncation; when truncating use ellipsis and provide full text via tooltip/expand (Apple HIG)
175
+ - `letter-spacing` - Respect default letter-spacing per platform; avoid tight tracking on body text (HIG, MD)
176
+ - `number-tabular` - Use tabular/monospaced figures for data columns, prices, and timers to prevent layout shift
177
+ - `whitespace-balance` - Use whitespace intentionally to group related items and separate sections; avoid visual clutter (Apple HIG)
178
+
179
+ ### 7. Animation (MEDIUM)
180
+
181
+ - `duration-timing` - Use 150–300ms for micro-interactions; complex transitions ≀400ms; avoid >500ms (MD)
182
+ - `transform-performance` - Use transform/opacity only; avoid animating width/height/top/left
183
+ - `loading-states` - Show skeleton or progress indicator when loading exceeds 300ms
184
+ - `excessive-motion` - Animate 1-2 key elements per view max
185
+ - `easing` - Use ease-out for entering, ease-in for exiting; avoid linear for UI transitions
186
+ - `motion-meaning` - Every animation must express a cause-effect relationship, not just be decorative (Apple HIG)
187
+ - `state-transition` - State changes (hover / active / expanded / collapsed / modal) should animate smoothly, not snap
188
+ - `continuity` - Page/screen transitions should maintain spatial continuity (shared element, directional slide) (Apple HIG)
189
+ - `parallax-subtle` - Use parallax sparingly; must respect reduced-motion and not cause disorientation (Apple HIG)
190
+ - `spring-physics` - Prefer spring/physics-based curves over linear or cubic-bezier for natural feel (Apple HIG fluid animations)
191
+ - `exit-faster-than-enter` - Exit animations shorter than enter (~60–70% of enter duration) to feel responsive (MD motion)
192
+ - `stagger-sequence` - Stagger list/grid item entrance by 30–50ms per item; avoid all-at-once or too-slow reveals (MD)
193
+ - `shared-element-transition` - Use shared element / hero transitions for visual continuity between screens (MD, HIG)
194
+ - `interruptible` - Animations must be interruptible; user tap/gesture cancels in-progress animation immediately (Apple HIG)
195
+ - `no-blocking-animation` - Never block user input during an animation; UI must stay interactive (Apple HIG)
196
+ - `fade-crossfade` - Use crossfade for content replacement within the same container (MD)
197
+ - `scale-feedback` - Subtle scale (0.95–1.05) on press for tappable cards/buttons; restore on release (HIG, MD)
198
+ - `gesture-feedback` - Drag, swipe, and pinch must provide real-time visual response tracking the finger (MD Motion)
199
+ - `hierarchy-motion` - Use translate/scale direction to express hierarchy: enter from below = deeper, exit upward = back (MD)
200
+ - `motion-consistency` - Unify duration/easing tokens globally; all animations share the same rhythm and feel
201
+ - `opacity-threshold` - Fading elements should not linger below opacity 0.2; either fade fully or remain visible
202
+ - `modal-motion` - Modals/sheets should animate from their trigger source (scale+fade or slide-in) for spatial context (HIG, MD)
203
+ - `navigation-direction` - Forward navigation animates left/up; backward animates right/down β€” keep direction logically consistent (HIG)
204
+ - `layout-shift-avoid` - Animations must not cause layout reflow or CLS; use transform for position changes
205
+
206
+ ### 8. Forms & Feedback (MEDIUM)
207
+
208
+ - `input-labels` - Visible label per input (not placeholder-only)
209
+ - `error-placement` - Show error below the related field
210
+ - `submit-feedback` - Loading then success/error state on submit
211
+ - `required-indicators` - Mark required fields (e.g. asterisk)
212
+ - `empty-states` - Helpful message and action when no content
213
+ - `toast-dismiss` - Auto-dismiss toasts in 3-5s
214
+ - `confirmation-dialogs` - Confirm before destructive actions
215
+ - `input-helper-text` - Provide persistent helper text below complex inputs, not just placeholder (Material Design)
216
+ - `disabled-states` - Disabled elements use reduced opacity (0.38–0.5) + cursor change + semantic attribute (MD)
217
+ - `progressive-disclosure` - Reveal complex options progressively; don't overwhelm users upfront (Apple HIG)
218
+ - `inline-validation` - Validate on blur (not keystroke); show error only after user finishes input (MD)
219
+ - `input-type-keyboard` - Use semantic input types (email, tel, number) to trigger the correct mobile keyboard (HIG, MD)
220
+ - `password-toggle` - Provide show/hide toggle for password fields (MD)
221
+ - `autofill-support` - Use autocomplete / textContentType attributes so the system can autofill (HIG, MD)
222
+ - `undo-support` - Allow undo for destructive or bulk actions (e.g. "Undo delete" toast) (Apple HIG)
223
+ - `success-feedback` - Confirm completed actions with brief visual feedback (checkmark, toast, color flash) (MD)
224
+ - `error-recovery` - Error messages must include a clear recovery path (retry, edit, help link) (HIG, MD)
225
+ - `multi-step-progress` - Multi-step flows show step indicator or progress bar; allow back navigation (MD)
226
+ - `form-autosave` - Long forms should auto-save drafts to prevent data loss on accidental dismissal (Apple HIG)
227
+ - `sheet-dismiss-confirm` - Confirm before dismissing a sheet/modal with unsaved changes (Apple HIG)
228
+ - `error-clarity` - Error messages must state cause + how to fix (not just "Invalid input") (HIG, MD)
229
+ - `field-grouping` - Group related fields logically (fieldset/legend or visual grouping) (MD)
230
+ - `read-only-distinction` - Read-only state should be visually and semantically different from disabled (MD)
231
+ - `focus-management` - After submit error, auto-focus the first invalid field (WCAG, MD)
232
+ - `error-summary` - For multiple errors, show summary at top with anchor links to each field (WCAG)
233
+ - `touch-friendly-input` - Mobile input height β‰₯44px to meet touch target requirements (Apple HIG)
234
+ - `destructive-emphasis` - Destructive actions use semantic danger color (red) and are visually separated from primary actions (HIG, MD)
235
+ - `toast-accessibility` - Toasts must not steal focus; use aria-live="polite" for screen reader announcement (WCAG)
236
+ - `aria-live-errors` - Form errors use aria-live region or role="alert" to notify screen readers (WCAG)
237
+ - `contrast-feedback` - Error and success state colors must meet 4.5:1 contrast ratio (WCAG, MD)
238
+ - `timeout-feedback` - Request timeout must show clear feedback with retry option (MD)
239
+
240
+ ### 9. Navigation Patterns (HIGH)
241
+
242
+ - `bottom-nav-limit` - Bottom navigation max 5 items; use labels with icons (Material Design)
243
+ - `drawer-usage` - Use drawer/sidebar for secondary navigation, not primary actions (Material Design)
244
+ - `back-behavior` - Back navigation must be predictable and consistent; preserve scroll/state (Apple HIG, MD)
245
+ - `deep-linking` - All key screens must be reachable via deep link / URL for sharing and notifications (Apple HIG, MD)
246
+ - `tab-bar-ios` - iOS: use bottom Tab Bar for top-level navigation (Apple HIG)
247
+ - `top-app-bar-android` - Android: use Top App Bar with navigation icon for primary structure (Material Design)
248
+ - `nav-label-icon` - Navigation items must have both icon and text label; icon-only nav harms discoverability (MD)
249
+ - `nav-state-active` - Current location must be visually highlighted (color, weight, indicator) in navigation (HIG, MD)
250
+ - `nav-hierarchy` - Primary nav (tabs/bottom bar) vs secondary nav (drawer/settings) must be clearly separated (MD)
251
+ - `modal-escape` - Modals and sheets must offer a clear close/dismiss affordance; swipe-down to dismiss on mobile (Apple HIG)
252
+ - `search-accessible` - Search must be easily reachable (top bar or tab); provide recent/suggested queries (MD)
253
+ - `breadcrumb-web` - Web: use breadcrumbs for 3+ level deep hierarchies to aid orientation (MD)
254
+ - `state-preservation` - Navigating back must restore previous scroll position, filter state, and input (HIG, MD)
255
+ - `gesture-nav-support` - Support system gesture navigation (iOS swipe-back, Android predictive back) without conflict (HIG, MD)
256
+ - `tab-badge` - Use badges on nav items sparingly to indicate unread/pending; clear after user visits (HIG, MD)
257
+ - `overflow-menu` - When actions exceed available space, use overflow/more menu instead of cramming (MD)
258
+ - `bottom-nav-top-level` - Bottom nav is for top-level screens only; never nest sub-navigation inside it (MD)
259
+ - `adaptive-navigation` - Large screens (β‰₯1024px) prefer sidebar; small screens use bottom/top nav (Material Adaptive)
260
+ - `back-stack-integrity` - Never silently reset the navigation stack or unexpectedly jump to home (HIG, MD)
261
+ - `navigation-consistency` - Navigation placement must stay the same across all pages; don't change by page type
262
+ - `avoid-mixed-patterns` - Don't mix Tab + Sidebar + Bottom Nav at the same hierarchy level
263
+ - `modal-vs-navigation` - Modals must not be used for primary navigation flows; they break the user's path (HIG)
264
+ - `focus-on-route-change` - After page transition, move focus to main content region for screen reader users (WCAG)
265
+ - `persistent-nav` - Core navigation must remain reachable from deep pages; don't hide it entirely in sub-flows (HIG, MD)
266
+ - `destructive-nav-separation` - Dangerous actions (delete account, logout) must be visually and spatially separated from normal nav items (HIG, MD)
267
+ - `empty-nav-state` - When a nav destination is unavailable, explain why instead of silently hiding it (MD)
268
+
269
+ ### 10. Charts & Data (LOW)
270
+
271
+ - `chart-type` - Match chart type to data type (trend β†’ line, comparison β†’ bar, proportion β†’ pie/donut)
272
+ - `color-guidance` - Use accessible color palettes; avoid red/green only pairs for colorblind users (WCAG, MD)
273
+ - `data-table` - Provide table alternative for accessibility; charts alone are not screen-reader friendly (WCAG)
274
+ - `pattern-texture` - Supplement color with patterns, textures, or shapes so data is distinguishable without color (WCAG, MD)
275
+ - `legend-visible` - Always show legend; position near the chart, not detached below a scroll fold (MD)
276
+ - `tooltip-on-interact` - Provide tooltips/data labels on hover (Web) or tap (mobile) showing exact values (HIG, MD)
277
+ - `axis-labels` - Label axes with units and readable scale; avoid truncated or rotated labels on mobile
278
+ - `responsive-chart` - Charts must reflow or simplify on small screens (e.g. horizontal bar instead of vertical, fewer ticks)
279
+ - `empty-data-state` - Show meaningful empty state when no data exists ("No data yet" + guidance), not a blank chart (MD)
280
+ - `loading-chart` - Use skeleton or shimmer placeholder while chart data loads; don't show an empty axis frame
281
+ - `animation-optional` - Chart entrance animations must respect prefers-reduced-motion; data should be readable immediately (HIG)
282
+ - `large-dataset` - For 1000+ data points, aggregate or sample; provide drill-down for detail instead of rendering all (MD)
283
+ - `number-formatting` - Use locale-aware formatting for numbers, dates, currencies on axes and labels (HIG, MD)
284
+ - `touch-target-chart` - Interactive chart elements (points, segments) must have β‰₯44pt tap area or expand on touch (Apple HIG)
285
+ - `no-pie-overuse` - Avoid pie/donut for >5 categories; switch to bar chart for clarity
286
+ - `contrast-data` - Data lines/bars vs background β‰₯3:1; data text labels β‰₯4.5:1 (WCAG)
287
+ - `legend-interactive` - Legends should be clickable to toggle series visibility (MD)
288
+ - `direct-labeling` - For small datasets, label values directly on the chart to reduce eye travel
289
+ - `tooltip-keyboard` - Tooltip content must be keyboard-reachable and not rely on hover alone (WCAG)
290
+ - `sortable-table` - Data tables must support sorting with aria-sort indicating current sort state (WCAG)
291
+ - `axis-readability` - Axis ticks must not be cramped; maintain readable spacing, auto-skip on small screens
292
+ - `data-density` - Limit information density per chart to avoid cognitive overload; split into multiple charts if needed
293
+ - `trend-emphasis` - Emphasize data trends over decoration; avoid heavy gradients/shadows that obscure the data
294
+ - `gridline-subtle` - Grid lines should be low-contrast (e.g. gray-200) so they don't compete with data
295
+ - `focusable-elements` - Interactive chart elements (points, bars, slices) must be keyboard-navigable (WCAG)
296
+ - `screen-reader-summary` - Provide a text summary or aria-label describing the chart's key insight for screen readers (WCAG)
297
+ - `error-state-chart` - Data load failure must show error message with retry action, not a broken/empty chart
298
+ - `export-option` - For data-heavy products, offer CSV/image export of chart data
299
+ - `drill-down-consistency` - Drill-down interactions must maintain a clear back-path and hierarchy breadcrumb
300
+ - `time-scale-clarity` - Time series charts must clearly label time granularity (day/week/month) and allow switching
301
+
302
+ ## How to Use
303
+
304
+ Search specific domains using the CLI tool below.
305
+
306
+ ---
307
+
308
+ ## Prerequisites
309
+
310
+ Check if Python is installed:
311
+
312
+ ```bash
313
+ python3 --version || python --version
314
+ ```
315
+
316
+ If Python is not installed, install it based on user's OS:
317
+
318
+ **macOS:**
319
+ ```bash
320
+ brew install python3
321
+ ```
322
+
323
+ **Ubuntu/Debian:**
324
+ ```bash
325
+ sudo apt update && sudo apt install python3
326
+ ```
327
+
328
+ **Windows:**
329
+ ```powershell
330
+ winget install Python.Python.3.12
331
+ ```
332
+
333
+ ---
334
+
335
+ ## How to Use This Skill
336
+
337
+ Use this skill when the user requests any of the following:
338
+
339
+ | Scenario | Trigger Examples | Start From |
340
+ |----------|-----------------|------------|
341
+ | **New project / page** | "Build a landing page", "Build a dashboard" | Step 1 β†’ Step 2 (design system) |
342
+ | **New component** | "Create a pricing card", "Add a modal" | Step 3 (domain search: style, ux) |
343
+ | **Choose style / color / font** | "What style fits a fintech app?", "Recommend a color palette" | Step 2 (design system) |
344
+ | **Review existing UI** | "Review this page for UX issues", "Check accessibility" | Quick Reference checklist above |
345
+ | **Fix a UI bug** | "Button hover is broken", "Layout shifts on load" | Quick Reference β†’ relevant section |
346
+ | **Improve / optimize** | "Make this faster", "Improve mobile experience" | Step 3 (domain search: ux, react) |
347
+ | **Implement dark mode** | "Add dark mode support" | Step 3 (domain: style "dark mode") |
348
+ | **Add charts / data viz** | "Add an analytics dashboard chart" | Step 3 (domain: chart) |
349
+ | **Stack best practices** | "React performance tips"、"SwiftUI navigation" | Step 4 (stack search) |
350
+
351
+ Follow this workflow:
352
+
353
+ ### Step 1: Analyze User Requirements
354
+
355
+ Extract key information from user request:
356
+ - **Product type**: Entertainment (social, video, music, gaming), Tool (scanner, editor, converter), Productivity (task manager, notes, calendar), or hybrid
357
+ - **Target audience**: C-end consumer users; consider age group, usage context (commute, leisure, work)
358
+ - **Style keywords**: playful, vibrant, minimal, dark mode, content-first, immersive, etc.
359
+ - **Stack**: React Native (this project's only tech stack)
360
+
361
+ ### Step 2: Generate Design System (REQUIRED)
362
+
363
+ **Always start with `--design-system`** to get comprehensive recommendations with reasoning:
364
+
365
+ ```bash
366
+ python3 skills/ui-ux-pro-max/scripts/search.py "<product_type> <industry> <keywords>" --design-system [-p "Project Name"]
367
+ ```
368
+
369
+ This command:
370
+ 1. Searches domains in parallel (product, style, color, landing, typography)
371
+ 2. Applies reasoning rules from `ui-reasoning.csv` to select best matches
372
+ 3. Returns complete design system: pattern, style, colors, typography, effects
373
+ 4. Includes anti-patterns to avoid
374
+
375
+ **Example:**
376
+ ```bash
377
+ python3 skills/ui-ux-pro-max/scripts/search.py "beauty spa wellness service" --design-system -p "Serenity Spa"
378
+ ```
379
+
380
+ ### Step 2b: Persist Design System (Master + Overrides Pattern)
381
+
382
+ To save the design system for **hierarchical retrieval across sessions**, add `--persist`:
383
+
384
+ ```bash
385
+ python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name"
386
+ ```
387
+
388
+ This creates:
389
+ - `design-system/MASTER.md` β€” Global Source of Truth with all design rules
390
+ - `design-system/pages/` β€” Folder for page-specific overrides
391
+
392
+ **With page-specific override:**
393
+ ```bash
394
+ python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name" --page "dashboard"
395
+ ```
396
+
397
+ This also creates:
398
+ - `design-system/pages/dashboard.md` β€” Page-specific deviations from Master
399
+
400
+ **How hierarchical retrieval works:**
401
+ 1. When building a specific page (e.g., "Checkout"), first check `design-system/pages/checkout.md`
402
+ 2. If the page file exists, its rules **override** the Master file
403
+ 3. If not, use `design-system/MASTER.md` exclusively
404
+
405
+ **Context-aware retrieval prompt:**
406
+ ```
407
+ I am building the [Page Name] page. Please read design-system/MASTER.md.
408
+ Also check if design-system/pages/[page-name].md exists.
409
+ If the page file exists, prioritize its rules.
410
+ If not, use the Master rules exclusively.
411
+ Now, generate the code...
412
+ ```
413
+
414
+ ### Step 3: Supplement with Detailed Searches (as needed)
415
+
416
+ After getting the design system, use domain searches to get additional details:
417
+
418
+ ```bash
419
+ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --domain <domain> [-n <max_results>]
420
+ ```
421
+
422
+ **When to use detailed searches:**
423
+
424
+ | Need | Domain | Example |
425
+ |------|--------|---------|
426
+ | Product type patterns | `product` | `--domain product "entertainment social"` |
427
+ | More style options | `style` | `--domain style "glassmorphism dark"` |
428
+ | Color palettes | `color` | `--domain color "entertainment vibrant"` |
429
+ | Font pairings | `typography` | `--domain typography "playful modern"` |
430
+ | Chart recommendations | `chart` | `--domain chart "real-time dashboard"` |
431
+ | UX best practices | `ux` | `--domain ux "animation accessibility"` |
432
+ | Alternative fonts | `typography` | `--domain typography "elegant luxury"` |
433
+ | Individual Google Fonts | `google-fonts` | `--domain google-fonts "sans serif popular variable"` |
434
+ | Landing structure | `landing` | `--domain landing "hero social-proof"` |
435
+ | React Native perf | `react` | `--domain react "rerender memo list"` |
436
+ | App interface a11y | `web` | `--domain web "accessibilityLabel touch safe-areas"` |
437
+ | AI prompt / CSS keywords | `prompt` | `--domain prompt "minimalism"` |
438
+
439
+ ### Step 4: Stack Guidelines (React Native)
440
+
441
+ Get React Native implementation-specific best practices:
442
+
443
+ ```bash
444
+ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
445
+ ```
446
+
447
+ ---
448
+
449
+ ## Search Reference
450
+
451
+ ### Available Domains
452
+
453
+ | Domain | Use For | Example Keywords |
454
+ |--------|---------|------------------|
455
+ | `product` | Product type recommendations | SaaS, e-commerce, portfolio, healthcare, beauty, service |
456
+ | `style` | UI styles, colors, effects | glassmorphism, minimalism, dark mode, brutalism |
457
+ | `typography` | Font pairings, Google Fonts | elegant, playful, professional, modern |
458
+ | `color` | Color palettes by product type | saas, ecommerce, healthcare, beauty, fintech, service |
459
+ | `landing` | Page structure, CTA strategies | hero, hero-centric, testimonial, pricing, social-proof |
460
+ | `chart` | Chart types, library recommendations | trend, comparison, timeline, funnel, pie |
461
+ | `ux` | Best practices, anti-patterns | animation, accessibility, z-index, loading |
462
+ | `google-fonts` | Individual Google Fonts lookup | sans serif, monospace, japanese, variable font, popular |
463
+ | `react` | React/Next.js performance | waterfall, bundle, suspense, memo, rerender, cache |
464
+ | `web` | App interface guidelines (iOS/Android/React Native) | accessibilityLabel, touch targets, safe areas, Dynamic Type |
465
+ | `prompt` | AI prompts, CSS keywords | (style name) |
466
+
467
+ ### Available Stacks
468
+
469
+ | Stack | Focus |
470
+ |-------|-------|
471
+ | `react-native` | Components, Navigation, Lists |
472
+
473
+ ---
474
+
475
+ ## Example Workflow
476
+
477
+ **User request:** "Make an AI search homepage."
478
+
479
+ ### Step 1: Analyze Requirements
480
+ - Product type: Tool (AI search engine)
481
+ - Target audience: C-end users looking for fast, intelligent search
482
+ - Style keywords: modern, minimal, content-first, dark mode
483
+ - Stack: React Native
484
+
485
+ ### Step 2: Generate Design System (REQUIRED)
486
+
487
+ ```bash
488
+ python3 skills/ui-ux-pro-max/scripts/search.py "AI search tool modern minimal" --design-system -p "AI Search"
489
+ ```
490
+
491
+ **Output:** Complete design system with pattern, style, colors, typography, effects, and anti-patterns.
492
+
493
+ ### Step 3: Supplement with Detailed Searches (as needed)
494
+
495
+ ```bash
496
+ # Get style options for a modern tool product
497
+ python3 skills/ui-ux-pro-max/scripts/search.py "minimalism dark mode" --domain style
498
+
499
+ # Get UX best practices for search interaction and loading
500
+ python3 skills/ui-ux-pro-max/scripts/search.py "search loading animation" --domain ux
501
+ ```
502
+
503
+ ### Step 4: Stack Guidelines
504
+
505
+ ```bash
506
+ python3 skills/ui-ux-pro-max/scripts/search.py "list performance navigation" --stack react-native
507
+ ```
508
+
509
+ **Then:** Synthesize design system + detailed searches and implement the design.
510
+
511
+ ---
512
+
513
+ ## Output Formats
514
+
515
+ The `--design-system` flag supports two output formats:
516
+
517
+ ```bash
518
+ # ASCII box (default) - best for terminal display
519
+ python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system
520
+
521
+ # Markdown - best for documentation
522
+ python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system -f markdown
523
+ ```
524
+
525
+ ---
526
+
527
+ ## Tips for Better Results
528
+
529
+ ### Query Strategy
530
+
531
+ - Use **multi-dimensional keywords** β€” combine product + industry + tone + density: `"entertainment social vibrant content-dense"` not just `"app"`
532
+ - Try different keywords for the same need: `"playful neon"` β†’ `"vibrant dark"` β†’ `"content-first minimal"`
533
+ - Use `--design-system` first for full recommendations, then `--domain` to deep-dive any dimension you're unsure about
534
+ - Always add `--stack react-native` for implementation-specific guidance
535
+
536
+ ### Common Sticking Points
537
+
538
+ | Problem | What to Do |
539
+ |---------|------------|
540
+ | Can't decide on style/color | Re-run `--design-system` with different keywords |
541
+ | Dark mode contrast issues | Quick Reference Β§6: `color-dark-mode` + `color-accessible-pairs` |
542
+ | Animations feel unnatural | Quick Reference Β§7: `spring-physics` + `easing` + `exit-faster-than-enter` |
543
+ | Form UX is poor | Quick Reference Β§8: `inline-validation` + `error-clarity` + `focus-management` |
544
+ | Navigation feels confusing | Quick Reference Β§9: `nav-hierarchy` + `bottom-nav-limit` + `back-behavior` |
545
+ | Layout breaks on small screens | Quick Reference Β§5: `mobile-first` + `breakpoint-consistency` |
546
+ | Performance / jank | Quick Reference Β§3: `virtualize-lists` + `main-thread-budget` + `debounce-throttle` |
547
+
548
+ ### Pre-Delivery Checklist
549
+
550
+ - Run `--domain ux "animation accessibility z-index loading"` as a UX validation pass before implementation
551
+ - Run through Quick Reference **Β§1–§3** (CRITICAL + HIGH) as a final review
552
+ - Test on 375px (small phone) and landscape orientation
553
+ - Verify behavior with **reduced-motion** enabled and **Dynamic Type** at largest size
554
+ - Check dark mode contrast independently (don't assume light mode values work)
555
+ - Confirm all touch targets β‰₯44pt and no content hidden behind safe areas
556
+
557
+ ---
558
+
559
+ ## Common Rules for Professional UI
560
+
561
+ These are frequently overlooked issues that make UI look unprofessional:
562
+ Scope notice: The rules below are for App UI (iOS/Android/React Native/Flutter), not desktop-web interaction patterns.
563
+
564
+ ### Icons & Visual Elements
565
+
566
+ | Rule | Standard | Avoid | Why It Matters |
567
+ |------|----------|--------|----------------|
568
+ | **No Emoji as Structural Icons** | Use vector-based icons (e.g., Lucide, react-native-vector-icons, @expo/vector-icons). | Using emojis (🎨 πŸš€ βš™οΈ) for navigation, settings, or system controls. | Emojis are font-dependent, inconsistent across platforms, and cannot be controlled via design tokens. |
569
+ | **Vector-Only Assets** | Use SVG or platform vector icons that scale cleanly and support theming. | Raster PNG icons that blur or pixelate. | Ensures scalability, crisp rendering, and dark/light mode adaptability. |
570
+ | **Stable Interaction States** | Use color, opacity, or elevation transitions for press states without changing layout bounds. | Layout-shifting transforms that move surrounding content or trigger visual jitter. | Prevents unstable interactions and preserves smooth motion/perceived quality on mobile. |
571
+ | **Correct Brand Logos** | Use official brand assets and follow their usage guidelines (spacing, color, clear space). | Guessing logo paths, recoloring unofficially, or modifying proportions. | Prevents brand misuse and ensures legal/platform compliance. |
572
+ | **Consistent Icon Sizing** | Define icon sizes as design tokens (e.g., icon-sm, icon-md = 24pt, icon-lg). | Mixing arbitrary values like 20pt / 24pt / 28pt randomly. | Maintains rhythm and visual hierarchy across the interface. |
573
+ | **Stroke Consistency** | Use a consistent stroke width within the same visual layer (e.g., 1.5px or 2px). | Mixing thick and thin stroke styles arbitrarily. | Inconsistent strokes reduce perceived polish and cohesion. |
574
+ | **Filled vs Outline Discipline** | Use one icon style per hierarchy level. | Mixing filled and outline icons at the same hierarchy level. | Maintains semantic clarity and stylistic coherence. |
575
+ | **Touch Target Minimum** | Minimum 44Γ—44pt interactive area (use hitSlop if icon is smaller). | Small icons without expanded tap area. | Meets accessibility and platform usability standards. |
576
+ | **Icon Alignment** | Align icons to text baseline and maintain consistent padding. | Misaligned icons or inconsistent spacing around them. | Prevents subtle visual imbalance that reduces perceived quality. |
577
+ | **Icon Contrast** | Follow WCAG contrast standards: 4.5:1 for small elements, 3:1 minimum for larger UI glyphs. | Low-contrast icons that blend into the background. | Ensures accessibility in both light and dark modes. |
578
+
579
+
580
+ ### Interaction (App)
581
+
582
+ | Rule | Do | Don't |
583
+ |------|----|----- |
584
+ | **Tap feedback** | Provide clear pressed feedback (ripple/opacity/elevation) within 80-150ms | No visual response on tap |
585
+ | **Animation timing** | Keep micro-interactions around 150-300ms with platform-native easing | Instant transitions or slow animations (>500ms) |
586
+ | **Accessibility focus** | Ensure screen reader focus order matches visual order and labels are descriptive | Unlabeled controls or confusing focus traversal |
587
+ | **Disabled state clarity** | Use disabled semantics (`disabled`/native disabled props), reduced emphasis, and no tap action | Controls that look tappable but do nothing |
588
+ | **Touch target minimum** | Keep tap areas >=44x44pt (iOS) or >=48x48dp (Android), expand hit area when icon is smaller | Tiny tap targets or icon-only hit areas without padding |
589
+ | **Gesture conflict prevention** | Keep one primary gesture per region and avoid nested tap/drag conflicts | Overlapping gestures causing accidental actions |
590
+ | **Semantic native controls** | Prefer native interactive primitives (`Button`, `Pressable`, platform equivalents) with proper accessibility roles | Generic containers used as primary controls without semantics |
591
+
592
+ ### Light/Dark Mode Contrast
593
+
594
+ | Rule | Do | Don't |
595
+ |------|----|----- |
596
+ | **Surface readability (light)** | Keep cards/surfaces clearly separated from background with sufficient opacity/elevation | Overly transparent surfaces that blur hierarchy |
597
+ | **Text contrast (light)** | Maintain body text contrast >=4.5:1 against light surfaces | Low-contrast gray body text |
598
+ | **Text contrast (dark)** | Maintain primary text contrast >=4.5:1 and secondary text >=3:1 on dark surfaces | Dark mode text that blends into background |
599
+ | **Border and divider visibility** | Ensure separators are visible in both themes (not just light mode) | Theme-specific borders disappearing in one mode |
600
+ | **State contrast parity** | Keep pressed/focused/disabled states equally distinguishable in light and dark themes | Defining interaction states for one theme only |
601
+ | **Token-driven theming** | Use semantic color tokens mapped per theme across app surfaces/text/icons | Hardcoded per-screen hex values |
602
+ | **Scrim and modal legibility** | Use a modal scrim strong enough to isolate foreground content (typically 40-60% black) | Weak scrim that leaves background visually competing |
603
+
604
+ ### Layout & Spacing
605
+
606
+ | Rule | Do | Don't |
607
+ |------|----|----- |
608
+ | **Safe-area compliance** | Respect top/bottom safe areas for all fixed headers, tab bars, and CTA bars | Placing fixed UI under notch, status bar, or gesture area |
609
+ | **System bar clearance** | Add spacing for status/navigation bars and gesture home indicator | Let tappable content collide with OS chrome |
610
+ | **Consistent content width** | Keep predictable content width per device class (phone/tablet) | Mixing arbitrary widths between screens |
611
+ | **8dp spacing rhythm** | Use a consistent 4/8dp spacing system for padding/gaps/section spacing | Random spacing increments with no rhythm |
612
+ | **Readable text measure** | Keep long-form text readable on large devices (avoid edge-to-edge paragraphs on tablets) | Full-width long text that hurts readability |
613
+ | **Section spacing hierarchy** | Define clear vertical rhythm tiers (e.g., 16/24/32/48) by hierarchy | Similar UI levels with inconsistent spacing |
614
+ | **Adaptive gutters by breakpoint** | Increase horizontal insets on larger widths and in landscape | Same narrow gutter on all device sizes/orientations |
615
+ | **Scroll and fixed element coexistence** | Add bottom/top content insets so lists are not hidden behind fixed bars | Scroll content obscured by sticky headers/footers |
616
+
617
+ ---
618
+
619
+ ## Pre-Delivery Checklist
620
+
621
+ Before delivering UI code, verify these items:
622
+ Scope notice: This checklist is for App UI (iOS/Android/React Native/Flutter).
623
+
624
+ ### Visual Quality
625
+ - [ ] No emojis used as icons (use SVG instead)
626
+ - [ ] All icons come from a consistent icon family and style
627
+ - [ ] Official brand assets are used with correct proportions and clear space
628
+ - [ ] Pressed-state visuals do not shift layout bounds or cause jitter
629
+ - [ ] Semantic theme tokens are used consistently (no ad-hoc per-screen hardcoded colors)
630
+
631
+ ### Interaction
632
+ - [ ] All tappable elements provide clear pressed feedback (ripple/opacity/elevation)
633
+ - [ ] Touch targets meet minimum size (>=44x44pt iOS, >=48x48dp Android)
634
+ - [ ] Micro-interaction timing stays in the 150-300ms range with native-feeling easing
635
+ - [ ] Disabled states are visually clear and non-interactive
636
+ - [ ] Screen reader focus order matches visual order, and interactive labels are descriptive
637
+ - [ ] Gesture regions avoid nested/conflicting interactions (tap/drag/back-swipe conflicts)
638
+
639
+ ### Light/Dark Mode
640
+ - [ ] Primary text contrast >=4.5:1 in both light and dark mode
641
+ - [ ] Secondary text contrast >=3:1 in both light and dark mode
642
+ - [ ] Dividers/borders and interaction states are distinguishable in both modes
643
+ - [ ] Modal/drawer scrim opacity is strong enough to preserve foreground legibility (typically 40-60% black)
644
+ - [ ] Both themes are tested before delivery (not inferred from a single theme)
645
+
646
+ ### Layout
647
+ - [ ] Safe areas are respected for headers, tab bars, and bottom CTA bars
648
+ - [ ] Scroll content is not hidden behind fixed/sticky bars
649
+ - [ ] Verified on small phone, large phone, and tablet (portrait + landscape)
650
+ - [ ] Horizontal insets/gutters adapt correctly by device size and orientation
651
+ - [ ] 4/8dp spacing rhythm is maintained across component, section, and page levels
652
+ - [ ] Long-form text measure remains readable on larger devices (no edge-to-edge paragraphs)
653
+
654
+ ### Accessibility
655
+ - [ ] All meaningful images/icons have accessibility labels
656
+ - [ ] Form fields have labels, hints, and clear error messages
657
+ - [ ] Color is not the only indicator
658
+ - [ ] Reduced motion and dynamic text size are supported without layout breakage
659
+ - [ ] Accessibility traits/roles/states (selected, disabled, expanded) are announced correctly
App/frontend/.agents/skills/ui-ux-pro-max/data ADDED
@@ -0,0 +1 @@
 
 
1
+ ../../../src/ui-ux-pro-max/data
App/frontend/.agents/skills/ui-ux-pro-max/scripts ADDED
@@ -0,0 +1 @@
 
 
1
+ ../../../src/ui-ux-pro-max/scripts
App/frontend/.gitignore ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ *.local
14
+
15
+ # Editor directories and files
16
+ .vscode/*
17
+ !.vscode/extensions.json
18
+ .idea
19
+ .DS_Store
20
+ *.suo
21
+ *.ntvs*
22
+ *.njsproj
23
+ *.sln
24
+ *.sw?
App/frontend/README.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # React + Vite
2
+
3
+ This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4
+
5
+ Currently, two official plugins are available:
6
+
7
+ - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
8
+ - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9
+
10
+ ## React Compiler
11
+
12
+ The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
13
+
14
+ ## Expanding the ESLint configuration
15
+
16
+ If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
App/frontend/eslint.config.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import { defineConfig, globalIgnores } from 'eslint/config'
6
+
7
+ export default defineConfig([
8
+ globalIgnores(['dist']),
9
+ {
10
+ files: ['**/*.{js,jsx}'],
11
+ extends: [
12
+ js.configs.recommended,
13
+ reactHooks.configs.flat.recommended,
14
+ reactRefresh.configs.vite,
15
+ ],
16
+ languageOptions: {
17
+ ecmaVersion: 2020,
18
+ globals: globals.browser,
19
+ parserOptions: {
20
+ ecmaVersion: 'latest',
21
+ ecmaFeatures: { jsx: true },
22
+ sourceType: 'module',
23
+ },
24
+ },
25
+ rules: {
26
+ 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
27
+ },
28
+ },
29
+ ])
App/frontend/index.html ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <link rel="icon" type="image/png" href="/logo.png" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
+ <meta name="theme-color" content="#ffffff" />
9
+ <meta name="description" content="An offline-first e-reader experience" />
10
+ <title>E-Reader</title>
11
+ <!-- Prevent theme flash: apply saved theme before React renders -->
12
+ <script>
13
+ (function () {
14
+ var t = localStorage.getItem('theme') || 'dark';
15
+ document.documentElement.setAttribute('data-theme', t);
16
+ })();
17
+ </script>
18
+ </head>
19
+
20
+ <body>
21
+ <div id="root"></div>
22
+ <script type="module" src="/src/main.jsx"></script>
23
+ </body>
24
+
25
+ </html>
App/frontend/package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
App/frontend/package.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "frontend",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "epubjs": "^0.3.93",
14
+ "localforage": "^1.10.0",
15
+ "lucide-react": "^0.575.0",
16
+ "react": "^19.2.0",
17
+ "react-dom": "^19.2.0"
18
+ },
19
+ "devDependencies": {
20
+ "@eslint/js": "^9.39.1",
21
+ "@types/react": "^19.2.7",
22
+ "@types/react-dom": "^19.2.3",
23
+ "@vitejs/plugin-react": "^5.1.1",
24
+ "eslint": "^9.39.1",
25
+ "eslint-plugin-react-hooks": "^7.0.1",
26
+ "eslint-plugin-react-refresh": "^0.4.24",
27
+ "globals": "^16.5.0",
28
+ "vite": "^7.3.1",
29
+ "vite-plugin-pwa": "^1.2.0"
30
+ }
31
+ }
App/frontend/public/eReaderLogo.png ADDED
App/frontend/public/logo.png ADDED
App/frontend/public/pwa-192x192.png ADDED
App/frontend/public/pwa-192x192.svg ADDED
App/frontend/public/pwa-512x512.png ADDED
App/frontend/public/pwa-512x512.svg ADDED
App/frontend/public/vite.svg ADDED
App/frontend/skills-lock.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": 1,
3
+ "skills": {
4
+ "ui-ux-pro-max": {
5
+ "source": "nextlevelbuilder/ui-ux-pro-max-skill",
6
+ "sourceType": "github",
7
+ "computedHash": "6337038fe1fe6bbe1b9f252ab678ee575859190bab6f0f246f4061824eb40875"
8
+ }
9
+ }
10
+ }
App/frontend/src/App.css ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #root {
2
+ max-width: 1280px;
3
+ margin: 0 auto;
4
+ padding: 2rem;
5
+ text-align: center;
6
+ }
7
+
8
+ .logo {
9
+ height: 6em;
10
+ padding: 1.5em;
11
+ will-change: filter;
12
+ transition: filter 300ms;
13
+ }
14
+ .logo:hover {
15
+ filter: drop-shadow(0 0 2em #646cffaa);
16
+ }
17
+ .logo.react:hover {
18
+ filter: drop-shadow(0 0 2em #61dafbaa);
19
+ }
20
+
21
+ @keyframes logo-spin {
22
+ from {
23
+ transform: rotate(0deg);
24
+ }
25
+ to {
26
+ transform: rotate(360deg);
27
+ }
28
+ }
29
+
30
+ @media (prefers-reduced-motion: no-preference) {
31
+ a:nth-of-type(2) .logo {
32
+ animation: logo-spin infinite 20s linear;
33
+ }
34
+ }
35
+
36
+ .card {
37
+ padding: 2em;
38
+ }
39
+
40
+ .read-the-docs {
41
+ color: #888;
42
+ }
App/frontend/src/App.jsx ADDED
@@ -0,0 +1,755 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react';
2
+ import ePub from 'epubjs';
3
+ import localforage from 'localforage';
4
+ import {
5
+ Play, Pause, SkipBack, SkipForward, FileText, Upload,
6
+ Settings, Search, BookOpen, ChevronLeft, Type,
7
+ Trash2, List, Bookmark, ChevronDown
8
+ } from 'lucide-react';
9
+
10
+ /* ─── PWA ─── */
11
+ import { useRegisterSW } from 'virtual:pwa-register/react';
12
+
13
+ /* ─── Components ─── */
14
+ import Sidebar from './components/Sidebar';
15
+ import SettingsPanel from './components/SettingsPanel';
16
+ import ReaderParagraph from './components/ReaderParagraph';
17
+ import AudioDock from './components/AudioDock';
18
+ import TOCPopover from './components/TOCPopover';
19
+ import BookmarksPopover from './components/BookmarksPopover';
20
+
21
+ /* ─── Utils ─── */
22
+ import {
23
+ splitTextIntoChunks,
24
+ extractChunksFromEpubDoc,
25
+ calculateReadingTime
26
+ } from './utils/epubHelpers';
27
+ import './index.css';
28
+
29
+ // Worker instance
30
+ const parsingWorker = new Worker(new URL('./workers/parsingWorker.js', import.meta.url));
31
+
32
+ // Configure storage
33
+ localforage.config({ name: 'E-Reader', storeName: 'library' });
34
+
35
+ function App() {
36
+ const [view, setView] = useState('library');
37
+ const [books, setBooks] = useState([]);
38
+ const [libraryLoaded, setLibraryLoaded] = useState(false);
39
+ const [activeBookIndex, setActiveBookIndex] = useState(null);
40
+ const [chunks, setChunks] = useState([]);
41
+ const [currentChunkIndex, setCurrentChunkIndex] = useState(0);
42
+ const [isPlaying, setIsPlaying] = useState(false);
43
+ const [loadingAudio, setLoadingAudio] = useState(false);
44
+ const [audioCache, setAudioCache] = useState({}); // { index: { url } }
45
+ const [serverReady, setServerReady] = useState(false);
46
+
47
+ // User Preferences
48
+ const [theme, setTheme] = useState(() => localStorage.getItem('theme') || 'auto');
49
+ const [speechRate, setSpeechRate] = useState(1.0);
50
+ const [piperVoice, setPiperVoice] = useState('en_US-lessac-low');
51
+ const [piperSpeaker, setPiperSpeaker] = useState(0);
52
+ const [readingFont, setReadingFont] = useState(() => localStorage.getItem('readingFont') || 'serif');
53
+ const [readingSpacing, setReadingSpacing] = useState(() => localStorage.getItem('readingSpacing') || 'normal');
54
+ const [highlightColor, setHighlightColor] = useState(() => localStorage.getItem('highlightColor') || '#fcff82');
55
+
56
+ // UI States
57
+ const [showSettings, setShowSettings] = useState(false);
58
+ const [showTOC, setShowTOC] = useState(false);
59
+ const [showBookmarks, setShowBookmarks] = useState(false);
60
+ const [showSortMenu, setShowSortMenu] = useState(false);
61
+ const [librarySearchQuery, setLibrarySearchQuery] = useState('');
62
+ const [librarySortOption, setLibrarySortOption] = useState('recently-read');
63
+
64
+ // Handle outside clicks for menus
65
+ useEffect(() => {
66
+ const handleOutsideClick = (e) => {
67
+ if (!e.target.closest('.sort-dropdown-container')) {
68
+ setShowSortMenu(false);
69
+ }
70
+ };
71
+ window.addEventListener('click', handleOutsideClick);
72
+ return () => window.removeEventListener('click', handleOutsideClick);
73
+ }, []);
74
+
75
+ // Refs
76
+ const audioRef = useRef(new Audio());
77
+ const fileInputRef = useRef(null);
78
+ const activeParagraphRef = useRef(null);
79
+ const searchInputRef = useRef(null);
80
+ const viewRef = useRef(view);
81
+ const isPlayingRef = useRef(isPlaying);
82
+ const lastSavedBooksRef = useRef(null);
83
+
84
+ useEffect(() => { viewRef.current = view; }, [view]);
85
+ useEffect(() => { isPlayingRef.current = isPlaying; }, [isPlaying]);
86
+
87
+ // Initial Load
88
+ useEffect(() => {
89
+ let mounts = true;
90
+ async function init() {
91
+ try {
92
+ const [savedBooks, savedRate, savedVoice, savedSpeaker] = await Promise.all([
93
+ localforage.getItem('books'),
94
+ localStorage.getItem('speechRate'),
95
+ localStorage.getItem('piperVoice'),
96
+ localStorage.getItem('piperSpeaker')
97
+ ]);
98
+ if (mounts) {
99
+ if (savedBooks) setBooks(savedBooks);
100
+ if (savedRate) setSpeechRate(parseFloat(savedRate));
101
+ if (savedVoice) setPiperVoice(savedVoice);
102
+ if (savedSpeaker) setPiperSpeaker(parseInt(savedSpeaker));
103
+ setLibraryLoaded(true);
104
+ }
105
+ } catch (e) { console.error(e); }
106
+ }
107
+ init();
108
+ return () => { mounts = false; };
109
+ }, []);
110
+
111
+ // Warm up the backend immediately so it's ready when user presses Play
112
+ useEffect(() => {
113
+ const apiUrl = import.meta.env.VITE_API_URL || '';
114
+ fetch(`${apiUrl}/warmup`)
115
+ .then(() => setServerReady(true))
116
+ .catch(() => setServerReady(true)); // Don't block UI even if warmup fails
117
+ }, []);
118
+
119
+ // Sync to Storage
120
+ useEffect(() => {
121
+ if (libraryLoaded && books !== lastSavedBooksRef.current) {
122
+ const timeout = setTimeout(() => {
123
+ localforage.setItem('books', books).catch(e => console.error(e));
124
+ lastSavedBooksRef.current = books;
125
+ }, 2000);
126
+ return () => clearTimeout(timeout);
127
+ }
128
+ }, [books, libraryLoaded]);
129
+
130
+ // Handle Position Update
131
+ useEffect(() => {
132
+ if (activeBookIndex !== null && libraryLoaded && books[activeBookIndex]) {
133
+ setBooks(prev => {
134
+ if (prev[activeBookIndex].lastPosition === currentChunkIndex) return prev;
135
+ const nb = [...prev];
136
+ nb[activeBookIndex] = { ...nb[activeBookIndex], lastPosition: currentChunkIndex };
137
+ return nb;
138
+ });
139
+ }
140
+ }, [currentChunkIndex]);
141
+
142
+ // Global Styles
143
+ useEffect(() => {
144
+ const applyTheme = (t) => {
145
+ if (t === 'auto') {
146
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
147
+ document.documentElement.setAttribute('data-theme', prefersDark ? 'dark' : 'light');
148
+ } else {
149
+ document.documentElement.setAttribute('data-theme', t);
150
+ }
151
+ };
152
+ applyTheme(theme);
153
+ localStorage.setItem('theme', theme);
154
+ }, [theme]);
155
+
156
+ useEffect(() => {
157
+ const fontMap = {
158
+ serif: "'Playfair Display', Georgia, serif",
159
+ sans: "'Instrument Sans', system-ui, sans-serif",
160
+ georgia: "Georgia, 'Times New Roman', serif",
161
+ mono: "'Courier New', Courier, monospace"
162
+ };
163
+ document.documentElement.style.setProperty('--reader-font', fontMap[readingFont] || fontMap.serif);
164
+ localStorage.setItem('readingFont', readingFont);
165
+ }, [readingFont]);
166
+
167
+ useEffect(() => {
168
+ document.documentElement.style.setProperty('--highlight-color', highlightColor);
169
+ localStorage.setItem('highlightColor', highlightColor);
170
+ }, [highlightColor]);
171
+
172
+ useEffect(() => {
173
+ const spacingMap = {
174
+ compact: { lh: '1.6', ls: '-0.01em', ps: '1.2rem' },
175
+ normal: { lh: '2.0', ls: '0em', ps: '1.85rem' },
176
+ relaxed: { lh: '2.4', ls: '0.01em', ps: '2.4rem' },
177
+ spacious: { lh: '2.8', ls: '0.02em', ps: '3rem' }
178
+ };
179
+ const s = spacingMap[readingSpacing] || spacingMap.normal;
180
+ document.documentElement.style.setProperty('--reader-line-height', s.lh);
181
+ document.documentElement.style.setProperty('--reader-letter-spacing', s.ls);
182
+ document.documentElement.style.setProperty('--reader-para-spacing', s.ps);
183
+ localStorage.setItem('readingSpacing', readingSpacing);
184
+ }, [readingSpacing]);
185
+
186
+ // Playback Logic
187
+ const prefetchNextChunks = async (currentIndex) => {
188
+ const PREFETCH_COUNT = 2;
189
+ const apiUrl = import.meta.env.VITE_API_URL || '';
190
+
191
+ for (let i = 1; i <= PREFETCH_COUNT; i++) {
192
+ const idx = currentIndex + i;
193
+ if (idx >= chunks.length || audioCache[idx]) continue;
194
+
195
+ const chunk = chunks[idx];
196
+ const text = typeof chunk === 'string' ? chunk : chunk.text;
197
+
198
+ // Fire and forget fetch
199
+ fetch(`${apiUrl}/synthesize`, {
200
+ method: 'POST',
201
+ headers: { 'Content-Type': 'application/json' },
202
+ body: JSON.stringify({ text, voice_id: piperVoice, speaker_id: piperSpeaker })
203
+ }).then(async (resp) => {
204
+ if (resp.ok) {
205
+ const blob = await resp.blob();
206
+ const url = URL.createObjectURL(blob);
207
+ setAudioCache(prev => ({ ...prev, [idx]: { url, blob } }));
208
+ }
209
+ }).catch(err => console.error("Prefetch error:", err));
210
+ }
211
+ };
212
+
213
+ const playCurrentChunk = async () => {
214
+ const chunk = chunks[currentChunkIndex];
215
+ if (!chunk) return;
216
+ const text = typeof chunk === 'string' ? chunk : chunk.text;
217
+
218
+ audioRef.current.pause();
219
+
220
+ // Check Cache first
221
+ if (audioCache[currentChunkIndex]) {
222
+ const { url } = audioCache[currentChunkIndex];
223
+ if (viewRef.current === 'reader' && isPlayingRef.current) {
224
+ audioRef.current.src = url;
225
+ audioRef.current.playbackRate = speechRate;
226
+ await audioRef.current.play();
227
+ prefetchNextChunks(currentChunkIndex); // Always try to keep buffer full
228
+ }
229
+ return;
230
+ }
231
+
232
+ setLoadingAudio(true);
233
+ try {
234
+ const apiUrl = import.meta.env.VITE_API_URL || '';
235
+ const resp = await fetch(`${apiUrl}/synthesize`, {
236
+ method: 'POST',
237
+ headers: { 'Content-Type': 'application/json' },
238
+ body: JSON.stringify({ text, voice_id: piperVoice, speaker_id: piperSpeaker })
239
+ });
240
+ if (!resp.ok) throw new Error("Synthesis failed");
241
+ const blob = await resp.blob();
242
+ const url = URL.createObjectURL(blob);
243
+
244
+ // Save to cache
245
+ setAudioCache(prev => ({ ...prev, [currentChunkIndex]: { url, blob } }));
246
+
247
+ if (viewRef.current === 'reader' && isPlayingRef.current) {
248
+ audioRef.current.src = url;
249
+ audioRef.current.playbackRate = speechRate;
250
+ await audioRef.current.play();
251
+ prefetchNextChunks(currentChunkIndex);
252
+ }
253
+ } catch (err) { console.error(err); setIsPlaying(false); }
254
+ finally { setLoadingAudio(false); }
255
+ };
256
+
257
+ const goToNextChunk = useCallback(() => {
258
+ setCurrentChunkIndex(prev => {
259
+ if (prev < chunks.length - 1) return prev + 1;
260
+ setIsPlaying(false);
261
+ return prev;
262
+ });
263
+ }, [chunks.length]);
264
+
265
+ useEffect(() => {
266
+ const audio = audioRef.current;
267
+ const handled = () => goToNextChunk();
268
+ audio.addEventListener('ended', handled);
269
+ return () => audio.removeEventListener('ended', handled);
270
+ }, [goToNextChunk]);
271
+
272
+ useEffect(() => {
273
+ audioRef.current.playbackRate = speechRate;
274
+ }, [speechRate]);
275
+
276
+ useEffect(() => {
277
+ if (isPlaying && chunks.length > 0) {
278
+ playCurrentChunk();
279
+ // Redirect to active paragraph when starting playback
280
+ if (activeParagraphRef.current) {
281
+ activeParagraphRef.current.scrollIntoView({ behavior: 'smooth', block: 'center' });
282
+ }
283
+ }
284
+ }, [isPlaying]);
285
+
286
+ useEffect(() => {
287
+ if (isPlaying && chunks.length > 0) {
288
+ playCurrentChunk();
289
+ }
290
+ // Auto-scroll to active paragraph on chunk change
291
+ if (activeParagraphRef.current) {
292
+ activeParagraphRef.current.scrollIntoView({ behavior: 'smooth', block: 'center' });
293
+ }
294
+ }, [currentChunkIndex]);
295
+
296
+ const handlePlayPause = () => {
297
+ if (chunks.length === 0) return;
298
+ if (isPlaying) {
299
+ setIsPlaying(false);
300
+ audioRef.current.pause();
301
+ } else {
302
+ setIsPlaying(true);
303
+ // The useEffect on currentChunkIndex will handle playCurrentChunk()
304
+ // but only if currentChunkIndex actually changed. We call it here manually
305
+ // if it's the first time playing or a resume.
306
+ if (!audioRef.current.src || audioRef.current.src === '' || audioRef.current.ended) {
307
+ playCurrentChunk();
308
+ } else {
309
+ audioRef.current.play().catch(() => playCurrentChunk());
310
+ }
311
+ }
312
+ };
313
+
314
+ const handleParagraphClick = useCallback((idx) => {
315
+ if (idx === currentChunkIndex) {
316
+ handlePlayPause();
317
+ } else {
318
+ setCurrentChunkIndex(idx);
319
+ if (!isPlaying) setIsPlaying(true);
320
+ }
321
+ }, [isPlaying, currentChunkIndex]);
322
+
323
+ // Actions
324
+ const openBook = (idx) => {
325
+ const ub = [...books];
326
+ ub[idx] = { ...ub[idx], lastOpened: Date.now() };
327
+ setBooks(ub);
328
+
329
+ setActiveBookIndex(idx);
330
+ setChunks(ub[idx].chunks);
331
+ setAudioCache({}); // Clear cache for new book
332
+ setCurrentChunkIndex(ub[idx].lastPosition || 0);
333
+ setIsPlaying(false);
334
+ audioRef.current.pause();
335
+ setView('reader');
336
+ };
337
+
338
+ const removeBook = (e, idx) => {
339
+ e.stopPropagation();
340
+ setBooks(prev => prev.filter((_, i) => i !== idx));
341
+ };
342
+
343
+ const toggleBookmark = () => {
344
+ if (activeBookIndex === null) return;
345
+ const ub = [...books];
346
+ const b = ub[activeBookIndex];
347
+ if (!b.bookmarks) b.bookmarks = [];
348
+ const existing = b.bookmarks.findIndex(x => x.chunkIndex === currentChunkIndex);
349
+ if (existing !== -1) {
350
+ b.bookmarks.splice(existing, 1);
351
+ } else {
352
+ let preview = '';
353
+ if (chunks[currentChunkIndex]) {
354
+ const t = typeof chunks[currentChunkIndex] === 'string' ? chunks[currentChunkIndex] : chunks[currentChunkIndex].text;
355
+ preview = t.substring(0, 45) + '...';
356
+ }
357
+ b.bookmarks.push({ chunkIndex: currentChunkIndex, timestamp: Date.now(), preview });
358
+ b.bookmarks.sort((a, b) => a.chunkIndex - b.chunkIndex);
359
+ }
360
+ setBooks(ub);
361
+ };
362
+
363
+ // PWA Registration
364
+ const {
365
+ offlineReady: [offlineReady, setOfflineReady],
366
+ needRefresh: [needRefresh, setNeedRefresh],
367
+ updateServiceWorker,
368
+ } = useRegisterSW();
369
+
370
+ useEffect(() => {
371
+ localStorage.setItem('piperVoice', piperVoice);
372
+ localStorage.setItem('piperSpeaker', piperSpeaker.toString());
373
+ localStorage.setItem('speechRate', speechRate.toString());
374
+
375
+ // Clear cache if voice settings change significantly
376
+ setAudioCache({});
377
+
378
+ // Auto-re-play if voice changes while reading
379
+ if (isPlaying && chunks.length > 0) {
380
+ playCurrentChunk();
381
+ }
382
+ }, [piperVoice, piperSpeaker, speechRate]);
383
+
384
+ // Handle Worker Response
385
+ useEffect(() => {
386
+ parsingWorker.onmessage = (e) => {
387
+ if (e.data.type === 'PARSE_COMPLETE') {
388
+ const { segments, chunks: txtChunks, title } = e.data;
389
+
390
+ setBooks(prev => {
391
+ const updated = [...prev];
392
+ if (!updated[0] || !updated[0].isParsing) return prev;
393
+
394
+ let finalChunks = [];
395
+ if (segments) {
396
+ // EPUB: Calculate start index for each spine segment
397
+ let currentOffset = 0;
398
+ const segmentStarts = segments.map(seg => {
399
+ const start = currentOffset;
400
+ currentOffset += seg.length;
401
+ return start;
402
+ });
403
+
404
+ finalChunks = segments.flat();
405
+
406
+ // Link TOC to chunks using spineIndex
407
+ const toc = updated[0].toc || [];
408
+ const mappedTOC = toc.map(item => ({
409
+ ...item,
410
+ chunkIndex: segmentStarts[item.spineIndex] || 0
411
+ }));
412
+
413
+ updated[0] = { ...updated[0], chunks: finalChunks, toc: mappedTOC, isParsing: false };
414
+ } else {
415
+ // TXT logic
416
+ updated[0] = { ...updated[0], chunks: txtChunks, isParsing: false, title: title || updated[0].title };
417
+ }
418
+ return updated;
419
+ });
420
+ }
421
+ };
422
+ }, []);
423
+
424
+ // EPUB Upload
425
+ const handleFileUpload = async (e) => {
426
+ const file = e.target.files[0];
427
+ if (!file) return;
428
+
429
+ const placeholderId = Date.now().toString();
430
+ const nb = {
431
+ id: placeholderId, title: file.name.replace(/\.[^/.]+$/, ""), author: "Parsing...", chunks: [], isParsing: true,
432
+ lastPosition: 0, lastOpened: Date.now(), coverBase64: null, toc: [], bookmarks: []
433
+ };
434
+ setBooks(prev => [nb, ...prev]);
435
+
436
+ if (file.name.endsWith('.txt')) {
437
+ const text = await file.text();
438
+ parsingWorker.postMessage({ type: 'PARSE_TXT', content: text, fileName: file.name });
439
+ } else if (file.name.endsWith('.epub')) {
440
+ const book = ePub(file);
441
+ await book.ready;
442
+ let coverBase64 = null, toc = [], extractedTitle = "", extractedAuthor = "", spinePaths = [];
443
+ try {
444
+ const metadata = await book.loaded.metadata;
445
+ extractedTitle = metadata.title;
446
+ extractedAuthor = metadata.creator;
447
+ const cu = await book.coverUrl();
448
+ if (cu) {
449
+ const resp = await fetch(cu);
450
+ const blob = await resp.blob();
451
+ coverBase64 = await new Promise(r => {
452
+ const fr = new FileReader();
453
+ fr.onloadend = () => r(fr.result);
454
+ fr.readAsDataURL(blob);
455
+ });
456
+ }
457
+ const nav = await book.loaded.navigation;
458
+ const flattoc = (items) => {
459
+ items.forEach(item => {
460
+ // Aggressive spine matching for robust TOC mapping
461
+ const cleanHref = item.href.split('#')[0];
462
+ let spineIndex = -1;
463
+
464
+ // Try Epubjs native get
465
+ const nativeMatch = book.spine.get(item.href);
466
+ if (nativeMatch) {
467
+ spineIndex = nativeMatch.index;
468
+ } else {
469
+ // Fallback to searching spine items by partial path
470
+ spineIndex = book.spine.spineItems.findIndex(si =>
471
+ si.href === cleanHref ||
472
+ si.href.endsWith('/' + cleanHref) ||
473
+ cleanHref.endsWith('/' + si.href)
474
+ );
475
+ }
476
+
477
+ toc.push({
478
+ label: item.label.trim(),
479
+ href: item.href,
480
+ spineIndex: spineIndex >= 0 ? spineIndex : 0
481
+ });
482
+ if (item.subitems) flattoc(item.subitems);
483
+ });
484
+ };
485
+ flattoc(nav.toc || []);
486
+
487
+ const spineSegments = [];
488
+ for (const item of book.spine.spineItems) {
489
+ spinePaths.push(item.href);
490
+ const doc = await book.load(item.href);
491
+ spineSegments.push(doc.body.innerHTML);
492
+ }
493
+
494
+ setBooks(prev => {
495
+ const u = [...prev];
496
+ if (u[0] && u[0].id === placeholderId) {
497
+ u[0] = { ...u[0], title: extractedTitle, author: extractedAuthor, coverBase64, toc, spinePaths };
498
+ }
499
+ return u;
500
+ });
501
+
502
+ parsingWorker.postMessage({ type: 'PARSE_HTML_SEGMENTS', content: spineSegments });
503
+ } catch (err) { console.error(err); }
504
+ }
505
+ };
506
+
507
+ // Keyboard Shortcuts
508
+ useEffect(() => {
509
+ const handleKD = (e) => {
510
+ if (document.activeElement.tagName === 'INPUT') return;
511
+ if (e.key === ' ' && view === 'reader') { e.preventDefault(); handlePlayPause(); }
512
+ if (e.key === 'ArrowRight' && view === 'reader') setCurrentChunkIndex(p => Math.min(chunks.length - 1, p + 1));
513
+ if (e.key === 'ArrowLeft' && view === 'reader') setCurrentChunkIndex(p => Math.max(0, p - 1));
514
+ if (e.key === '/' && view === 'library') { e.preventDefault(); searchInputRef.current?.focus(); }
515
+ };
516
+ window.addEventListener('keydown', handleKD);
517
+ return () => window.removeEventListener('keydown', handleKD);
518
+ }, [view, chunks.length, isPlaying]);
519
+
520
+ // Memoized lists
521
+ const filteredBooks = useMemo(() => {
522
+ let list = books.map((b, i) => ({ ...b, originalIndex: i }))
523
+ .filter(b => (b.title + b.author).toLowerCase().includes(librarySearchQuery.toLowerCase()));
524
+ if (librarySortOption === 'recently-read') list.sort((a,b) => (b.lastOpened||0) - (a.lastOpened||0));
525
+ else if (librarySortOption === 'title-asc') list.sort((a,b) => (a.title||'').localeCompare(b.title||''));
526
+ return list;
527
+ }, [books, librarySearchQuery, librarySortOption]);
528
+
529
+ const activeBook = activeBookIndex !== null ? books[activeBookIndex] : null;
530
+
531
+ if (!libraryLoaded) return <div className="loading-screen"><div className="spinner"/></div>;
532
+
533
+ return (
534
+ <div className="app-container">
535
+ {view === 'library' && (
536
+ <React.Fragment>
537
+ <Sidebar
538
+ view={view} setView={setView} activeBook={activeBook}
539
+ onLogoClick={() => { setView('library'); audioRef.current.pause(); setIsPlaying(false); }}
540
+ searchQuery={librarySearchQuery} onSearchChange={e => setLibrarySearchQuery(e.target.value)} searchRef={searchInputRef}
541
+ piperVoice={piperVoice} onVoiceChange={e => setPiperVoice(e.target.value)}
542
+ speechRate={speechRate} onRateChange={e => setSpeechRate(parseFloat(e.target.value))}
543
+ showSettings={showSettings} setShowSettings={setShowSettings}
544
+ />
545
+ <main className="main-content page-enter">
546
+ <header className="header" style={{ padding: '0 3.5rem' }}>
547
+ <div className="header-title">Library</div>
548
+ <div className="header-actions">
549
+ {!serverReady && (
550
+ <span style={{ fontSize: '11px', color: 'var(--text-muted)', letterSpacing: '0.05em', display: 'flex', alignItems: 'center', gap: '6px', marginRight: '1rem' }}>
551
+ <span style={{ width: 6, height: 6, borderRadius: '50%', background: '#f59e0b', display: 'inline-block', animation: 'pulse 1.5s infinite' }} />
552
+ Connecting to voice server…
553
+ </span>
554
+ )}
555
+ <span className="book-count">
556
+ {books.length} {books.length === 1 ? 'BOOK' : 'BOOKS'}
557
+ </span>
558
+
559
+ <div style={{ position: 'relative' }} className="sort-dropdown-container">
560
+ <button
561
+ className={`btn-text ${showSortMenu ? 'active' : ''}`}
562
+ onClick={(e) => { e.stopPropagation(); setShowSortMenu(!showSortMenu); }}
563
+ aria-label="Change Sort Order"
564
+ title="Change Sort Order"
565
+ style={{ marginRight: '1rem' }}
566
+ >
567
+ {librarySortOption === 'recently-read' ? "Recently Read" : "Alphabetical (A-Z)"}
568
+ <ChevronDown size={14} style={{ marginLeft: '6px', opacity: 0.5 }} />
569
+ </button>
570
+
571
+ {showSortMenu && (
572
+ <div
573
+ className="dropdown-menu glass"
574
+ style={{ position: 'absolute', top: 'calc(100% + 8px)', right: 0, zIndex: 100, minWidth: '180px', padding: '0.5rem', animation: 'dropdownEnter 0.2s ease-out' }}
575
+ onClick={e => e.stopPropagation()}
576
+ >
577
+ <button
578
+ className={`dropdown-item ${librarySortOption === 'recently-read' ? 'active' : ''}`}
579
+ onClick={() => { setLibrarySortOption('recently-read'); setShowSortMenu(false); }}
580
+ >
581
+ Recently Read
582
+ </button>
583
+ <button
584
+ className={`dropdown-item ${librarySortOption === 'title-asc' ? 'active' : ''}`}
585
+ onClick={() => { setLibrarySortOption('title-asc'); setShowSortMenu(false); }}
586
+ >
587
+ Alphabetical (A-Z)
588
+ </button>
589
+ </div>
590
+ )}
591
+ </div>
592
+
593
+ <button className="btn-text" onClick={() => fileInputRef.current?.click()}><Upload size={14}/> Import</button>
594
+ <input type="file" ref={fileInputRef} onChange={handleFileUpload} style={{ display: 'none' }} accept=".txt,.epub" />
595
+ </div>
596
+ </header>
597
+
598
+ {filteredBooks.length === 0 ? (
599
+ <div className="empty-library">
600
+ <BookOpen size={48} style={{ marginBottom: '1.5rem', color: 'var(--text-muted)' }} />
601
+ <h3 style={{ marginBottom: '0.5rem', fontFamily: 'var(--font-display)', fontStyle: 'italic', fontSize: '1.5rem' }}>Your Library is Empty</h3>
602
+ <p style={{ color: 'var(--text-secondary)', maxWidth: '300px', textAlign: 'center' }}>
603
+ Import EPUB or TXT files to start reading and listening.
604
+ </p>
605
+ </div>
606
+ ) : (
607
+ <div className="library-grid">
608
+ {filteredBooks.map(book => {
609
+ const progressPct = book.chunks.length > 0 ? Math.floor(((book.lastPosition || 0) / book.chunks.length) * 100) : 0;
610
+ const remainingChunks = book.chunks.length - (book.lastPosition || 0);
611
+ const remainingTime = calculateReadingTime(remainingChunks, speechRate);
612
+
613
+ return (
614
+ <div
615
+ key={book.id}
616
+ className={`book-card ${book.isParsing ? 'is-parsing' : ''}`}
617
+ onClick={() => !book.isParsing && openBook(book.originalIndex)}
618
+ >
619
+ <div className="book-cover" style={{ backgroundImage: book.coverBase64 ? `url(${book.coverBase64})` : 'none', backgroundSize: 'cover', backgroundPosition: 'center' }}>
620
+ {!book.coverBase64 && (
621
+ <div className="book-cover-content">
622
+ <span className="default-cover-title">{book.title}</span>
623
+ <span className="default-cover-author">{book.author || "Unknown Author"}</span>
624
+ </div>
625
+ )}
626
+ {book.isParsing && (
627
+ <div className="parsing-overlay">
628
+ <div className="spinner-small" />
629
+ </div>
630
+ )}
631
+ <button
632
+ className="delete-book-btn"
633
+ onClick={e => removeBook(e, book.originalIndex)}
634
+ aria-label="Remove Book"
635
+ title="Remove Book"
636
+ >
637
+ <Trash2 size={18} />
638
+ </button>
639
+ </div>
640
+ <div className="book-title">{book.title}</div>
641
+ <div className="book-author">{book.author}</div>
642
+
643
+ {!book.isParsing && book.chunks.length > 0 && (
644
+ <div className="book-progress-container">
645
+ <div className="book-progress-labels">
646
+ <span>{progressPct}%</span>
647
+ <span>{remainingTime} left</span>
648
+ </div>
649
+ <div className="book-progress-track">
650
+ <div className="book-progress-fill" style={{ width: `${progressPct}%` }} />
651
+ </div>
652
+ </div>
653
+ )}
654
+ </div>
655
+ );
656
+ })}
657
+ </div>
658
+ )}
659
+ </main>
660
+ </React.Fragment>
661
+ )}
662
+
663
+ {view === 'reader' && activeBook && (
664
+ <div className="reader-wrapper page-enter">
665
+ <header className="reader-header" style={{ position: 'relative' }}>
666
+ <div style={{ display: 'flex', width: '100%', height: '100%', alignItems: 'center', justifyContent: 'space-between', padding: '0 1.5rem' }}>
667
+ <button className="btn-icon" style={{ gap: '6px', color: 'var(--text-primary)', width: 'auto', padding: '0.5rem 0.75rem' }} onClick={() => { setView('library'); setIsPlaying(false); audioRef.current.pause(); }}>
668
+ <ChevronLeft size={20} /> <span style={{ fontSize: '14px', fontWeight: 600 }}>Library</span>
669
+ </button>
670
+ <div style={{ position: 'absolute', left: '50%', transform: 'translateX(-50%)', textAlign: 'center', pointerEvents: 'none', fontFamily: 'var(--font-display)', fontStyle: 'italic', fontSize: '1rem', color: 'var(--text-secondary)', letterSpacing: '0.01em', maxWidth: '320px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
671
+ {activeBook.title}
672
+ </div>
673
+ <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
674
+ <button
675
+ className="btn-icon"
676
+ onClick={toggleBookmark}
677
+ title="Bookmark current paragraph"
678
+ style={{ color: activeBook.bookmarks?.some(x => x.chunkIndex === currentChunkIndex) ? 'var(--highlight-color)' : 'inherit' }}
679
+ >
680
+ <Bookmark size={18} fill={activeBook.bookmarks?.some(x => x.chunkIndex === currentChunkIndex) ? 'currentColor' : 'none'} />
681
+ </button>
682
+ <button
683
+ className={`btn-icon ${showBookmarks ? 'active' : ''}`}
684
+ onClick={() => { setShowBookmarks(!showBookmarks); setShowTOC(false); setShowSettings(false); }}
685
+ title="View bookmarks list"
686
+ aria-label="View bookmarks list"
687
+ >
688
+ <Bookmark size={18} />
689
+ </button>
690
+ <button
691
+ className={`btn-icon ${showTOC ? 'active' : ''}`}
692
+ onClick={() => { setShowTOC(!showTOC); setShowSettings(false); setShowBookmarks(false); }}
693
+ title="Table of Contents"
694
+ aria-label="Table of Contents"
695
+ >
696
+ <List size={18} />
697
+ </button>
698
+ <button
699
+ className={`btn-icon ${showSettings ? 'active' : ''}`}
700
+ onClick={() => { setShowSettings(!showSettings); setShowTOC(false); setShowBookmarks(false); }}
701
+ title="Display settings"
702
+ aria-label="Display settings"
703
+ >
704
+ <Type size={18} />
705
+ </button>
706
+ </div>
707
+ </div>
708
+ {/* Enhanced progress bar at bottom of reader header */}
709
+ <div style={{ position: 'absolute', bottom: -1, left: 0, width: '100%', height: '2px', background: 'var(--border-color)', zIndex: 11 }}>
710
+ <div style={{ height: '100%', background: 'var(--highlight-color)', width: `${Math.floor((currentChunkIndex / (chunks.length || 1)) * 100)}%`, transition: 'width 0.3s ease', boxShadow: '0 0 10px var(--highlight-color)' }} />
711
+ </div>
712
+ </header>
713
+
714
+ {showSettings && (
715
+ <SettingsPanel
716
+ readingFont={readingFont} setReadingFont={setReadingFont}
717
+ readingSpacing={readingSpacing} setReadingSpacing={setReadingSpacing}
718
+ theme={theme} setTheme={setTheme}
719
+ highlightColor={highlightColor} setHighlightColor={setHighlightColor}
720
+ piperVoice={piperVoice} handleVoiceChange={e => setPiperVoice(e.target.value)}
721
+ piperSpeaker={piperSpeaker} handleSpeakerChange={e => setPiperSpeaker(parseInt(e.target.value))}
722
+ speechRate={speechRate} handleRateChange={e => setSpeechRate(parseFloat(e.target.value))}
723
+ onClose={() => setShowSettings(false)}
724
+ />
725
+ )}
726
+ {showTOC && <TOCPopover toc={activeBook.toc} currentChunkIndex={currentChunkIndex} onJump={setCurrentChunkIndex} onClose={() => setShowTOC(false)} />}
727
+ {showBookmarks && <BookmarksPopover bookmarks={activeBook.bookmarks} onJump={setCurrentChunkIndex} onClose={() => setShowBookmarks(false)} />}
728
+
729
+ <div className="reader-content" onClick={() => { setShowSettings(false); setShowTOC(false); setShowBookmarks(false); }}>
730
+ <div className="book-page">
731
+ {chunks.map((c, i) => (
732
+ <ReaderParagraph key={i} chunk={c} index={i} isActive={i === currentChunkIndex} activeParagraphRef={activeParagraphRef} onClick={handleParagraphClick} />
733
+ ))}
734
+ </div>
735
+ </div>
736
+
737
+ <AudioDock
738
+ activeBook={activeBook} currentChunkIndex={currentChunkIndex} chunks={chunks}
739
+ isPlaying={isPlaying} loadingAudio={loadingAudio}
740
+ onPlayPause={handlePlayPause}
741
+ onSkipBack={() => setCurrentChunkIndex(p => Math.max(0, p-1))}
742
+ onSkipForward={() => setCurrentChunkIndex(p => Math.min(chunks.length-1, p+1))}
743
+ onProgressClick={(e) => {
744
+ const rect = e.currentTarget.getBoundingClientRect();
745
+ const pct = (e.clientX - rect.left) / rect.width;
746
+ setCurrentChunkIndex(Math.floor(pct * chunks.length));
747
+ }}
748
+ />
749
+ </div>
750
+ )}
751
+ </div>
752
+ );
753
+ }
754
+
755
+ export default App;
App/frontend/src/assets/react.svg ADDED
App/frontend/src/components/AudioDock.jsx ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import { Play, Pause, SkipBack, SkipForward } from 'lucide-react';
3
+
4
+ export default function AudioDock({
5
+ activeBook,
6
+ currentChunkIndex,
7
+ chunks,
8
+ isPlaying,
9
+ loadingAudio,
10
+ onPlayPause,
11
+ onSkipBack,
12
+ onSkipForward,
13
+ onProgressClick
14
+ }) {
15
+ if (!activeBook) return null;
16
+
17
+ return (
18
+ <div className="audio-dock">
19
+ <div className="dock-controls">
20
+ <button className="dock-btn" onClick={onSkipBack}>
21
+ <SkipBack size={18} fill="currentColor" />
22
+ </button>
23
+
24
+ <button className="dock-btn play" onClick={onPlayPause} disabled={chunks.length === 0}>
25
+ {loadingAudio ? (
26
+ <div className="spinner" />
27
+ ) : (
28
+ isPlaying ? <Pause size={18} fill="currentColor" /> : <Play size={18} fill="currentColor" style={{ marginLeft: '2px' }} />
29
+ )}
30
+ </button>
31
+
32
+ <button className="dock-btn" onClick={onSkipForward}>
33
+ <SkipForward size={18} fill="currentColor" />
34
+ </button>
35
+ </div>
36
+
37
+ <div className="dock-info">
38
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
39
+ <div className="dock-title">{activeBook.title}</div>
40
+ <div className="dock-subtitle">Powered by Piper</div>
41
+ </div>
42
+
43
+ <div className="dock-progress">
44
+ <span>Page {chunks.length > 0 ? Math.floor(currentChunkIndex / 15) + 1 : 0}</span>
45
+ <div className="scrubber" onClick={onProgressClick}>
46
+ <div
47
+ className="scrubber-fill"
48
+ style={{ width: `${chunks.length > 0 ? (currentChunkIndex / chunks.length) * 100 : 0}%` }}
49
+ />
50
+ </div>
51
+ <span>{chunks.length > 0 ? Math.floor(chunks.length / 15) + 1 : 0}</span>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ );
56
+ }
App/frontend/src/components/BookmarksPopover.jsx ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import { BookOpen } from 'lucide-react';
3
+
4
+ export default function BookmarksPopover({ bookmarks, onJump, onClose }) {
5
+ return (
6
+ <div className="bookmarks-popover">
7
+ <div className="settings-section-title" style={{ padding: '0 8px', marginBottom: '12px' }}>Bookmarks</div>
8
+ <div className="toc-list">
9
+ {(bookmarks?.length || 0) === 0 ? (
10
+ <div style={{ padding: '8px', fontSize: '14px', color: 'var(--text-muted)' }}>
11
+ No bookmarks yet.
12
+ </div>
13
+ ) : (
14
+ bookmarks.map((bm, i) => (
15
+ <div
16
+ key={`bm-${i}`}
17
+ className="toc-item"
18
+ onClick={() => { onJump(bm.chunkIndex); onClose(); }}
19
+ style={{ display: 'flex', alignItems: 'center', gap: '8px' }}
20
+ >
21
+ <BookOpen size={14} style={{ flexShrink: 0, color: 'var(--highlight-color)' }} />
22
+ <div style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
23
+ Page {Math.floor(bm.chunkIndex / 15) + 1}: {bm.preview}
24
+ </div>
25
+ </div>
26
+ ))
27
+ )}
28
+ </div>
29
+ </div>
30
+ );
31
+ }
App/frontend/src/components/EReaderLogo.jsx ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+
3
+ export default function EReaderLogo({ onClick }) {
4
+ return (
5
+ <svg
6
+ viewBox="0 0 168 38"
7
+ height="34"
8
+ aria-label="eReader."
9
+ role="img"
10
+ onClick={onClick}
11
+ style={{
12
+ cursor: 'pointer',
13
+ display: 'block',
14
+ marginBottom: '2rem',
15
+ paddingLeft: '0.25rem',
16
+ color: 'var(--text-primary)',
17
+ flexShrink: 0,
18
+ }}
19
+ >
20
+ <text
21
+ x="2"
22
+ y="30"
23
+ fontFamily="'Playfair Display', Georgia, serif"
24
+ fontStyle="italic"
25
+ fontWeight="700"
26
+ fontSize="32"
27
+ fill="currentColor"
28
+ letterSpacing="-0.5"
29
+ >
30
+ eReader.
31
+ </text>
32
+ </svg>
33
+ );
34
+ }
App/frontend/src/components/ReaderParagraph.jsx ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+
3
+ const ReaderParagraph = React.memo(({ chunk, index, isActive, activeParagraphRef, onClick }) => {
4
+ const text = typeof chunk === 'string' ? chunk : chunk.text;
5
+ const type = typeof chunk === 'string' ? 'p' : (chunk.type || 'p');
6
+ const isHeading = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(type);
7
+ const Tag = isHeading ? type : 'p';
8
+
9
+ return (
10
+ <Tag
11
+ data-chunk-index={index}
12
+ ref={isActive ? activeParagraphRef : null}
13
+ onClick={() => onClick(index)}
14
+ className={`reader-paragraph ${isActive ? 'active' : ''}`}
15
+ style={isActive ? {
16
+ backgroundColor: 'var(--highlight-color)',
17
+ color: '#000000',
18
+ borderRadius: '6px',
19
+ padding: '0.4rem 0.75rem',
20
+ marginLeft: '-0.75rem',
21
+ marginRight: '-0.75rem',
22
+ boxShadow: '0 0 0 6px var(--highlight-color)',
23
+ transition: 'background-color 0.3s ease, box-shadow 0.3s ease'
24
+ } : {}}
25
+ >
26
+ {text}
27
+ </Tag>
28
+ );
29
+ });
30
+
31
+ export default ReaderParagraph;
App/frontend/src/components/SettingsPanel.jsx ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+
3
+ export default function SettingsPanel({
4
+ readingFont, setReadingFont,
5
+ readingSpacing, setReadingSpacing,
6
+ theme, setTheme,
7
+ highlightColor, setHighlightColor,
8
+ piperVoice, handleVoiceChange,
9
+ piperSpeaker, handleSpeakerChange,
10
+ speechRate, handleRateChange,
11
+ onClose
12
+ }) {
13
+ const spacingSteps = ['compact', 'normal', 'relaxed', 'spacious'];
14
+ const spacingIdx = spacingSteps.indexOf(readingSpacing);
15
+
16
+ return (
17
+ <div className="settings-popover">
18
+ {/* Panel header */}
19
+ <div className="sp-header">
20
+ <span className="sp-title">Display & Voice</span>
21
+ <button className="btn-icon sp-close" onClick={onClose} aria-label="Close settings">
22
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M1 1l12 12M13 1L1 13" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>
23
+ </button>
24
+ </div>
25
+
26
+ {/* ── Typography ── */}
27
+ <div className="sp-group">
28
+ <span className="sp-group-label">Typography</span>
29
+
30
+ {/* Font Select */}
31
+ <div className="sp-row sp-row-col">
32
+ <span className="sp-row-label">Typeface</span>
33
+ <select
34
+ className="sp-select sp-font-select"
35
+ value={readingFont}
36
+ onChange={e => setReadingFont(e.target.value)}
37
+ >
38
+ <option value="serif">Playfair Display β€” Serif</option>
39
+ <option value="sans">Instrument Sans β€” Humanist</option>
40
+ <option value="georgia">Georgia β€” Old Style</option>
41
+ <option value="mono">Courier New β€” Monospace</option>
42
+ </select>
43
+ </div>
44
+
45
+ {/* Spacing Steps */}
46
+ <div className="sp-row sp-row-col">
47
+ <div className="sp-label-between">
48
+ <span className="sp-row-label">Spacing</span>
49
+ <span className="sp-step-badge">{readingSpacing}</span>
50
+ </div>
51
+ <div className="sp-step-wrap">
52
+ <input
53
+ type="range" min="0" max="3" step="1"
54
+ value={spacingIdx}
55
+ onChange={e => setReadingSpacing(spacingSteps[+e.target.value])}
56
+ className="sp-range sp-range-stepped"
57
+ />
58
+ <div className="sp-step-ticks">
59
+ {spacingSteps.map((s, i) => (
60
+ <span
61
+ key={s}
62
+ className={`sp-tick ${i === spacingIdx ? 'active' : ''}`}
63
+ onClick={() => setReadingSpacing(s)}
64
+ >
65
+ {s[0].toUpperCase()}
66
+ </span>
67
+ ))}
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </div>
72
+
73
+ {/* ── Appearance ── */}
74
+ <div className="sp-group">
75
+ <span className="sp-group-label">Appearance</span>
76
+ <div className="sp-theme-row">
77
+ {[
78
+ { value: 'auto', icon: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z"/><path d="M12 3v18"/><path d="M12 3c4.97 0 9 4.03 9 9s-4.03 9-9 9"/></svg>, label: 'Auto' },
79
+ { value: 'light', icon: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>, label: 'Light' },
80
+ { value: 'dark', icon: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>, label: 'Dark' },
81
+ ].map(opt => (
82
+ <button
83
+ key={opt.value}
84
+ className={`sp-theme-btn ${theme === opt.value ? 'active' : ''}`}
85
+ onClick={() => setTheme(opt.value)}
86
+ >
87
+ {opt.icon}
88
+ <span>{opt.label}</span>
89
+ </button>
90
+ ))}
91
+ </div>
92
+ </div>
93
+
94
+ {/* ── Highlight color ── */}
95
+ <div className="sp-group">
96
+ <span className="sp-group-label">Highlight</span>
97
+ <div className="sp-color-row">
98
+ {['#fcff82', '#a5d8ff', '#b2f2bb', '#ffc9c9', '#eebefa', '#ffffff'].map(color => (
99
+ <button
100
+ key={color}
101
+ className={`sp-color-btn ${highlightColor === color ? 'active' : ''}`}
102
+ onClick={() => setHighlightColor(color)}
103
+ style={{ '--swatch-bg': color }}
104
+ aria-label={`Highlight color ${color}`}
105
+ />
106
+ ))}
107
+ </div>
108
+ </div>
109
+
110
+ {/* ── Playback ── */}
111
+ <div className="sp-group">
112
+ <span className="sp-group-label">Playback</span>
113
+ <div className="sp-row sp-row-col">
114
+ <span className="sp-row-label">Voice</span>
115
+ <select value={piperVoice} onChange={handleVoiceChange} className="sp-select">
116
+ <option disabled style={{ fontWeight: 600 }}>πŸ‡ΊπŸ‡Έ US English</option>
117
+ <option value="en_US-lessac-medium">Lessac β€” Female</option>
118
+ <option value="en_US-joe-medium">Joe β€” Male</option>
119
+ <option value="en_US-libritts_r-medium">LibriTTS β€” Multi</option>
120
+ <option disabled style={{ fontWeight: 600 }}>πŸ‡¬πŸ‡§ British English</option>
121
+ <option value="en_GB-alan-medium">Alan β€” Male</option>
122
+ <option value="en_GB-northern_english_male-medium">Northern Male</option>
123
+ <option value="en_GB-semaine-medium">Semaine</option>
124
+ <option value="en_GB-southern_english_female-low">Southern Female</option>
125
+ </select>
126
+ {piperVoice === 'en_US-libritts_r-medium' && (
127
+ <input
128
+ type="number" min="0" max="903"
129
+ value={piperSpeaker}
130
+ onChange={handleSpeakerChange}
131
+ placeholder="Speaker ID (0–903)"
132
+ className="sp-number"
133
+ />
134
+ )}
135
+ </div>
136
+ <div className="sp-row">
137
+ <span className="sp-row-label">Speed</span>
138
+ <div className="sp-slider-wrap">
139
+ <input
140
+ type="range" min="0.5" max="2.0" step="0.1"
141
+ value={speechRate} onChange={handleRateChange}
142
+ className="sp-range"
143
+ />
144
+ <span className="sp-range-val">{speechRate}Γ—</span>
145
+ </div>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ );
150
+ }
App/frontend/src/components/Sidebar.jsx ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import { Search, FileText, BookOpen, Settings } from 'lucide-react';
3
+ import EReaderLogo from './EReaderLogo';
4
+
5
+ export default function Sidebar({
6
+ view, setView, activeBook, onLogoClick, searchQuery, onSearchChange, searchRef,
7
+ piperVoice, onVoiceChange, speechRate, onRateChange, showSettings, setShowSettings
8
+ }) {
9
+ return (
10
+ <aside className="sidebar glass">
11
+ <EReaderLogo onClick={onLogoClick} />
12
+
13
+ <div className="search-bar">
14
+ <Search size={14} />
15
+ <input
16
+ ref={searchRef}
17
+ type="text"
18
+ placeholder="Search"
19
+ value={searchQuery}
20
+ onChange={onSearchChange}
21
+ />
22
+ <span className="search-kbd">/</span>
23
+ </div>
24
+
25
+ <div className="sidebar-category">
26
+ <span className="sidebar-heading">Browse</span>
27
+ <div
28
+ className={`sidebar-item ${view === 'library' ? 'active' : ''}`}
29
+ onClick={() => setView('library')}
30
+ style={{ cursor: 'pointer' }}
31
+ >
32
+ <FileText size={16} className="icon" /> Library
33
+ </div>
34
+ <div
35
+ className={`sidebar-item ${view === 'reader' ? 'active' : ''}`}
36
+ onClick={() => { if (activeBook) setView('reader'); }}
37
+ style={{ cursor: activeBook ? 'pointer' : 'default', opacity: activeBook ? 1 : 0.5 }}
38
+ >
39
+ <BookOpen size={16} className="icon" /> Reading Now
40
+ </div>
41
+ </div>
42
+
43
+ <div style={{ flex: 1 }}></div>
44
+
45
+ <div className="sidebar-settings">
46
+ <div
47
+ className="sidebar-settings-header"
48
+ onClick={() => setShowSettings(!showSettings)}
49
+ >
50
+ <span className="sidebar-heading">Options</span>
51
+ <Settings size={14} style={{ color: 'var(--text-muted)' }} />
52
+ </div>
53
+
54
+ {showSettings && (
55
+ <div className="sidebar-settings-content">
56
+ <div className="sidebar-setting-row">
57
+ <label>Voice Engine</label>
58
+ <select value={piperVoice} onChange={onVoiceChange}>
59
+ <option disabled style={{ fontWeight: 600 }}>πŸ‡ΊπŸ‡Έ US English</option>
60
+ <option value="en_US-lessac-medium"> Lessac β€” Female</option>
61
+ <option value="en_US-joe-medium"> Joe β€” Male</option>
62
+ <option value="en_US-libritts_r-medium"> LibriTTS β€” Multi</option>
63
+ <option disabled style={{ fontWeight: 600 }}>πŸ‡¬πŸ‡§ British English</option>
64
+ <option value="en_GB-alan-medium"> Alan β€” Male</option>
65
+ <option value="en_GB-northern_english_male-medium"> Northern Male</option>
66
+ <option value="en_GB-semaine-medium"> Semaine</option>
67
+ <option value="en_GB-southern_english_female-low"> Southern Female</option>
68
+ </select>
69
+ </div>
70
+
71
+ <div className="sidebar-setting-row">
72
+ <label>Speed ({speechRate}x)</label>
73
+ <input type="range" min="0.5" max="2.0" step="0.1" value={speechRate} onChange={onRateChange} />
74
+ </div>
75
+ </div>
76
+ )}
77
+ </div>
78
+ </aside>
79
+ );
80
+ }
App/frontend/src/components/TOCPopover.jsx ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+
3
+ export default function TOCPopover({ toc, currentChunkIndex, onJump, onClose }) {
4
+ return (
5
+ <div className="toc-popover">
6
+ <div className="settings-section-title" style={{ padding: '0 8px', marginBottom: '12px' }}>Table of Contents</div>
7
+ <div className="toc-list">
8
+ {toc?.length > 0 ? (
9
+ toc.map((item, i) => {
10
+ const isCurrentOrPast = item.chunkIndex <= currentChunkIndex;
11
+ const isNextFuture = (i < toc.length - 1) ? (toc[i + 1].chunkIndex > currentChunkIndex) : true;
12
+ const isActive = isCurrentOrPast && isNextFuture;
13
+
14
+ return (
15
+ <div
16
+ key={i}
17
+ className={`toc-item ${isActive ? 'active' : ''}`}
18
+ onClick={() => {
19
+ onJump(item.chunkIndex);
20
+ onClose();
21
+ }}
22
+ >
23
+ {item.label}
24
+ </div>
25
+ );
26
+ })
27
+ ) : (
28
+ <div style={{ padding: '8px', fontSize: '14px', color: 'var(--text-secondary)' }}>
29
+ No contents found in this document.
30
+ </div>
31
+ )}
32
+ </div>
33
+ </div>
34
+ );
35
+ }
App/frontend/src/index.css ADDED
@@ -0,0 +1,1845 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import url('https://fonts.googleapis.com/css2?family=Instrument+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Playfair+Display:ital,wght@0,400;0,700;0,800;1,400;1,700&display=swap');
2
+
3
+ /* ─── Theme Transition ─── */
4
+ *,
5
+ *::before,
6
+ *::after {
7
+ transition-property: background-color, border-color, color, box-shadow;
8
+ transition-duration: 0.25s;
9
+ transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
10
+ }
11
+
12
+ :root {
13
+ /* ── Dark Mode (Default) ── */
14
+ --bg-primary: #000000;
15
+ --bg-secondary: #0a0a0a;
16
+ --bg-elevated: #111111;
17
+ --bg-input: rgba(255, 255, 255, 0.05);
18
+ --bg-sidebar: rgba(0, 0, 0, 0.5);
19
+ --bg-header: rgba(0, 0, 0, 0.75);
20
+ --bg-reader-header: rgba(0, 0, 0, 0.85);
21
+ --bg-dock: rgba(10, 10, 10, 0.8);
22
+ --bg-popover: rgba(15, 15, 15, 0.92);
23
+ --bg-cover-content: linear-gradient(135deg, rgba(20, 20, 20, 0.9) 0%, rgba(5, 5, 5, 0.95) 100%);
24
+ --bg-app-gradient: radial-gradient(ellipse 80% 50% at 50% 110%, rgba(252, 255, 130, 0.04) 0%, transparent 70%), #000000;
25
+
26
+ --text-primary: #ffffff;
27
+ --text-secondary: #a1a1aa;
28
+ --text-muted: #71717a;
29
+ --text-body: #d4d4d8;
30
+ --text-body-hover: #ffffff;
31
+ --text-cover-author: rgba(255, 255, 255, 0.6);
32
+
33
+ /* Accent */
34
+ --accent: #fcff82;
35
+ --accent-blue: #3b82f6;
36
+ --accent-dim: rgba(252, 255, 130, 0.15);
37
+
38
+ /* Typography */
39
+ --font-display: 'Playfair Display', Georgia, serif;
40
+ --font-sans: 'Instrument Sans', system-ui, sans-serif;
41
+
42
+ /* Borders */
43
+ --border-color: rgba(255, 255, 255, 0.08);
44
+ --border-hover: rgba(255, 255, 255, 0.16);
45
+ --border-active: rgba(252, 255, 130, 0.25);
46
+
47
+ /* Shadows - Layered for depth */
48
+ --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.5);
49
+ --shadow-md: 0 8px 16px -4px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);
50
+ --shadow-lg: 0 20px 48px -12px rgba(0, 0, 0, 0.8), 0 0 0 1px rgba(255, 255, 255, 0.08);
51
+ --shadow-dock: 0 24px 64px rgba(0, 0, 0, 0.9), 0 0 0 1px rgba(255, 255, 255, 0.1);
52
+
53
+ /* UI Tokens */
54
+ --radius-xs: 6px;
55
+ --radius-sm: 10px;
56
+ --radius-md: 16px;
57
+ --radius-lg: 28px;
58
+ --radius-full: 9999px;
59
+
60
+ /* Spacing Scale (8dp system) */
61
+ --space-1: 0.25rem;
62
+ /* 4px */
63
+ --space-2: 0.5rem;
64
+ /* 8px */
65
+ --space-3: 0.75rem;
66
+ /* 12px */
67
+ --space-4: 1rem;
68
+ /* 16px */
69
+ --space-5: 1.5rem;
70
+ /* 24px */
71
+ --space-6: 2rem;
72
+ /* 32px */
73
+ --space-8: 3rem;
74
+ /* 48px */
75
+ --space-10: 4rem;
76
+ /* 64px */
77
+
78
+ /* Input/select styles */
79
+ --select-bg: rgba(255, 255, 255, 0.06);
80
+ --select-bg-hover: rgba(255, 255, 255, 0.08);
81
+ --select-arrow: rgba(255, 255, 255, 0.5);
82
+ --select-option-bg: #1a1a1a;
83
+ --select-option-color: #ffffff;
84
+ --select-disabled-color: #52525b;
85
+ --range-track: rgba(255, 255, 255, 0.12);
86
+ --scrubber-track: rgba(255, 255, 255, 0.08);
87
+ --scrubber-fill: rgba(255, 255, 255, 0.35);
88
+ --progress-bar-track: rgba(255, 255, 255, 0.08);
89
+ --progress-bar-fill: rgba(255, 255, 255, 0.35);
90
+ --scrollbar-thumb: rgba(255, 255, 255, 0.1);
91
+ --spinner-border: rgba(255, 255, 255, 0.15);
92
+ --sidebar-item-hover: rgba(255, 255, 255, 0.04);
93
+ --sidebar-item-active: rgba(255, 255, 255, 0.08);
94
+ --sidebar-item-active-border: rgba(255, 255, 255, 0.12);
95
+ --btn-icon-hover: rgba(255, 255, 255, 0.08);
96
+ --btn-icon-active: rgba(255, 255, 255, 0.1);
97
+ --btn-icon-active-shadow: rgba(255, 255, 255, 0.15);
98
+ --btn-text-border: rgba(255, 255, 255, 0.18);
99
+ --toc-hover: rgba(255, 255, 255, 0.05);
100
+ --toc-active: rgba(255, 255, 255, 0.04);
101
+ --toc-active-border: rgba(255, 255, 255, 0.1);
102
+ --dock-btn-hover: rgba(255, 255, 255, 0.08);
103
+ --dock-play-border: rgba(255, 255, 255, 0.2);
104
+ --reader-content-scrollbar: rgba(255, 255, 255, 0.08);
105
+ --color-scheme: dark;
106
+
107
+ /* Reader typography (overridden via JS) */
108
+ --reader-font: 'Playfair Display', Georgia, serif;
109
+ --reader-line-height: 2.0;
110
+ --reader-letter-spacing: 0em;
111
+ --reader-para-spacing: 1.85rem;
112
+
113
+ /* Transitions */
114
+ --transition-fast: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
115
+ --transition-base: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
116
+ --transition-slow: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
117
+ --transition-spring: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
118
+ }
119
+
120
+ /* ─── Light Theme ─────────────────────────────────────── */
121
+ [data-theme="light"] {
122
+ --bg-primary: #fbfbf8;
123
+ /* Warm paper editorial tone */
124
+ --bg-secondary: #f4f4f2;
125
+ --bg-elevated: #ffffff;
126
+ --bg-input: rgba(0, 0, 0, 0.04);
127
+ --bg-sidebar: rgba(255, 255, 255, 0.65);
128
+ --bg-header: rgba(255, 255, 255, 0.75);
129
+ --bg-reader-header: rgba(255, 255, 255, 0.85);
130
+ --bg-dock: rgba(255, 255, 255, 0.8);
131
+ --bg-popover: rgba(255, 255, 255, 0.96);
132
+ --bg-cover-content: linear-gradient(135deg, rgba(230, 225, 215, 0.9) 0%, rgba(215, 210, 200, 0.95) 100%);
133
+ --bg-app-gradient: radial-gradient(ellipse 80% 50% at 50% 110%, rgba(0, 71, 255, 0.02) 0%, transparent 70%), #fbfbf8;
134
+
135
+ --text-primary: #18181b;
136
+ /* Deep coal */
137
+ --text-secondary: #52525b;
138
+ --text-muted: #94949e;
139
+ --text-body: #27272a;
140
+ --text-body-hover: #000000;
141
+ --text-cover-author: rgba(0, 0, 0, 0.55);
142
+
143
+ /* Accent stays distinctive */
144
+ --accent: #fcff82;
145
+ --accent-blue: #2563eb;
146
+ --accent-dim: rgba(252, 255, 130, 0.3);
147
+
148
+ --border-color: rgba(0, 0, 0, 0.08);
149
+ --border-hover: rgba(0, 0, 0, 0.16);
150
+ --border-active: rgba(0, 0, 0, 0.25);
151
+
152
+ --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
153
+ --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.06);
154
+ --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.14), 0 0 0 1px rgba(0, 0, 0, 0.07);
155
+ --shadow-dock: 0 24px 48px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(0, 0, 0, 0.1);
156
+
157
+ /* Input/select overrides */
158
+ --select-bg: rgba(0, 0, 0, 0.05);
159
+ --select-bg-hover: rgba(0, 0, 0, 0.08);
160
+ --select-arrow: rgba(0, 0, 0, 0.45);
161
+ --select-option-bg: #f7f5f0;
162
+ --select-option-color: #1a1a1a;
163
+ --select-disabled-color: #a8a29e;
164
+ --range-track: rgba(0, 0, 0, 0.12);
165
+ --scrubber-track: rgba(0, 0, 0, 0.12);
166
+ --scrubber-fill: rgba(0, 0, 0, 0.3);
167
+ --progress-bar-track: rgba(0, 0, 0, 0.08);
168
+ --progress-bar-fill: rgba(0, 0, 0, 0.3);
169
+ --scrollbar-thumb: rgba(0, 0, 0, 0.12);
170
+ --spinner-border: rgba(0, 0, 0, 0.12);
171
+ --sidebar-item-hover: rgba(0, 0, 0, 0.04);
172
+ --sidebar-item-active: rgba(0, 0, 0, 0.08);
173
+ --sidebar-item-active-border: rgba(0, 0, 0, 0.12);
174
+ --btn-icon-hover: rgba(0, 0, 0, 0.06);
175
+ --btn-icon-active: rgba(0, 0, 0, 0.08);
176
+ --btn-icon-active-shadow: rgba(0, 0, 0, 0.12);
177
+ --btn-text-border: rgba(0, 0, 0, 0.2);
178
+ --toc-hover: rgba(0, 0, 0, 0.05);
179
+ --toc-active: rgba(0, 0, 0, 0.05);
180
+ --toc-active-border: rgba(0, 0, 0, 0.1);
181
+ --dock-btn-hover: rgba(0, 0, 0, 0.06);
182
+ --dock-play-border: rgba(0, 0, 0, 0.2);
183
+ --reader-content-scrollbar: rgba(0, 0, 0, 0.1);
184
+ --color-scheme: light;
185
+ }
186
+
187
+ /* ─── Reset ─────────────────────────────────────────── */
188
+ *,
189
+ *::before,
190
+ *::after {
191
+ box-sizing: border-box;
192
+ margin: 0;
193
+ padding: 0;
194
+ }
195
+
196
+ body {
197
+ font-family: var(--font-sans);
198
+ background-color: var(--bg-primary);
199
+ color: var(--text-primary);
200
+ line-height: 1.65;
201
+ -webkit-font-smoothing: antialiased;
202
+ -moz-osx-font-smoothing: grayscale;
203
+ overflow: hidden;
204
+ }
205
+
206
+ #root {
207
+ height: 100vh;
208
+ display: flex;
209
+ }
210
+
211
+ /* ─── App Container ──────────────────────────────────── */
212
+ .app-container {
213
+ display: flex;
214
+ height: 100vh;
215
+ width: 100vw;
216
+ overflow: hidden;
217
+ background: var(--bg-app-gradient);
218
+ }
219
+
220
+ /* ─── Sidebar ────────────────────────────────────────── */
221
+ .sidebar {
222
+ width: 260px;
223
+ flex-shrink: 0;
224
+ border-right: 1px solid var(--border-color);
225
+ background: var(--bg-sidebar);
226
+ backdrop-filter: blur(20px);
227
+ -webkit-backdrop-filter: blur(20px);
228
+ display: flex;
229
+ flex-direction: column;
230
+ padding: 1.75rem 1.25rem;
231
+ z-index: 10;
232
+ }
233
+
234
+ /* Logo area */
235
+ .sidebar-logo {
236
+ padding: 0 0.5rem;
237
+ margin-bottom: 2rem;
238
+ }
239
+
240
+ .search-bar {
241
+ background: var(--bg-input);
242
+ border: 1px solid var(--border-color);
243
+ border-radius: var(--radius-full);
244
+ padding: 0.65rem 1.1rem;
245
+ display: flex;
246
+ align-items: center;
247
+ gap: 10px;
248
+ color: var(--text-muted);
249
+ font-size: 0.875rem;
250
+ margin-bottom: 2rem;
251
+ transition: var(--transition);
252
+ }
253
+
254
+ .search-bar:focus-within {
255
+ border-color: var(--border-hover);
256
+ box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.04);
257
+ color: var(--text-secondary);
258
+ }
259
+
260
+ .search-bar input {
261
+ border: none;
262
+ background: transparent;
263
+ outline: none;
264
+ color: var(--text-primary);
265
+ width: 100%;
266
+ font-family: var(--font-sans);
267
+ font-size: 0.875rem;
268
+ }
269
+
270
+ .search-bar input::placeholder {
271
+ color: var(--text-muted);
272
+ }
273
+
274
+ .sidebar-settings {
275
+ border-top: none;
276
+ padding-bottom: 20px;
277
+ }
278
+
279
+ .sidebar-settings-header {
280
+ display: flex;
281
+ align-items: center;
282
+ justify-content: space-between;
283
+ padding: 0 8px;
284
+ margin-bottom: 16px;
285
+ cursor: pointer;
286
+ }
287
+
288
+ .sidebar-settings-content {
289
+ display: flex;
290
+ flex-direction: column;
291
+ gap: 16px;
292
+ padding: 0 4px;
293
+ }
294
+
295
+ .sidebar-setting-row label {
296
+ font-size: 11px;
297
+ color: var(--text-muted);
298
+ display: block;
299
+ margin-bottom: 6px;
300
+ text-transform: uppercase;
301
+ letter-spacing: 0.05em;
302
+ }
303
+
304
+ .sidebar-setting-row select,
305
+ .sidebar-setting-row input[type="range"] {
306
+ width: 100%;
307
+ }
308
+
309
+ .search-kbd {
310
+ font-size: 10px;
311
+ color: var(--text-muted);
312
+ border: 1px solid rgba(255, 255, 255, 0.1);
313
+ padding: 2px 5px;
314
+ border-radius: 4px;
315
+ letter-spacing: 0;
316
+ pointer-events: none;
317
+ }
318
+
319
+ .sidebar-section {
320
+ margin-bottom: 2rem;
321
+ }
322
+
323
+ .sidebar-heading {
324
+ font-family: var(--font-sans);
325
+ font-size: 0.7rem;
326
+ /* 11.2px - Microcopy standard */
327
+ font-weight: 700;
328
+ color: var(--text-muted);
329
+ text-transform: uppercase;
330
+ letter-spacing: 0.18em;
331
+ margin-bottom: 1rem;
332
+ padding-left: 0.75rem;
333
+ display: block;
334
+ }
335
+
336
+ .sidebar-category {
337
+ margin-bottom: 2.25rem;
338
+ }
339
+
340
+ .sidebar-item {
341
+ display: flex;
342
+ align-items: center;
343
+ gap: 12px;
344
+ padding: 0.75rem 1rem;
345
+ margin-bottom: 4px;
346
+ font-size: 0.93rem;
347
+ font-weight: 500;
348
+ color: var(--text-secondary);
349
+ cursor: pointer;
350
+ transition: var(--transition-fast);
351
+ border-radius: var(--radius-md);
352
+ border: 1px solid transparent;
353
+ user-select: none;
354
+ }
355
+
356
+ .sidebar-item:hover {
357
+ background: var(--sidebar-item-hover);
358
+ color: var(--text-primary);
359
+ transform: translateX(2px);
360
+ }
361
+
362
+ .sidebar-item:active {
363
+ transform: scale(0.98);
364
+ }
365
+
366
+ .sidebar-item.active {
367
+ background: var(--sidebar-item-active);
368
+ color: var(--text-primary);
369
+ border-color: var(--sidebar-item-active-border);
370
+ font-weight: 600;
371
+ }
372
+
373
+ .sidebar-item .icon {
374
+ color: var(--text-muted);
375
+ display: flex;
376
+ flex-shrink: 0;
377
+ transition: color 0.15s ease;
378
+ }
379
+
380
+ .sidebar-item:hover .icon,
381
+ .sidebar-item.active .icon {
382
+ color: var(--text-primary);
383
+ }
384
+
385
+ /* ─── Main Content ───────────────────────────────────── */
386
+ .main-content {
387
+ flex: 1;
388
+ background: transparent;
389
+ display: flex;
390
+ flex-direction: column;
391
+ position: relative;
392
+ overflow-y: auto;
393
+ }
394
+
395
+ .main-content::-webkit-scrollbar {
396
+ width: 4px;
397
+ }
398
+
399
+ .main-content::-webkit-scrollbar-track {
400
+ background: transparent;
401
+ }
402
+
403
+ .main-content::-webkit-scrollbar-thumb {
404
+ background: var(--scrollbar-thumb);
405
+ border-radius: var(--radius-full);
406
+ }
407
+
408
+ /* ─── Header ─────────────────────────────────────────── */
409
+ .header {
410
+ height: 80px;
411
+ padding: 0 3.5rem;
412
+ display: flex;
413
+ align-items: center;
414
+ justify-content: space-between;
415
+ border-bottom: 1px solid var(--border-color);
416
+ position: sticky;
417
+ top: 0;
418
+ z-index: 10;
419
+ background: var(--bg-header);
420
+ backdrop-filter: blur(16px);
421
+ -webkit-backdrop-filter: blur(16px);
422
+ }
423
+
424
+ .header-title {
425
+ font-family: var(--font-display);
426
+ font-size: 2.2rem;
427
+ font-weight: 700;
428
+ font-style: italic;
429
+ letter-spacing: -0.01em;
430
+ color: var(--text-primary);
431
+ }
432
+
433
+ .btn-pill {
434
+ background: var(--bg-elevated);
435
+ border: 1px solid var(--border-color);
436
+ color: var(--text-secondary);
437
+ padding: 0.5rem 1.25rem;
438
+ border-radius: var(--radius-full);
439
+ font-family: var(--font-sans);
440
+ font-size: 0.72rem;
441
+ font-weight: 600;
442
+ cursor: pointer;
443
+ transition: var(--transition-fast);
444
+ }
445
+
446
+ .btn-pill:hover {
447
+ background: var(--btn-icon-hover);
448
+ color: var(--text-primary);
449
+ border-color: var(--border-hover);
450
+ }
451
+
452
+ .dropdown-menu {
453
+ background: var(--bg-popover);
454
+ border: 1px solid var(--border-color);
455
+ border-radius: var(--radius-md);
456
+ box-shadow: var(--shadow-lg);
457
+ overflow: hidden;
458
+ box-sizing: border-box;
459
+ backdrop-filter: blur(20px);
460
+ -webkit-backdrop-filter: blur(20px);
461
+ animation: dropdownEnter 0.2s cubic-bezier(0.16, 1, 0.3, 1) both;
462
+ }
463
+
464
+ .dropdown-item {
465
+ display: block;
466
+ width: 100%;
467
+ padding: 0.75rem 1rem;
468
+ border: none;
469
+ background: transparent;
470
+ color: var(--text-secondary);
471
+ font-family: var(--font-sans);
472
+ font-size: 0.82rem;
473
+ font-weight: 500;
474
+ text-align: left;
475
+ cursor: pointer;
476
+ transition: var(--transition-fast);
477
+ }
478
+
479
+ .dropdown-item:hover {
480
+ background: var(--btn-icon-hover);
481
+ color: var(--text-primary);
482
+ }
483
+
484
+ .dropdown-item.active {
485
+ background: var(--text-primary);
486
+ color: var(--bg-primary);
487
+ font-weight: 600;
488
+ }
489
+
490
+ @keyframes dropdownEnter {
491
+ from {
492
+ opacity: 0;
493
+ transform: translateY(-4px) scale(0.98);
494
+ }
495
+
496
+ to {
497
+ opacity: 1;
498
+ transform: translateY(0) scale(1);
499
+ }
500
+ }
501
+
502
+ .header-actions {
503
+ display: flex;
504
+ gap: 1rem;
505
+ align-items: center;
506
+ }
507
+
508
+ /* ─── Buttons ────────────────────────────────────────── */
509
+ .btn-icon {
510
+ background: transparent;
511
+ border: none;
512
+ color: var(--text-secondary);
513
+ cursor: pointer;
514
+ display: flex;
515
+ align-items: center;
516
+ justify-content: center;
517
+ transition: var(--transition-fast);
518
+ padding: 0;
519
+ border-radius: var(--radius-full);
520
+ width: 44px;
521
+ /* Rule 86: 44px touch target */
522
+ height: 44px;
523
+ flex-shrink: 0;
524
+ outline: none;
525
+ }
526
+
527
+ .btn-icon:hover {
528
+ color: var(--text-primary);
529
+ background: var(--btn-icon-hover);
530
+ }
531
+
532
+ .btn-icon:active {
533
+ transform: scale(0.96);
534
+ /* Rule 197: scale feedback */
535
+ background: var(--btn-icon-active);
536
+ }
537
+
538
+ .btn-icon.active {
539
+ color: var(--text-primary);
540
+ background: var(--btn-icon-active);
541
+ box-shadow: 0 0 0 1px var(--btn-icon-active-shadow);
542
+ }
543
+
544
+ /* Page Animations */
545
+ .page-enter {
546
+ animation: pageEnter 0.55s cubic-bezier(0.16, 1, 0.3, 1) both;
547
+ }
548
+
549
+ @keyframes pageEnter {
550
+ from {
551
+ opacity: 0;
552
+ transform: scale(0.985) translateY(10px);
553
+ }
554
+
555
+ to {
556
+ opacity: 1;
557
+ transform: scale(1) translateY(0);
558
+ }
559
+ }
560
+
561
+ @keyframes slideUp {
562
+ from {
563
+ opacity: 0;
564
+ transform: translateY(20px);
565
+ }
566
+
567
+ to {
568
+ opacity: 1;
569
+ transform: translateY(0);
570
+ }
571
+ }
572
+
573
+ .btn-text {
574
+ background: transparent;
575
+ border: 1px solid var(--btn-text-border);
576
+ color: var(--text-primary);
577
+ padding: 0.55rem 1.4rem;
578
+ font-size: 0.75rem;
579
+ font-weight: 600;
580
+ text-transform: uppercase;
581
+ letter-spacing: 0.1em;
582
+ border-radius: var(--radius-full);
583
+ cursor: pointer;
584
+ transition: var(--transition);
585
+ font-family: var(--font-sans);
586
+ }
587
+
588
+ .btn-text:hover,
589
+ .btn-text.active {
590
+ background: var(--text-primary);
591
+ color: var(--bg-primary);
592
+ border-color: var(--text-primary);
593
+ }
594
+
595
+ .btn-text:hover {
596
+ transform: translateY(-1px);
597
+ }
598
+
599
+ .btn-text:active {
600
+ transform: translateY(0) scale(0.98);
601
+ }
602
+
603
+ /* ─── Theme Toggle Button ────────────────────────────── */
604
+ .theme-toggle {
605
+ background: transparent;
606
+ border: 1px solid var(--border-color);
607
+ color: var(--text-secondary);
608
+ cursor: pointer;
609
+ width: 40px;
610
+ height: 40px;
611
+ border-radius: var(--radius-full);
612
+ display: flex;
613
+ align-items: center;
614
+ justify-content: center;
615
+ transition: var(--transition-fast);
616
+ flex-shrink: 0;
617
+ font-size: 1rem;
618
+ line-height: 1;
619
+ }
620
+
621
+ .theme-toggle:hover {
622
+ background: var(--btn-icon-hover);
623
+ color: var(--text-primary);
624
+ border-color: var(--border-hover);
625
+ }
626
+
627
+ .library-grid {
628
+ padding: 3.5rem 3.5rem 6rem;
629
+ /* Top padding added to prevent header overlap */
630
+ display: grid;
631
+ grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
632
+ gap: 3.5rem 2.5rem;
633
+ animation: fadeInUp 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
634
+ }
635
+
636
+ .book-card {
637
+ display: flex;
638
+ flex-direction: column;
639
+ cursor: pointer;
640
+ position: relative;
641
+ transition: var(--transition);
642
+ animation: fadeInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
643
+ max-width: 320px;
644
+ }
645
+
646
+ /* ─── Book Cover ─────────────────────────────────────── */
647
+ .book-cover {
648
+ width: 100%;
649
+ height: 315px;
650
+ background: var(--bg-elevated);
651
+ border: 1px solid var(--border-color);
652
+ border-radius: var(--radius-sm);
653
+ margin-bottom: 1.15rem;
654
+ display: flex;
655
+ align-items: center;
656
+ justify-content: center;
657
+ overflow: hidden;
658
+ position: relative;
659
+ box-shadow: var(--shadow-sm);
660
+ transition: var(--transition);
661
+ }
662
+
663
+ .book-card:hover .book-cover {
664
+ border-color: var(--border-hover);
665
+ box-shadow: var(--shadow-lg);
666
+ }
667
+
668
+ /* Hover translation removed for stability */
669
+
670
+ /* Empty State */
671
+ .empty-library {
672
+ flex: 1;
673
+ display: flex;
674
+ flex-direction: column;
675
+ align-items: center;
676
+ justify-content: center;
677
+ padding: 4rem 2rem;
678
+ text-align: center;
679
+ min-height: calc(100vh - 200px);
680
+ }
681
+
682
+ .btn-primary {
683
+ display: inline-flex;
684
+ align-items: center;
685
+ gap: 0.75rem;
686
+ background-color: var(--accent);
687
+ color: #000;
688
+ padding: 0.8rem 1.75rem;
689
+ border: 2px solid #000;
690
+ border-radius: var(--radius-sm);
691
+ font-family: var(--font-sans);
692
+ font-weight: 700;
693
+ text-transform: uppercase;
694
+ letter-spacing: 0.05em;
695
+ font-size: 0.8rem;
696
+ box-shadow: 4px 4px 0px 0px #000;
697
+ transition: transform 0.1s ease, box-shadow 0.1s ease;
698
+ cursor: pointer;
699
+ }
700
+
701
+ .btn-primary:hover {
702
+ transform: translate(-1px, -1px);
703
+ box-shadow: 5px 5px 0px 0px #000;
704
+ }
705
+
706
+ .book-cover-content {
707
+ display: flex;
708
+ flex-direction: column;
709
+ justify-content: center;
710
+ align-items: center;
711
+ height: 100%;
712
+ width: 100%;
713
+ padding: 1.5rem;
714
+ text-align: center;
715
+ background: var(--bg-cover-content);
716
+ }
717
+
718
+ .default-cover-title {
719
+ color: var(--text-primary);
720
+ font-family: var(--font-display);
721
+ font-weight: 700;
722
+ font-style: italic;
723
+ font-size: 1.3rem;
724
+ line-height: 1.2;
725
+ display: -webkit-box;
726
+ -webkit-line-clamp: 4;
727
+ line-clamp: 4;
728
+ -webkit-box-orient: vertical;
729
+ overflow: hidden;
730
+ margin-bottom: 1rem;
731
+ }
732
+
733
+ .default-cover-author {
734
+ color: var(--text-cover-author);
735
+ font-family: var(--font-sans);
736
+ font-weight: 500;
737
+ font-size: 0.68rem;
738
+ text-transform: uppercase;
739
+ letter-spacing: 0.14em;
740
+ position: relative;
741
+ z-index: 1;
742
+ }
743
+
744
+ .book-cover img {
745
+ width: 100%;
746
+ height: 100%;
747
+ object-fit: cover;
748
+ transition: var(--transition);
749
+ filter: brightness(0.88);
750
+ }
751
+
752
+ .book-card:hover .book-cover img {
753
+ filter: brightness(1.0);
754
+ }
755
+
756
+ /* Delete button on cover */
757
+ .delete-book-btn {
758
+ position: absolute;
759
+ top: 0.65rem;
760
+ right: 0.65rem;
761
+ width: 32px;
762
+ /* Scaled down for cleanliness */
763
+ height: 32px;
764
+ background: rgba(0, 0, 0, 0.7);
765
+ backdrop-filter: blur(12px);
766
+ -webkit-backdrop-filter: blur(12px);
767
+ color: #ffffff;
768
+ border: 1px solid rgba(255, 255, 255, 0.2);
769
+ border-radius: var(--radius-full);
770
+ display: flex;
771
+ align-items: center;
772
+ justify-content: center;
773
+ z-index: 20;
774
+ opacity: 0;
775
+ transform: scale(0.9) translateY(-2px);
776
+ transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
777
+ cursor: pointer;
778
+ }
779
+
780
+ .book-card:hover .delete-book-btn {
781
+ opacity: 1;
782
+ transform: scale(1) translateY(0);
783
+ }
784
+
785
+ .delete-book-btn:hover {
786
+ background: #ffffff;
787
+ border-color: #ffffff;
788
+ color: #000000;
789
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
790
+ }
791
+
792
+ .delete-book-btn:active {
793
+ transform: scale(0.92);
794
+ }
795
+
796
+ .book-card.is-parsing {
797
+ cursor: default;
798
+ opacity: 0.8;
799
+ filter: grayscale(0.2);
800
+ }
801
+
802
+ .book-card.is-parsing:hover {
803
+ transform: scale(1.0);
804
+ }
805
+
806
+ .parsing-overlay {
807
+ position: absolute;
808
+ inset: 0;
809
+ background: rgba(0, 0, 0, 0.4);
810
+ backdrop-filter: blur(2px);
811
+ display: flex;
812
+ align-items: center;
813
+ justify-content: center;
814
+ z-index: 5;
815
+ }
816
+
817
+ .spinner-small {
818
+ width: 24px;
819
+ height: 24px;
820
+ border: 2px solid rgba(255, 255, 255, 0.2);
821
+ border-top-color: #fff;
822
+ border-radius: 50%;
823
+ animation: spin 0.8s linear infinite;
824
+ }
825
+
826
+ .book-title {
827
+ font-family: var(--font-display);
828
+ font-size: 1.05rem;
829
+ font-weight: 400;
830
+ color: var(--text-primary);
831
+ line-height: 1.35;
832
+ margin-bottom: 0.3rem;
833
+ display: -webkit-box;
834
+ -webkit-line-clamp: 2;
835
+ line-clamp: 2;
836
+ -webkit-box-orient: vertical;
837
+ overflow: hidden;
838
+ }
839
+
840
+ .book-author {
841
+ font-family: var(--font-sans);
842
+ font-size: 0.78rem;
843
+ color: var(--text-secondary);
844
+ margin-bottom: 0.6rem;
845
+ }
846
+
847
+ .book-progress {
848
+ font-family: var(--font-sans);
849
+ font-size: 0.72rem;
850
+ color: var(--text-muted);
851
+ display: flex;
852
+ align-items: center;
853
+ gap: 8px;
854
+ text-transform: uppercase;
855
+ letter-spacing: 0.06em;
856
+ }
857
+
858
+ /* Progress bar under book cards */
859
+ .book-progress-bar-track {
860
+ flex: 1;
861
+ height: 2px;
862
+ background: var(--progress-bar-track);
863
+ border-radius: var(--radius-full);
864
+ overflow: hidden;
865
+ }
866
+
867
+ .book-progress-bar-fill {
868
+ height: 100%;
869
+ background: var(--progress-bar-fill);
870
+ border-radius: var(--radius-full);
871
+ transition: width 0.4s ease;
872
+ }
873
+
874
+ /* Book counts and labels */
875
+ .book-count {
876
+ font-size: 0.72rem;
877
+ font-weight: 700;
878
+ letter-spacing: 0.12rem;
879
+ opacity: 0.5;
880
+ text-transform: uppercase;
881
+ color: var(--text-primary);
882
+ }
883
+
884
+ /* Book progress tracking */
885
+ .book-progress-container {
886
+ margin-top: auto;
887
+ padding-top: 1rem;
888
+ }
889
+
890
+ .book-progress-labels {
891
+ display: flex;
892
+ justify-content: space-between;
893
+ font-size: 0.65rem;
894
+ font-weight: 700;
895
+ color: var(--text-muted);
896
+ margin-bottom: 0.5rem;
897
+ text-transform: uppercase;
898
+ letter-spacing: 0.08em;
899
+ }
900
+
901
+ .book-progress-track {
902
+ height: 2px;
903
+ background: var(--border-color);
904
+ width: 100%;
905
+ border-radius: var(--radius-full);
906
+ overflow: hidden;
907
+ }
908
+
909
+ .book-progress-fill {
910
+ height: 100%;
911
+ background: var(--text-secondary);
912
+ transition: width 0.35s ease;
913
+ }
914
+
915
+ /* ─── Empty State ────────────────────────────────────── */
916
+ @keyframes pulseGlow {
917
+
918
+ 0%,
919
+ 100% {
920
+ box-shadow: 0 0 0 0 rgba(252, 255, 130, 0);
921
+ }
922
+
923
+ 50% {
924
+ box-shadow: 0 0 30px 4px rgba(252, 255, 130, 0.08);
925
+ }
926
+ }
927
+
928
+ .empty-state {
929
+ display: flex;
930
+ flex-direction: column;
931
+ align-items: center;
932
+ justify-content: center;
933
+ flex: 1;
934
+ color: var(--text-muted);
935
+ text-align: center;
936
+ padding: 3rem;
937
+ animation: fadeInUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
938
+ }
939
+
940
+ .empty-state-icon {
941
+ width: 80px;
942
+ height: 80px;
943
+ border-radius: 50%;
944
+ background: var(--bg-input);
945
+ border: 1px solid var(--border-color);
946
+ display: flex;
947
+ align-items: center;
948
+ justify-content: center;
949
+ margin-bottom: 2rem;
950
+ animation: pulseGlow 3s ease-in-out infinite;
951
+ }
952
+
953
+ .empty-state h2 {
954
+ font-family: var(--font-display);
955
+ font-size: 2.25rem;
956
+ font-weight: 400;
957
+ font-style: italic;
958
+ color: var(--text-primary);
959
+ margin-bottom: 1rem;
960
+ letter-spacing: -0.01em;
961
+ }
962
+
963
+ .empty-state p {
964
+ font-family: var(--font-sans);
965
+ font-size: 0.95rem;
966
+ margin-bottom: 2.5rem;
967
+ max-width: 340px;
968
+ line-height: 1.7;
969
+ color: var(--text-secondary);
970
+ }
971
+
972
+ /* ─── Reader View ────────────────────────────────────── */
973
+ @keyframes slideUpFade {
974
+ from {
975
+ opacity: 0;
976
+ transform: translateY(12px);
977
+ }
978
+
979
+ to {
980
+ opacity: 1;
981
+ transform: translateY(0);
982
+ }
983
+ }
984
+
985
+ .reader-wrapper {
986
+ background-color: var(--bg-primary);
987
+ color: var(--text-primary);
988
+ height: 100%;
989
+ display: flex;
990
+ flex-direction: column;
991
+ position: absolute;
992
+ inset: 0;
993
+ z-index: 20;
994
+ animation: slideUpFade 0.45s cubic-bezier(0.16, 1, 0.3, 1) forwards;
995
+ }
996
+
997
+ .reader-header {
998
+ height: 72px;
999
+ display: flex;
1000
+ align-items: center;
1001
+ justify-content: space-between;
1002
+ padding: 0 3.5rem;
1003
+ border-bottom: 1px solid var(--border-color);
1004
+ background: var(--bg-reader-header);
1005
+ backdrop-filter: blur(16px);
1006
+ -webkit-backdrop-filter: blur(16px);
1007
+ position: relative;
1008
+ z-index: 10;
1009
+ flex-shrink: 0;
1010
+ }
1011
+
1012
+ .reader-progress-bar {
1013
+ position: absolute;
1014
+ bottom: 0;
1015
+ left: 0;
1016
+ height: 1px;
1017
+ background: var(--accent);
1018
+ transition: width 0.3s ease;
1019
+ opacity: 0.7;
1020
+ }
1021
+
1022
+ .reader-content {
1023
+ flex: 1;
1024
+ overflow-y: auto;
1025
+ padding: 5rem 2rem 18rem;
1026
+ display: flex;
1027
+ justify-content: center;
1028
+ scroll-behavior: smooth;
1029
+ }
1030
+
1031
+ .reader-content::-webkit-scrollbar {
1032
+ width: 4px;
1033
+ }
1034
+
1035
+ .reader-content::-webkit-scrollbar-track {
1036
+ background: transparent;
1037
+ }
1038
+
1039
+ .reader-content::-webkit-scrollbar-thumb {
1040
+ background: var(--reader-content-scrollbar);
1041
+ border-radius: var(--radius-full);
1042
+ }
1043
+
1044
+ /* ─── Book Text ──────────────────────────────────────── */
1045
+ .book-page {
1046
+ max-width: 680px;
1047
+ width: 100%;
1048
+ font-size: 1.2rem;
1049
+ line-height: var(--reader-line-height);
1050
+ color: var(--text-primary);
1051
+ font-family: var(--reader-font);
1052
+ letter-spacing: var(--reader-letter-spacing);
1053
+ transition: font-family 0.3s ease, line-height 0.3s ease, letter-spacing 0.3s ease;
1054
+ }
1055
+
1056
+ .book-page h1,
1057
+ .book-page h2,
1058
+ .book-page h3,
1059
+ .book-page h4,
1060
+ .book-page h5,
1061
+ .book-page h6 {
1062
+ font-family: var(--font-display);
1063
+ font-weight: 400;
1064
+ color: var(--text-primary);
1065
+ margin-top: 4.5rem;
1066
+ margin-bottom: 1.75rem;
1067
+ line-height: 1.2;
1068
+ }
1069
+
1070
+ .book-page h1 {
1071
+ font-size: 3rem;
1072
+ font-style: italic;
1073
+ }
1074
+
1075
+ .book-page h2 {
1076
+ font-size: 2.25rem;
1077
+ }
1078
+
1079
+ .book-page h3 {
1080
+ font-size: 1.75rem;
1081
+ }
1082
+
1083
+ .book-page h4,
1084
+ .book-page h5,
1085
+ .book-page h6 {
1086
+ font-size: 1.4rem;
1087
+ }
1088
+
1089
+ .book-page p {
1090
+ margin-bottom: var(--reader-para-spacing);
1091
+ text-align: left;
1092
+ font-family: var(--reader-font);
1093
+ color: var(--text-body);
1094
+ font-weight: 400;
1095
+ cursor: text;
1096
+ letter-spacing: var(--reader-letter-spacing);
1097
+ line-height: var(--reader-line-height);
1098
+ transition: color 0.2s ease, margin-bottom 0.3s ease, letter-spacing 0.3s ease, line-height 0.3s ease;
1099
+ }
1100
+
1101
+ .book-page p:hover {
1102
+ color: var(--text-body-hover);
1103
+ }
1104
+
1105
+ /* ─── Audio Dock ─────────────────────────────────────── */
1106
+ .audio-dock {
1107
+ position: absolute;
1108
+ bottom: 2.5rem;
1109
+ left: 50%;
1110
+ transform: translateX(-50%);
1111
+ background: var(--bg-dock);
1112
+ backdrop-filter: blur(28px) saturate(180%);
1113
+ -webkit-backdrop-filter: blur(28px) saturate(180%);
1114
+ border: 1px solid var(--border-color);
1115
+ border-radius: var(--radius-full);
1116
+ padding: 1.1rem 2.25rem;
1117
+ display: flex;
1118
+ align-items: center;
1119
+ gap: 2.25rem;
1120
+ z-index: 50;
1121
+ width: min(88%, 740px);
1122
+ box-shadow: var(--shadow-dock);
1123
+ transition: var(--transition);
1124
+ }
1125
+
1126
+ .audio-dock:hover {
1127
+ border-color: var(--border-hover);
1128
+ }
1129
+
1130
+ .dock-info {
1131
+ flex: 1;
1132
+ display: flex;
1133
+ flex-direction: column;
1134
+ min-width: 0;
1135
+ }
1136
+
1137
+ .dock-title {
1138
+ font-family: var(--font-display);
1139
+ font-size: 1.05rem;
1140
+ font-weight: 400;
1141
+ font-style: italic;
1142
+ white-space: nowrap;
1143
+ overflow: hidden;
1144
+ text-overflow: ellipsis;
1145
+ color: var(--text-primary);
1146
+ }
1147
+
1148
+ .dock-subtitle {
1149
+ font-family: var(--font-sans);
1150
+ font-size: 0.7rem;
1151
+ /* 11px Microcopy */
1152
+ text-transform: uppercase;
1153
+ letter-spacing: 0.16em;
1154
+ color: var(--text-muted);
1155
+ margin-top: 0.35rem;
1156
+ }
1157
+
1158
+ .dock-controls {
1159
+ display: flex;
1160
+ align-items: center;
1161
+ gap: 1rem;
1162
+ }
1163
+
1164
+ .dock-btn {
1165
+ background: transparent;
1166
+ border: none;
1167
+ color: var(--text-secondary);
1168
+ cursor: pointer;
1169
+ display: flex;
1170
+ align-items: center;
1171
+ justify-content: center;
1172
+ transition: var(--transition-fast);
1173
+ border-radius: var(--radius-full);
1174
+ width: 44px;
1175
+ /* Rule 86: 44px touch target */
1176
+ height: 44px;
1177
+ flex-shrink: 0;
1178
+ }
1179
+
1180
+ .dock-btn:hover {
1181
+ background: var(--dock-btn-hover);
1182
+ color: var(--text-primary);
1183
+ }
1184
+
1185
+ .dock-btn.play {
1186
+ width: 52px;
1187
+ height: 52px;
1188
+ border: 1px solid var(--dock-play-border);
1189
+ color: var(--text-primary);
1190
+ }
1191
+
1192
+ .dock-btn.play:hover {
1193
+ background: var(--text-primary);
1194
+ border-color: var(--text-primary);
1195
+ color: var(--bg-primary);
1196
+ transform: scale(1.04);
1197
+ }
1198
+
1199
+ .dock-btn.play:active {
1200
+ transform: scale(0.97);
1201
+ }
1202
+
1203
+ .dock-progress {
1204
+ display: flex;
1205
+ align-items: center;
1206
+ gap: 1rem;
1207
+ font-family: var(--font-sans);
1208
+ font-size: 0.68rem;
1209
+ color: var(--text-muted);
1210
+ font-variant-numeric: tabular-nums;
1211
+ margin-top: 0.85rem;
1212
+ letter-spacing: 0.03em;
1213
+ }
1214
+
1215
+ .scrubber {
1216
+ flex: 1;
1217
+ height: 2px;
1218
+ background: var(--scrubber-track);
1219
+ position: relative;
1220
+ cursor: pointer;
1221
+ border-radius: var(--radius-full);
1222
+ margin: 0 4px;
1223
+ transition: height 0.2s cubic-bezier(0.16, 1, 0.3, 1);
1224
+ }
1225
+
1226
+ .scrubber:hover {
1227
+ height: 4px;
1228
+ }
1229
+
1230
+ .scrubber-fill {
1231
+ position: absolute;
1232
+ top: 0;
1233
+ left: 0;
1234
+ height: 100%;
1235
+ background: var(--scrubber-fill);
1236
+ border-radius: var(--radius-full);
1237
+ transition: width 0.25s linear, background-color 0.2s ease;
1238
+ }
1239
+
1240
+ .scrubber:hover .scrubber-fill {
1241
+ background: var(--text-primary);
1242
+ }
1243
+
1244
+ .scrubber-thumb {
1245
+ position: absolute;
1246
+ top: 50%;
1247
+ width: 12px;
1248
+ height: 12px;
1249
+ background: var(--text-primary);
1250
+ border-radius: 50%;
1251
+ transform: translate(-50%, -50%) scale(0);
1252
+ transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
1253
+ box-shadow: var(--shadow-sm);
1254
+ pointer-events: none;
1255
+ z-index: 2;
1256
+ }
1257
+
1258
+ .scrubber:hover .scrubber-thumb {
1259
+ transform: translate(-50%, -50%) scale(1);
1260
+ }
1261
+
1262
+ /* ─── Spinner ─────────────────────────────��──────────── */
1263
+ .spinner {
1264
+ width: 20px;
1265
+ height: 20px;
1266
+ border: 2px solid var(--spinner-border);
1267
+ border-top-color: var(--text-primary);
1268
+ border-radius: 50%;
1269
+ animation: spin 0.75s linear infinite;
1270
+ }
1271
+
1272
+ @keyframes spin {
1273
+ to {
1274
+ transform: rotate(360deg);
1275
+ }
1276
+ }
1277
+
1278
+ /* ─── Popovers ───────────────────────────────────────── */
1279
+ .book-page p,
1280
+ .book-page h1,
1281
+ .book-page h2,
1282
+ .book-page h3,
1283
+ .book-page h4,
1284
+ .book-page h5,
1285
+ .book-page h6 {
1286
+ transition: opacity 0.4s ease, color 0.4s ease, background-color 0.4s ease;
1287
+ }
1288
+
1289
+ /* ════════════════════════════════════════════════════════
1290
+ SETTINGS PANEL β€” Matches app button + UI language
1291
+ ════════════════════════════════════════════════════════ */
1292
+
1293
+ .settings-popover {
1294
+ position: absolute;
1295
+ top: 68px;
1296
+ right: 1.5rem;
1297
+ z-index: 200;
1298
+ width: 320px;
1299
+ background: var(--bg-popover);
1300
+ border: 1px solid var(--border-color);
1301
+ border-radius: var(--radius-md);
1302
+ box-shadow: var(--shadow-lg);
1303
+ overflow: hidden;
1304
+ display: flex;
1305
+ flex-direction: column;
1306
+ animation: spEnter 0.2s cubic-bezier(0.16, 1, 0.3, 1) both;
1307
+ /* Blur same as sidebar/header */
1308
+ backdrop-filter: blur(20px);
1309
+ -webkit-backdrop-filter: blur(20px);
1310
+ }
1311
+
1312
+ @keyframes spEnter {
1313
+ from {
1314
+ opacity: 0;
1315
+ transform: translateY(-6px) scale(0.98);
1316
+ }
1317
+
1318
+ to {
1319
+ opacity: 1;
1320
+ transform: translateY(0) scale(1);
1321
+ }
1322
+ }
1323
+
1324
+ /* ── Panel header ──────────────────────────────────────── */
1325
+ .sp-header {
1326
+ display: flex;
1327
+ align-items: center;
1328
+ justify-content: space-between;
1329
+ padding: 0.9rem 1.25rem 0.75rem;
1330
+ border-bottom: 1px solid var(--border-color);
1331
+ }
1332
+
1333
+ .sp-title {
1334
+ font-family: var(--font-display);
1335
+ font-style: italic;
1336
+ font-weight: 400;
1337
+ font-size: 1rem;
1338
+ color: var(--text-primary);
1339
+ letter-spacing: -0.01em;
1340
+ }
1341
+
1342
+ /* Close button reuses btn-icon β€” just size override */
1343
+ .sp-close {
1344
+ width: 30px !important;
1345
+ height: 30px !important;
1346
+ padding: 0 !important;
1347
+ color: var(--text-muted) !important;
1348
+ flex-shrink: 0;
1349
+ }
1350
+
1351
+ .sp-close:hover {
1352
+ color: var(--text-primary) !important;
1353
+ }
1354
+
1355
+ /* ── Groups ────────────────────────────────────────────── */
1356
+ .sp-group {
1357
+ padding: 0.875rem 1.25rem;
1358
+ display: flex;
1359
+ flex-direction: column;
1360
+ gap: 0.6rem;
1361
+ border-bottom: 1px solid var(--border-color);
1362
+ }
1363
+
1364
+ .sp-group:last-child {
1365
+ border-bottom: none;
1366
+ }
1367
+
1368
+ .sp-group-label {
1369
+ font-family: var(--font-sans);
1370
+ font-size: 0.7rem;
1371
+ /* 11px Microcopy */
1372
+ font-weight: 700;
1373
+ letter-spacing: 0.16em;
1374
+ text-transform: uppercase;
1375
+ color: var(--text-muted);
1376
+ margin-bottom: 0.4rem;
1377
+ }
1378
+
1379
+ /* ── Rows ──────────────────────────────────────────────── */
1380
+ .sp-row {
1381
+ display: flex;
1382
+ align-items: center;
1383
+ gap: 0.75rem;
1384
+ min-height: 36px;
1385
+ /* comfortable click target */
1386
+ }
1387
+
1388
+ .sp-row-col {
1389
+ flex-direction: column;
1390
+ align-items: stretch;
1391
+ gap: 0.4rem;
1392
+ min-height: unset;
1393
+ }
1394
+
1395
+ .sp-row-label {
1396
+ font-family: var(--font-sans);
1397
+ font-size: 0.75rem;
1398
+ font-weight: 500;
1399
+ color: var(--text-secondary);
1400
+ min-width: 48px;
1401
+ flex-shrink: 0;
1402
+ }
1403
+
1404
+ /* Label + badge on same line (used in Spacing row) */
1405
+ .sp-label-between {
1406
+ display: flex;
1407
+ align-items: baseline;
1408
+ justify-content: space-between;
1409
+ }
1410
+
1411
+ .sp-step-badge {
1412
+ font-family: var(--font-sans);
1413
+ font-size: 0.7rem;
1414
+ font-weight: 700;
1415
+ text-transform: uppercase;
1416
+ letter-spacing: 0.12em;
1417
+ color: var(--text-muted);
1418
+ }
1419
+
1420
+ /* Discrete step slider (Spacing) */
1421
+ .sp-step-wrap {
1422
+ display: flex;
1423
+ flex-direction: column;
1424
+ gap: 4px;
1425
+ }
1426
+
1427
+
1428
+ .sp-step-ticks {
1429
+ display: flex;
1430
+ justify-content: space-between;
1431
+ padding: 0 2px;
1432
+ }
1433
+
1434
+ .sp-tick {
1435
+ font-family: var(--font-sans);
1436
+ font-size: 0.7rem;
1437
+ font-weight: 700;
1438
+ text-transform: uppercase;
1439
+ letter-spacing: 0.08em;
1440
+ color: var(--text-muted);
1441
+ cursor: pointer;
1442
+ padding: 4px 8px;
1443
+ transition: color 0.12s ease;
1444
+ user-select: none;
1445
+ }
1446
+
1447
+ .sp-tick:hover {
1448
+ color: var(--text-secondary);
1449
+ }
1450
+
1451
+ .sp-tick.active {
1452
+ color: var(--text-primary);
1453
+ }
1454
+
1455
+ /* Theme switcher β€” icon + label buttons filling full width */
1456
+ .sp-theme-row {
1457
+ display: flex;
1458
+ gap: 6px;
1459
+ }
1460
+
1461
+ .sp-theme-btn {
1462
+ flex: 1;
1463
+ display: flex;
1464
+ flex-direction: column;
1465
+ align-items: center;
1466
+ gap: 5px;
1467
+ padding: 0.7rem 0.5rem 0.6rem;
1468
+ background: transparent;
1469
+ border: 1px solid var(--btn-text-border);
1470
+ border-radius: var(--radius-sm);
1471
+ color: var(--text-muted);
1472
+ cursor: pointer;
1473
+ transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
1474
+ font-family: var(--font-sans);
1475
+ }
1476
+
1477
+ .sp-theme-btn span {
1478
+ font-size: 0.62rem;
1479
+ font-weight: 600;
1480
+ letter-spacing: 0.1em;
1481
+ text-transform: uppercase;
1482
+ line-height: 1;
1483
+ }
1484
+
1485
+ .sp-theme-btn:hover {
1486
+ background: var(--btn-icon-hover);
1487
+ color: var(--text-primary);
1488
+ border-color: var(--border-hover);
1489
+ }
1490
+
1491
+ .sp-theme-btn.active {
1492
+ background: var(--text-primary);
1493
+ color: var(--bg-primary);
1494
+ border-color: var(--text-primary);
1495
+ }
1496
+
1497
+ .sp-theme-btn.active svg {
1498
+ stroke: var(--bg-primary);
1499
+ }
1500
+
1501
+ /* Font select β€” show selected font in its typeface */
1502
+ .sp-font-select {
1503
+ font-family: var(--reader-font);
1504
+ }
1505
+
1506
+ /* Highlight color swatches */
1507
+ .sp-color-row {
1508
+ display: grid;
1509
+ grid-template-columns: repeat(6, 1fr);
1510
+ gap: 8px;
1511
+ padding: 4px 0;
1512
+ }
1513
+
1514
+ .sp-color-btn {
1515
+ aspect-ratio: 1;
1516
+ border-radius: 50%;
1517
+ border: 1px solid var(--border-color);
1518
+ background: var(--swatch-bg);
1519
+ cursor: pointer;
1520
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
1521
+ padding: 0;
1522
+ position: relative;
1523
+ }
1524
+
1525
+ .sp-color-btn:hover {
1526
+ transform: scale(1.1);
1527
+ border-color: var(--text-muted);
1528
+ }
1529
+
1530
+ .sp-color-btn.active {
1531
+ transform: scale(1.1);
1532
+ box-shadow: 0 0 0 2px var(--bg-popover), 0 0 0 4px var(--text-primary);
1533
+ border-color: transparent;
1534
+ z-index: 1;
1535
+ }
1536
+
1537
+ :root {
1538
+ --highlight-color: #fcff82;
1539
+ }
1540
+
1541
+
1542
+ /* ── Option buttons β€” match .btn-text language exactly ─── */
1543
+ /*
1544
+ App's .btn-text uses:
1545
+ border: 1px solid var(--btn-text-border)
1546
+ border-radius: var(--radius-full) ← pill
1547
+ uppercase, 0.75rem, weight 600, letter-spacing 0.1em
1548
+ hover β†’ inverted (bg=text-primary, color=bg-primary)
1549
+ We mirror that exactly for the options.
1550
+ */
1551
+ .sp-options {
1552
+ display: flex;
1553
+ flex-wrap: wrap;
1554
+ gap: 6px;
1555
+ flex: 1;
1556
+ }
1557
+
1558
+ .sp-opt {
1559
+ /* Same base as .btn-text */
1560
+ background: transparent;
1561
+ border: 1px solid var(--btn-text-border);
1562
+ color: var(--text-secondary);
1563
+ padding: 0.38rem 0.85rem;
1564
+ font-size: 0.72rem;
1565
+ font-weight: 600;
1566
+ text-transform: uppercase;
1567
+ letter-spacing: 0.1em;
1568
+ border-radius: var(--radius-full);
1569
+ /* pill β€” matches app buttons */
1570
+ cursor: pointer;
1571
+ transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
1572
+ font-family: var(--font-sans);
1573
+ white-space: nowrap;
1574
+ line-height: 1;
1575
+ min-height: 30px;
1576
+ display: inline-flex;
1577
+ align-items: center;
1578
+ }
1579
+
1580
+ .sp-opt:hover {
1581
+ background: var(--btn-icon-hover);
1582
+ color: var(--text-primary);
1583
+ border-color: var(--border-hover);
1584
+ }
1585
+
1586
+ .sp-opt:active {
1587
+ transform: scale(0.97);
1588
+ }
1589
+
1590
+ /* Active = same inversion as .btn-text:hover */
1591
+ .sp-opt.active {
1592
+ background: var(--text-primary);
1593
+ color: var(--bg-primary);
1594
+ border-color: var(--text-primary);
1595
+ }
1596
+
1597
+ /* ── Voice select β€” uses global select styles, no override needed ─ */
1598
+ .sp-select {
1599
+ width: 100%;
1600
+ /* global select rules apply; just ensure full width */
1601
+ }
1602
+
1603
+ .sp-number {
1604
+ width: 100%;
1605
+ background: transparent;
1606
+ color: var(--text-primary);
1607
+ border: 1px solid var(--border-color);
1608
+ border-radius: var(--radius-sm);
1609
+ padding: 0.4rem 0.7rem;
1610
+ font-family: var(--font-sans);
1611
+ font-size: 0.82rem;
1612
+ }
1613
+
1614
+ /* ── Speed slider row ─────────────────────────────────── */
1615
+ .sp-slider-wrap {
1616
+ flex: 1;
1617
+ display: flex;
1618
+ align-items: center;
1619
+ gap: 0.75rem;
1620
+ }
1621
+
1622
+ .sp-range {
1623
+ flex: 1;
1624
+ height: 3px;
1625
+ appearance: none;
1626
+ -webkit-appearance: none;
1627
+ background: var(--range-track);
1628
+ border-radius: var(--radius-full);
1629
+ cursor: pointer;
1630
+ outline: none;
1631
+ }
1632
+
1633
+ .sp-range::-webkit-slider-thumb {
1634
+ -webkit-appearance: none;
1635
+ width: 16px;
1636
+ height: 16px;
1637
+ background: var(--text-primary);
1638
+ border: 2.5px solid var(--bg-popover);
1639
+ border-radius: 50%;
1640
+ cursor: pointer;
1641
+ box-shadow: 0 0 0 1px var(--border-hover);
1642
+ transition: transform 0.15s ease;
1643
+ }
1644
+
1645
+ .sp-range::-webkit-slider-thumb:hover {
1646
+ transform: scale(1.2);
1647
+ }
1648
+
1649
+ .sp-range-val {
1650
+ font-family: var(--font-sans);
1651
+ font-size: 0.72rem;
1652
+ font-weight: 700;
1653
+ text-transform: uppercase;
1654
+ letter-spacing: 0.08em;
1655
+ color: var(--text-secondary);
1656
+ min-width: 28px;
1657
+ text-align: right;
1658
+ font-variant-numeric: tabular-nums;
1659
+ }
1660
+
1661
+ /* ════ TOC / Bookmarks popovers ════ */
1662
+ .bookmarks-popover,
1663
+ .toc-popover {
1664
+ position: absolute;
1665
+ top: 68px;
1666
+ right: 1.5rem;
1667
+ z-index: 200;
1668
+ width: 290px;
1669
+ background: var(--bg-popover);
1670
+ border: 1px solid var(--border-color);
1671
+ border-radius: var(--radius-md);
1672
+ box-shadow: var(--shadow-lg);
1673
+ backdrop-filter: blur(20px);
1674
+ -webkit-backdrop-filter: blur(20px);
1675
+ animation: spEnter 0.2s cubic-bezier(0.16, 1, 0.3, 1) both;
1676
+ padding: 1.25rem;
1677
+ }
1678
+
1679
+ /* ── Legacy aliases (TOC/Bookmarks still use these) ──── */
1680
+ .settings-section-title {
1681
+ font-family: var(--font-sans);
1682
+ font-size: 0.6rem;
1683
+ font-weight: 700;
1684
+ text-transform: uppercase;
1685
+ color: var(--text-muted);
1686
+ letter-spacing: 0.18em;
1687
+ margin-bottom: 0.75rem;
1688
+ display: block;
1689
+ }
1690
+
1691
+
1692
+
1693
+
1694
+
1695
+ .toc-list {
1696
+ display: flex;
1697
+ flex-direction: column;
1698
+ gap: 4px;
1699
+ overflow-y: auto;
1700
+ max-height: 52vh;
1701
+ }
1702
+
1703
+ .toc-item {
1704
+ font-family: var(--font-sans);
1705
+ font-size: 0.9rem;
1706
+ padding: 0.75rem 1rem;
1707
+ border-radius: var(--radius-md);
1708
+ color: var(--text-secondary);
1709
+ cursor: pointer;
1710
+ transition: var(--transition-fast);
1711
+ border: 1px solid transparent;
1712
+ line-height: 1.4;
1713
+ }
1714
+
1715
+ .toc-item:hover {
1716
+ background: var(--toc-hover);
1717
+ color: var(--text-primary);
1718
+ }
1719
+
1720
+ .toc-item.active {
1721
+ color: var(--text-primary);
1722
+ background: var(--toc-active);
1723
+ border-color: var(--toc-active-border);
1724
+ font-weight: 500;
1725
+ }
1726
+
1727
+ /* ─── Selects & Inputs ───────────────────────────────── */
1728
+ select {
1729
+ font-family: var(--font-sans);
1730
+ background-color: var(--select-bg);
1731
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-opacity='0.45' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
1732
+ background-repeat: no-repeat;
1733
+ background-position: right 1rem center;
1734
+ background-size: 14px;
1735
+ -webkit-appearance: none;
1736
+ appearance: none;
1737
+ border-radius: var(--radius-full);
1738
+ border: 1px solid var(--border-color);
1739
+ color: var(--text-primary);
1740
+ padding: 0.7rem 2.5rem 0.7rem 1.1rem;
1741
+ cursor: pointer;
1742
+ transition: var(--transition-fast);
1743
+ font-size: 0.875rem;
1744
+ color-scheme: var(--color-scheme);
1745
+ width: 100%;
1746
+ }
1747
+
1748
+ select:hover {
1749
+ border-color: var(--border-hover);
1750
+ background-color: var(--select-bg-hover);
1751
+ }
1752
+
1753
+ select:focus {
1754
+ outline: none;
1755
+ border-color: var(--border-hover);
1756
+ box-shadow: 0 0 0 3px var(--bg-input);
1757
+ }
1758
+
1759
+ select option {
1760
+ background-color: var(--select-option-bg);
1761
+ color: var(--select-option-color);
1762
+ }
1763
+
1764
+ select option:disabled {
1765
+ color: var(--select-disabled-color);
1766
+ }
1767
+
1768
+ input[type="range"] {
1769
+ -webkit-appearance: none;
1770
+ appearance: none;
1771
+ width: 100%;
1772
+ background: transparent;
1773
+ height: 3px;
1774
+ cursor: pointer;
1775
+ }
1776
+
1777
+ input[type="range"]::-webkit-slider-runnable-track {
1778
+ width: 100%;
1779
+ height: 2px;
1780
+ background: var(--range-track);
1781
+ border-radius: var(--radius-full);
1782
+ }
1783
+
1784
+ input[type="range"]::-webkit-slider-thumb {
1785
+ -webkit-appearance: none;
1786
+ appearance: none;
1787
+ height: 14px;
1788
+ width: 14px;
1789
+ margin-top: -6px;
1790
+ border-radius: 50%;
1791
+ background: var(--text-primary);
1792
+ cursor: pointer;
1793
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
1794
+ }
1795
+
1796
+ input[type="range"]::-webkit-slider-thumb:hover {
1797
+ transform: scale(1.25);
1798
+ box-shadow: 0 0 0 4px var(--bg-input);
1799
+ }
1800
+
1801
+ input[type="number"] {
1802
+ font-family: var(--font-sans);
1803
+ border-radius: var(--radius-md);
1804
+ border: 1px solid var(--border-color);
1805
+ padding: 0.65rem 1rem;
1806
+ background: var(--bg-input);
1807
+ color: var(--text-primary);
1808
+ font-size: 0.875rem;
1809
+ transition: var(--transition-fast);
1810
+ width: 100%;
1811
+ }
1812
+
1813
+ input[type="number"]:focus {
1814
+ outline: none;
1815
+ border-color: var(--border-hover);
1816
+ }
1817
+
1818
+ /* ─── Reading progress bar ───────────────────────────── */
1819
+ .highlight,
1820
+ .book-page p.highlight,
1821
+ .book-page h1.highlight,
1822
+ .book-page h2.highlight,
1823
+ .book-page h3.highlight {
1824
+ background-color: var(--highlight-color) !important;
1825
+ color: #000000 !important;
1826
+ border-radius: var(--radius-xs) !important;
1827
+ transition: background-color 0.35s ease, color 0.35s ease !important;
1828
+ padding: 0.25rem 0.5rem !important;
1829
+ box-shadow: 0 0 0 4px var(--highlight-color) !important;
1830
+ margin-left: -0.5rem !important;
1831
+ margin-right: -0.5rem !important;
1832
+ }
1833
+
1834
+ /* Utility */
1835
+ a,
1836
+ button,
1837
+ [role="button"] {
1838
+ cursor: pointer;
1839
+ }
1840
+
1841
+ /* Focus ring for keyboard users */
1842
+ :focus-visible {
1843
+ outline: 2px solid var(--border-hover);
1844
+ outline-offset: 2px;
1845
+ }
App/frontend/src/main.jsx ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.jsx'
5
+
6
+ createRoot(document.getElementById('root')).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )