@trishchuk/coolors-mcp 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/.claude/settings.local.json +2 -6
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +20 -8
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +22 -8
  4. package/.github/pull_request_template.md +33 -8
  5. package/.github/workflows/ci.yml +97 -97
  6. package/.github/workflows/deploy-docs.yml +9 -9
  7. package/.github/workflows/release.yml +15 -15
  8. package/README.md +26 -1
  9. package/TOOLS_UK.md +233 -0
  10. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +30 -12
  11. package/docs/.vitepress/cache/deps/_metadata.json +1 -1
  12. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -6
  13. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +2543 -1612
  14. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +3508 -2529
  15. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +1902 -1003
  16. package/docs/.vitepress/cache/deps/cytoscape.js +13303 -7347
  17. package/docs/.vitepress/cache/deps/dayjs.js +494 -272
  18. package/docs/.vitepress/cache/deps/debug.js +82 -38
  19. package/docs/.vitepress/cache/deps/prismjs.js +444 -272
  20. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +80 -73
  21. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +93 -62
  22. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +13 -13
  23. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +34 -27
  24. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +20 -17
  25. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +75 -41
  26. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +2005 -1438
  27. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +2 -2
  28. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +566 -229
  29. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +382 -270
  30. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +334 -125
  31. package/docs/.vitepress/cache/deps/vue.js +2 -2
  32. package/docs/.vitepress/components/ClientGrid.vue +9 -3
  33. package/docs/.vitepress/components/CodeBlock.vue +51 -44
  34. package/docs/.vitepress/components/ConfigModal.vue +151 -67
  35. package/docs/.vitepress/components/DiagramModal.vue +186 -154
  36. package/docs/.vitepress/components/TroubleshootingModal.vue +101 -96
  37. package/docs/.vitepress/config.js +171 -141
  38. package/docs/.vitepress/theme/FundingLayout.vue +65 -54
  39. package/docs/.vitepress/theme/Layout.vue +21 -21
  40. package/docs/.vitepress/theme/components/AdBanner.vue +73 -52
  41. package/docs/.vitepress/theme/components/AdPlaceholder.vue +3 -3
  42. package/docs/.vitepress/theme/components/FundingEffects.vue +77 -53
  43. package/docs/.vitepress/theme/components/FundingHero.vue +78 -63
  44. package/docs/.vitepress/theme/components/SupportSection.vue +106 -89
  45. package/docs/.vitepress/theme/custom-app.css +19 -12
  46. package/docs/.vitepress/theme/custom.css +33 -25
  47. package/docs/.vitepress/theme/index.js +19 -16
  48. package/docs/concepts/accessibility.md +59 -47
  49. package/docs/concepts/color-spaces.md +28 -6
  50. package/docs/concepts/distance-metrics.md +45 -30
  51. package/docs/concepts/hct.md +30 -27
  52. package/docs/concepts/image-analysis.md +52 -21
  53. package/docs/concepts/material-design.md +43 -17
  54. package/docs/concepts/theme-matching.md +64 -40
  55. package/docs/examples/basic-colors.md +92 -108
  56. package/docs/examples/creating-themes.md +104 -108
  57. package/docs/examples/css-refactoring.md +33 -29
  58. package/docs/examples/image-extraction.md +145 -138
  59. package/docs/getting-started.md +45 -34
  60. package/docs/index.md +5 -1
  61. package/docs/installation.md +15 -1
  62. package/docs/tools/accessibility.md +74 -68
  63. package/docs/tools/image-extraction.md +62 -54
  64. package/docs/tools/theme-matching.md +45 -42
  65. package/note.md +1 -2
  66. package/package.json +2 -2
@@ -12,13 +12,13 @@
12
12
  --app-success: #10b981;
13
13
  --app-warning: #f59e0b;
14
14
  --app-error: #ef4444;
15
-
15
+
16
16
  /* Override VitePress brand colors */
17
17
  --vp-c-brand-1: var(--app-primary);
18
18
  --vp-c-brand-2: var(--app-primary-dark);
19
19
  --vp-c-brand-3: var(--app-secondary);
20
20
  --vp-c-brand-soft: rgba(14, 165, 233, 0.14);
21
-
21
+
22
22
  /* Home hero gradient */
23
23
  --vp-home-hero-name-color: transparent;
24
24
  --vp-home-hero-name-background: linear-gradient(
@@ -26,7 +26,7 @@
26
26
  var(--app-primary) 30%,
27
27
  var(--app-secondary)
28
28
  );
29
-
29
+
30
30
  /* Button styles */
31
31
  --vp-button-brand-border: transparent;
32
32
  --vp-button-brand-bg: var(--app-primary);
@@ -57,7 +57,9 @@
57
57
 
58
58
  /* Feature cards with hover effects */
59
59
  .VPFeature {
60
- transition: transform 0.2s ease, box-shadow 0.2s ease;
60
+ transition:
61
+ transform 0.2s ease,
62
+ box-shadow 0.2s ease;
61
63
  }
62
64
 
63
65
  .VPFeature:hover {
@@ -70,13 +72,13 @@
70
72
  }
71
73
 
72
74
  /* Code blocks styling */
73
- div[class*='language-'] {
75
+ div[class*="language-"] {
74
76
  position: relative;
75
77
  border-radius: 8px;
76
78
  overflow: hidden;
77
79
  }
78
80
 
79
- div[class*='language-']::before {
81
+ div[class*="language-"]::before {
80
82
  content: attr(data-lang);
81
83
  position: absolute;
82
84
  top: 8px;
@@ -158,11 +160,15 @@ div[class*='language-']::before {
158
160
  .client-card--recommended {
159
161
  border-color: var(--app-primary);
160
162
  position: relative;
161
- background: linear-gradient(135deg, var(--vp-c-bg) 0%, var(--vp-c-brand-soft) 100%);
163
+ background: linear-gradient(
164
+ 135deg,
165
+ var(--vp-c-bg) 0%,
166
+ var(--vp-c-brand-soft) 100%
167
+ );
162
168
  }
163
169
 
164
170
  .client-card--recommended::before {
165
- content: 'RECOMMENDED';
171
+ content: "RECOMMENDED";
166
172
  position: absolute;
167
173
  top: -12px;
168
174
  left: 50%;
@@ -260,7 +266,7 @@ div[class*='language-']::before {
260
266
  .client-card {
261
267
  margin: 1rem 0;
262
268
  }
263
-
269
+
264
270
  .tool-card {
265
271
  padding: 1rem;
266
272
  }
@@ -268,7 +274,8 @@ div[class*='language-']::before {
268
274
 
269
275
  /* Animation for loading states */
270
276
  @keyframes pulse {
271
- 0%, 100% {
277
+ 0%,
278
+ 100% {
272
279
  opacity: 1;
273
280
  }
274
281
  50% {
@@ -300,14 +307,14 @@ div[class*='language-']::before {
300
307
  }
301
308
 
302
309
  /* Code snippet copy button enhancement */
303
- div[class*='language-'] .copy {
310
+ div[class*="language-"] .copy {
304
311
  background-color: var(--vp-c-bg-soft);
305
312
  border: 1px solid var(--vp-c-divider);
306
313
  border-radius: 4px;
307
314
  transition: all 0.2s ease;
308
315
  }
309
316
 
310
- div[class*='language-'] .copy:hover {
317
+ div[class*="language-"] .copy:hover {
311
318
  background-color: var(--app-primary);
312
319
  border-color: var(--app-primary);
313
320
  }
@@ -2,8 +2,11 @@
2
2
 
3
3
  /* Base colors and fonts */
4
4
  :root {
5
- --vp-font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
6
- --vp-font-family-mono: 'SF Mono', Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
5
+ --vp-font-family-base:
6
+ -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu",
7
+ "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
8
+ --vp-font-family-mono:
9
+ "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
7
10
  }
8
11
 
9
12
  /* Dark theme refinements */
@@ -142,7 +145,6 @@ html.dark {
142
145
  color: var(--vp-c-text-2);
143
146
  }
144
147
 
145
-
146
148
  /* Tables - wiki style */
147
149
  .vp-doc table {
148
150
  margin: 20px 0;
@@ -226,7 +228,6 @@ html.dark .VPNavBarTitle .logo {
226
228
  border-left: 4px solid var(--vp-c-brand);
227
229
  }
228
230
 
229
-
230
231
  /* Modern hero section */
231
232
  .VPHero {
232
233
  padding: 80px 24px;
@@ -280,7 +281,7 @@ html.dark .VPNavBarTitle .logo {
280
281
 
281
282
  /* Floating star on hover */
282
283
  .VPButton.alt::before {
283
- content: '';
284
+ content: "";
284
285
  position: absolute;
285
286
  font-size: 18px;
286
287
  top: 50%;
@@ -294,7 +295,7 @@ html.dark .VPNavBarTitle .logo {
294
295
 
295
296
  /* Multiple burst particles */
296
297
  .VPButton.alt::after {
297
- content: '✨ ⭐ ✨ ⭐ ✨';
298
+ content: "✨ ⭐ ✨ ⭐ ✨";
298
299
  position: absolute;
299
300
  font-size: 12px;
300
301
  top: 50%;
@@ -355,11 +356,13 @@ html.dark .VPNavBarTitle .logo {
355
356
  }
356
357
  50% {
357
358
  opacity: 1;
358
- transform: translate(-50%, -50%) translateY(-100px) scale(1.5) rotate(180deg);
359
+ transform: translate(-50%, -50%) translateY(-100px) scale(1.5)
360
+ rotate(180deg);
359
361
  }
360
362
  100% {
361
363
  opacity: 0;
362
- transform: translate(-50%, -50%) translateY(-100px) scale(2.5) rotate(360deg);
364
+ transform: translate(-50%, -50%) translateY(-100px) scale(2.5)
365
+ rotate(360deg);
363
366
  }
364
367
  }
365
368
 
@@ -421,7 +424,7 @@ html.dark .VPFeature {
421
424
  /* Light mode hover */
422
425
  .VPFeature:hover {
423
426
  border-color: var(--vp-c-brand-light);
424
- box-shadow:
427
+ box-shadow:
425
428
  0 12px 32px rgba(0, 0, 0, 0.1),
426
429
  0 2px 4px rgba(0, 0, 0, 0.05);
427
430
  }
@@ -430,7 +433,7 @@ html.dark .VPFeature {
430
433
  html.dark .VPFeature:hover {
431
434
  background: rgba(255, 255, 255, 0.05);
432
435
  border-color: rgba(66, 184, 131, 0.5);
433
- box-shadow:
436
+ box-shadow:
434
437
  0 12px 32px rgba(0, 0, 0, 0.4),
435
438
  0 0 0 1px rgba(66, 184, 131, 0.3),
436
439
  inset 0 1px 0 0 rgba(255, 255, 255, 0.1);
@@ -438,7 +441,7 @@ html.dark .VPFeature:hover {
438
441
 
439
442
  /* Gradient overlay for depth */
440
443
  .VPFeature::before {
441
- content: '';
444
+ content: "";
442
445
  position: absolute;
443
446
  top: 0;
444
447
  left: 0;
@@ -511,10 +514,11 @@ html.dark .VPFeature:hover {
511
514
 
512
515
  /* Pulse effect when actively exploring */
513
516
  @keyframes explorePulse {
514
- 0%, 100% {
517
+ 0%,
518
+ 100% {
515
519
  transform: translateY(-3px) scale(1);
516
520
  }
517
- 50% {
521
+ 50% {
518
522
  transform: translateY(-6px) scale(1.05);
519
523
  }
520
524
  }
@@ -525,8 +529,13 @@ html.dark .VPFeature:hover {
525
529
 
526
530
  /* Animated dots while exploring */
527
531
  @keyframes dotDance {
528
- 0%, 100% { transform: translateY(0) scale(1); }
529
- 50% { transform: translateY(-4px) scale(1.5); }
532
+ 0%,
533
+ 100% {
534
+ transform: translateY(0) scale(1);
535
+ }
536
+ 50% {
537
+ transform: translateY(-4px) scale(1.5);
538
+ }
530
539
  }
531
540
 
532
541
  .VPHome:has(.VPFeature:hover) .explore-hint .dot:nth-child(1) {
@@ -560,7 +569,7 @@ html.dark .VPFeature:hover {
560
569
 
561
570
  /* Add diff symbols as pseudo-elements (hidden by default) */
562
571
  .diff-line::before {
563
- content: '';
572
+ content: "";
564
573
  position: absolute;
565
574
  left: 4px;
566
575
  font-family: var(--vp-font-family-mono);
@@ -571,7 +580,7 @@ html.dark .VPFeature:hover {
571
580
 
572
581
  /* Line numbers - typed out on hover */
573
582
  .diff-line::after {
574
- content: '';
583
+ content: "";
575
584
  position: absolute;
576
585
  right: 100%;
577
586
  margin-right: 12px;
@@ -586,19 +595,19 @@ html.dark .VPFeature:hover {
586
595
  }
587
596
 
588
597
  .diff-delete::after {
589
- content: '6739';
598
+ content: "6739";
590
599
  }
591
600
 
592
601
  .diff-add::after {
593
- content: '6740';
602
+ content: "6740";
594
603
  }
595
604
 
596
605
  .diff-delete::before {
597
- content: '-';
606
+ content: "-";
598
607
  }
599
608
 
600
609
  .diff-add::before {
601
- content: '+';
610
+ content: "+";
602
611
  }
603
612
 
604
613
  /* Hover state - transform to diff view */
@@ -614,7 +623,9 @@ html.dark .VPFeature:hover {
614
623
  .VPFeature:first-child:hover .diff-line::after {
615
624
  opacity: 0.6;
616
625
  max-width: 50px;
617
- transition: opacity 0.3s ease 0.3s, max-width 0.4s ease 0.3s;
626
+ transition:
627
+ opacity 0.3s ease 0.3s,
628
+ max-width 0.4s ease 0.3s;
618
629
  }
619
630
 
620
631
  /* Ensure space for line numbers only on File Analysis card */
@@ -694,6 +705,3 @@ html.dark .VPFeature:first-child:hover .diff-add::before {
694
705
  .VPSidebar::-webkit-scrollbar {
695
706
  display: none; /* Chrome/Safari/Webkit */
696
707
  }
697
-
698
-
699
-
@@ -1,25 +1,28 @@
1
- import DefaultTheme from 'vitepress/theme'
2
- import Layout from './Layout.vue'
3
- import FundingLayout from './FundingLayout.vue'
4
- import DiagramModal from '../components/DiagramModal.vue'
5
- import CodeBlock from '../components/CodeBlock.vue'
6
- import ClientGrid from '../components/ClientGrid.vue'
7
- import './custom.css'
8
- import './custom-app.css'
1
+ import DefaultTheme from "vitepress/theme";
2
+ import Layout from "./Layout.vue";
3
+ import FundingLayout from "./FundingLayout.vue";
4
+ import DiagramModal from "../components/DiagramModal.vue";
5
+ import CodeBlock from "../components/CodeBlock.vue";
6
+ import ClientGrid from "../components/ClientGrid.vue";
7
+ import "./custom.css";
8
+ import "./custom-app.css";
9
9
 
10
10
  export default {
11
11
  extends: DefaultTheme,
12
12
  Layout: Layout,
13
13
  enhanceApp({ app, router }) {
14
- app.component('DiagramModal', DiagramModal)
15
- app.component('CodeBlock', CodeBlock)
16
- app.component('ClientGrid', ClientGrid)
17
- app.component('FundingLayout', FundingLayout)
14
+ app.component("DiagramModal", DiagramModal);
15
+ app.component("CodeBlock", CodeBlock);
16
+ app.component("ClientGrid", ClientGrid);
17
+ app.component("FundingLayout", FundingLayout);
18
18
  },
19
19
  setup() {
20
20
  // Force dark mode on initial load
21
- if (typeof window !== 'undefined' && !localStorage.getItem('vitepress-theme-appearance')) {
22
- localStorage.setItem('vitepress-theme-appearance', 'dark')
21
+ if (
22
+ typeof window !== "undefined" &&
23
+ !localStorage.getItem("vitepress-theme-appearance")
24
+ ) {
25
+ localStorage.setItem("vitepress-theme-appearance", "dark");
23
26
  }
24
- }
25
- }
27
+ },
28
+ };
@@ -8,12 +8,13 @@ Coolors MCP ensures color choices meet accessibility standards through comprehen
8
8
 
9
9
  The Web Content Accessibility Guidelines (WCAG) define contrast requirements for readable content:
10
10
 
11
- | Level | Normal Text | Large Text | Non-Text |
12
- |-------|------------|------------|----------|
13
- | **AA** | 4.5:1 | 3:1 | 3:1 |
14
- | **AAA** | 7:1 | 4.5:1 | N/A |
11
+ | Level | Normal Text | Large Text | Non-Text |
12
+ | ------- | ----------- | ---------- | -------- |
13
+ | **AA** | 4.5:1 | 3:1 | 3:1 |
14
+ | **AAA** | 7:1 | 4.5:1 | N/A |
15
15
 
16
16
  **Large text** is defined as:
17
+
17
18
  - 18pt (24px) or larger
18
19
  - 14pt (18.5px) or larger if bold
19
20
 
@@ -24,11 +25,9 @@ Contrast ratio is based on relative luminance:
24
25
  ```javascript
25
26
  // Relative luminance calculation
26
27
  function getLuminance(rgb) {
27
- const [r, g, b] = rgb.map(val => {
28
+ const [r, g, b] = rgb.map((val) => {
28
29
  val = val / 255;
29
- return val <= 0.03928
30
- ? val / 12.92
31
- : Math.pow((val + 0.055) / 1.055, 2.4);
30
+ return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);
32
31
  });
33
32
 
34
33
  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
@@ -59,19 +58,19 @@ function getContrastRatio(color1, color2) {
59
58
 
60
59
  HCT's tone component directly correlates with contrast:
61
60
 
62
- | Tone Difference | Approximate Contrast | Use Case |
63
- |-----------------|---------------------|----------|
64
- | 40 | ~3:1 | Large text, UI elements |
65
- | 50 | ~4.5:1 | Normal text (AA) |
66
- | 70 | ~7:1 | Enhanced (AAA) |
67
- | 90 | ~15:1 | Maximum readability |
61
+ | Tone Difference | Approximate Contrast | Use Case |
62
+ | --------------- | -------------------- | ----------------------- |
63
+ | 40 | ~3:1 | Large text, UI elements |
64
+ | 50 | ~4.5:1 | Normal text (AA) |
65
+ | 70 | ~7:1 | Enhanced (AAA) |
66
+ | 90 | ~15:1 | Maximum readability |
68
67
 
69
68
  ### Predictable Relationships
70
69
 
71
70
  ```javascript
72
71
  // Guaranteed accessible pairs in HCT
73
- const background = { h: 200, c: 20, t: 95 }; // Light surface
74
- const text = { h: 200, c: 20, t: 20 }; // Dark text
72
+ const background = { h: 200, c: 20, t: 95 }; // Light surface
73
+ const text = { h: 200, c: 20, t: 20 }; // Dark text
75
74
  // Tone difference: 75 = guaranteed 7:1+ contrast
76
75
  ```
77
76
 
@@ -117,7 +116,9 @@ const text = { h: 200, c: 20, t: 20 }; // Dark text
117
116
  ## Material Design Contrast Levels
118
117
 
119
118
  ### Default Contrast (0.0)
119
+
120
120
  Meets AA accessibility:
121
+
121
122
  - **Guaranteed minimums**:
122
123
  - 4.5:1 for all text and icons
123
124
  - 3:1 for required non-text elements
@@ -125,7 +126,9 @@ Meets AA accessibility:
125
126
  - 7:1 for high emphasis text
126
127
 
127
128
  ### Medium Contrast (+0.5)
129
+
128
130
  Exceeds AA requirements:
131
+
129
132
  - **Guaranteed minimums**:
130
133
  - 4.5:1 for all text
131
134
  - 3:1 for all non-text elements
@@ -134,7 +137,9 @@ Exceeds AA requirements:
134
137
  - 11:1 for high emphasis
135
138
 
136
139
  ### High Contrast (+1.0)
140
+
137
141
  Meets AAA accessibility:
142
+
138
143
  - **Guaranteed minimums**:
139
144
  - 7:1 for all text and icons
140
145
  - 4.5:1 for all non-text elements
@@ -196,9 +201,9 @@ function getAccessibleTextColor(background) {
196
201
 
197
202
  // Use white or black based on background
198
203
  if (bgLuminance > 0.5) {
199
- return '#000000'; // Dark text on light background
204
+ return "#000000"; // Dark text on light background
200
205
  } else {
201
- return '#ffffff'; // Light text on dark background
206
+ return "#ffffff"; // Light text on dark background
202
207
  }
203
208
  }
204
209
  ```
@@ -209,12 +214,12 @@ function getAccessibleTextColor(background) {
209
214
 
210
215
  Material Design ensures these pairs always meet contrast requirements:
211
216
 
212
- | Background | Foreground | Min Contrast | Use Case |
213
- |------------|------------|--------------|----------|
214
- | surface | onSurface | 4.5:1 | Main content |
215
- | primary | onPrimary | 4.5:1 | Primary actions |
216
- | primaryContainer | onPrimaryContainer | 4.5:1 | Containers |
217
- | error | onError | 4.5:1 | Error states |
217
+ | Background | Foreground | Min Contrast | Use Case |
218
+ | ---------------- | ------------------ | ------------ | --------------- |
219
+ | surface | onSurface | 4.5:1 | Main content |
220
+ | primary | onPrimary | 4.5:1 | Primary actions |
221
+ | primaryContainer | onPrimaryContainer | 4.5:1 | Containers |
222
+ | error | onError | 4.5:1 | Error states |
218
223
 
219
224
  ### Role-Based Adjustments
220
225
 
@@ -225,17 +230,17 @@ function assignColorRoles(sourceColor, contrastLevel = 0) {
225
230
 
226
231
  // Adjust tone mappings based on contrast level
227
232
  const toneMap = {
228
- primary: 40 - (contrastLevel * 10),
233
+ primary: 40 - contrastLevel * 10,
229
234
  onPrimary: 100,
230
- primaryContainer: 90 + (contrastLevel * 5),
231
- onPrimaryContainer: 10 - (contrastLevel * 5)
235
+ primaryContainer: 90 + contrastLevel * 5,
236
+ onPrimaryContainer: 10 - contrastLevel * 5,
232
237
  };
233
238
 
234
239
  // Ensure minimum contrast
235
240
  return Object.entries(toneMap).map(([role, tone]) => ({
236
241
  role,
237
242
  color: palette[tone],
238
- meetsContrast: true
243
+ meetsContrast: true,
239
244
  }));
240
245
  }
241
246
  ```
@@ -245,6 +250,7 @@ function assignColorRoles(sourceColor, contrastLevel = 0) {
245
250
  ### Design Guidelines
246
251
 
247
252
  #### DO's
253
+
248
254
  - ✅ Test all color combinations for contrast
249
255
  - ✅ Provide high contrast mode options
250
256
  - ✅ Use semantic color roles consistently
@@ -252,6 +258,7 @@ function assignColorRoles(sourceColor, contrastLevel = 0) {
252
258
  - ✅ Test with real content, not just color swatches
253
259
 
254
260
  #### DON'Ts
261
+
255
262
  - ❌ Rely on color alone to convey information
256
263
  - ❌ Use low contrast for aesthetic reasons
257
264
  - ❌ Assume large text allows poor contrast
@@ -261,6 +268,7 @@ function assignColorRoles(sourceColor, contrastLevel = 0) {
261
268
  ### Testing Strategies
262
269
 
263
270
  #### Automated Testing
271
+
264
272
  ```javascript
265
273
  // Test all color combinations in theme
266
274
  function testThemeAccessibility(theme) {
@@ -276,7 +284,7 @@ function testThemeAccessibility(theme) {
276
284
  context,
277
285
  ratio,
278
286
  passes: ratio >= required,
279
- recommendation: getRecommendation(ratio, context)
287
+ recommendation: getRecommendation(ratio, context),
280
288
  });
281
289
  });
282
290
 
@@ -285,6 +293,7 @@ function testThemeAccessibility(theme) {
285
293
  ```
286
294
 
287
295
  #### Manual Testing
296
+
288
297
  1. **Blur test**: Blur your vision - can you still read it?
289
298
  2. **Grayscale test**: Convert to grayscale - still distinguishable?
290
299
  3. **Sunlight test**: View in bright light conditions
@@ -297,14 +306,15 @@ function testThemeAccessibility(theme) {
297
306
 
298
307
  Approximately 8% of men and 0.5% of women have color vision deficiency:
299
308
 
300
- | Type | Frequency | Description | Design Impact |
301
- |------|-----------|-------------|---------------|
302
- | Protanopia | 1.3% | No red cones | Red/green confusion |
303
- | Deuteranopia | 1.2% | No green cones | Red/green confusion |
304
- | Tritanopia | 0.001% | No blue cones | Blue/yellow confusion |
305
- | Monochromacy | Rare | No color vision | Rely on contrast only |
309
+ | Type | Frequency | Description | Design Impact |
310
+ | ------------ | --------- | --------------- | --------------------- |
311
+ | Protanopia | 1.3% | No red cones | Red/green confusion |
312
+ | Deuteranopia | 1.2% | No green cones | Red/green confusion |
313
+ | Tritanopia | 0.001% | No blue cones | Blue/yellow confusion |
314
+ | Monochromacy | Rare | No color vision | Rely on contrast only |
306
315
 
307
316
  #### Design Strategies
317
+
308
318
  ```javascript
309
319
  // Ensure information isn't conveyed by color alone
310
320
  ✓ Error: "❌ Invalid input" (icon + text)
@@ -326,15 +336,15 @@ Dark themes require special attention:
326
336
  ```javascript
327
337
  // Light theme
328
338
  const lightTheme = {
329
- surface: { tone: 99 }, // Very light
330
- onSurface: { tone: 10 }, // Very dark
339
+ surface: { tone: 99 }, // Very light
340
+ onSurface: { tone: 10 }, // Very dark
331
341
  // Contrast: ~15:1
332
342
  };
333
343
 
334
344
  // Dark theme - NOT just inverted
335
345
  const darkTheme = {
336
- surface: { tone: 10 }, // Very dark
337
- onSurface: { tone: 90 }, // Light, not white
346
+ surface: { tone: 10 }, // Very dark
347
+ onSurface: { tone: 90 }, // Light, not white
338
348
  // Contrast: ~13:1 (slightly less harsh)
339
349
  };
340
350
  ```
@@ -354,9 +364,9 @@ function getEffectiveColor(foreground, background, alpha) {
354
364
 
355
365
  // Ensure minimum opacity for text
356
366
  const minOpacity = {
357
- normalText: 0.87, // ~87% opacity minimum
358
- secondaryText: 0.60, // ~60% for secondary
359
- disabledText: 0.38 // ~38% for disabled
367
+ normalText: 0.87, // ~87% opacity minimum
368
+ secondaryText: 0.6, // ~60% for secondary
369
+ disabledText: 0.38, // ~38% for disabled
360
370
  };
361
371
  ```
362
372
 
@@ -366,7 +376,7 @@ const minOpacity = {
366
376
 
367
377
  ```jsx
368
378
  function AccessibleButton({ color, children }) {
369
- const [textColor, setTextColor] = useState('#ffffff');
379
+ const [textColor, setTextColor] = useState("#ffffff");
370
380
 
371
381
  useEffect(() => {
372
382
  // Automatically choose accessible text color
@@ -378,7 +388,7 @@ function AccessibleButton({ color, children }) {
378
388
  <button
379
389
  style={{
380
390
  backgroundColor: color,
381
- color: textColor
391
+ color: textColor,
382
392
  }}
383
393
  aria-label={children}
384
394
  >
@@ -434,14 +444,14 @@ class AccessibilityValidator {
434
444
  background,
435
445
  ratio,
436
446
  required: this.minRatio,
437
- suggestion: this.suggestFix(color, background)
447
+ suggestion: this.suggestFix(color, background),
438
448
  });
439
449
  }
440
450
  });
441
451
 
442
452
  return {
443
453
  valid: issues.length === 0,
444
- issues
454
+ issues,
445
455
  };
446
456
  }
447
457
 
@@ -454,6 +464,7 @@ class AccessibilityValidator {
454
464
  ## Resources
455
465
 
456
466
  ### Testing Tools
467
+
457
468
  - Chrome DevTools (Lighthouse)
458
469
  - Firefox Accessibility Inspector
459
470
  - axe DevTools
@@ -461,6 +472,7 @@ class AccessibilityValidator {
461
472
  - Stark (Figma/Sketch plugin)
462
473
 
463
474
  ### Guidelines
475
+
464
476
  - [WCAG 2.1](https://www.w3.org/WAI/WCAG21/quickref/)
465
477
  - [Material Design Accessibility](https://m3.material.io/foundations/accessible-design)
466
478
  - [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
@@ -470,4 +482,4 @@ class AccessibilityValidator {
470
482
  - [HCT System](./hct.md) - Tone-based contrast
471
483
  - [Material Design](./material-design.md) - Contrast levels
472
484
  - [Theme Matching](./theme-matching.md) - Accessibility scoring
473
- - [Color Spaces](./color-spaces.md) - Understanding luminance
485
+ - [Color Spaces](./color-spaces.md) - Understanding luminance