@cogenta/theme-association 0.3.3 → 0.5.4

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 (148) hide show
  1. package/dist/src/index.d.ts +6 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +9 -0
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/render/blocks/accordion.d.ts.map +1 -1
  6. package/dist/src/render/blocks/accordion.js +13 -10
  7. package/dist/src/render/blocks/accordion.js.map +1 -1
  8. package/dist/src/render/blocks/breakdown.d.ts +14 -0
  9. package/dist/src/render/blocks/breakdown.d.ts.map +1 -0
  10. package/dist/src/render/blocks/breakdown.js +17 -0
  11. package/dist/src/render/blocks/breakdown.js.map +1 -0
  12. package/dist/src/render/blocks/collection-list.d.ts +4 -10
  13. package/dist/src/render/blocks/collection-list.d.ts.map +1 -1
  14. package/dist/src/render/blocks/collection-list.js +89 -58
  15. package/dist/src/render/blocks/collection-list.js.map +1 -1
  16. package/dist/src/render/blocks/cta.d.ts +0 -5
  17. package/dist/src/render/blocks/cta.d.ts.map +1 -1
  18. package/dist/src/render/blocks/cta.js +22 -10
  19. package/dist/src/render/blocks/cta.js.map +1 -1
  20. package/dist/src/render/blocks/embed.d.ts.map +1 -1
  21. package/dist/src/render/blocks/embed.js +30 -22
  22. package/dist/src/render/blocks/embed.js.map +1 -1
  23. package/dist/src/render/blocks/faq.d.ts.map +1 -1
  24. package/dist/src/render/blocks/faq.js +11 -15
  25. package/dist/src/render/blocks/faq.js.map +1 -1
  26. package/dist/src/render/blocks/feature-grid.d.ts +6 -0
  27. package/dist/src/render/blocks/feature-grid.d.ts.map +1 -1
  28. package/dist/src/render/blocks/feature-grid.js +42 -20
  29. package/dist/src/render/blocks/feature-grid.js.map +1 -1
  30. package/dist/src/render/blocks/gallery.d.ts +9 -7
  31. package/dist/src/render/blocks/gallery.d.ts.map +1 -1
  32. package/dist/src/render/blocks/gallery.js +22 -16
  33. package/dist/src/render/blocks/gallery.js.map +1 -1
  34. package/dist/src/render/blocks/hero.d.ts +23 -9
  35. package/dist/src/render/blocks/hero.d.ts.map +1 -1
  36. package/dist/src/render/blocks/hero.js +40 -23
  37. package/dist/src/render/blocks/hero.js.map +1 -1
  38. package/dist/src/render/blocks/logo-strip.d.ts +6 -0
  39. package/dist/src/render/blocks/logo-strip.d.ts.map +1 -1
  40. package/dist/src/render/blocks/logo-strip.js +7 -9
  41. package/dist/src/render/blocks/logo-strip.js.map +1 -1
  42. package/dist/src/render/blocks/logos.d.ts +14 -0
  43. package/dist/src/render/blocks/logos.d.ts.map +1 -1
  44. package/dist/src/render/blocks/logos.js +30 -16
  45. package/dist/src/render/blocks/logos.js.map +1 -1
  46. package/dist/src/render/blocks/media-figure.d.ts +12 -5
  47. package/dist/src/render/blocks/media-figure.d.ts.map +1 -1
  48. package/dist/src/render/blocks/media-figure.js +32 -18
  49. package/dist/src/render/blocks/media-figure.js.map +1 -1
  50. package/dist/src/render/blocks/pricing-table.d.ts.map +1 -1
  51. package/dist/src/render/blocks/pricing-table.js +18 -20
  52. package/dist/src/render/blocks/pricing-table.js.map +1 -1
  53. package/dist/src/render/blocks/prose.d.ts +9 -3
  54. package/dist/src/render/blocks/prose.d.ts.map +1 -1
  55. package/dist/src/render/blocks/prose.js +11 -4
  56. package/dist/src/render/blocks/prose.js.map +1 -1
  57. package/dist/src/render/blocks/quote.d.ts +4 -7
  58. package/dist/src/render/blocks/quote.d.ts.map +1 -1
  59. package/dist/src/render/blocks/quote.js +12 -17
  60. package/dist/src/render/blocks/quote.js.map +1 -1
  61. package/dist/src/render/blocks/stat-counter.d.ts +8 -1
  62. package/dist/src/render/blocks/stat-counter.d.ts.map +1 -1
  63. package/dist/src/render/blocks/stat-counter.js +18 -10
  64. package/dist/src/render/blocks/stat-counter.js.map +1 -1
  65. package/dist/src/render/blocks/stats.d.ts +12 -1
  66. package/dist/src/render/blocks/stats.d.ts.map +1 -1
  67. package/dist/src/render/blocks/stats.js +24 -14
  68. package/dist/src/render/blocks/stats.js.map +1 -1
  69. package/dist/src/render/blocks/testimonial.d.ts +6 -5
  70. package/dist/src/render/blocks/testimonial.d.ts.map +1 -1
  71. package/dist/src/render/blocks/testimonial.js +13 -11
  72. package/dist/src/render/blocks/testimonial.js.map +1 -1
  73. package/dist/src/render/chrome.d.ts +38 -1
  74. package/dist/src/render/chrome.d.ts.map +1 -1
  75. package/dist/src/render/chrome.js +117 -91
  76. package/dist/src/render/chrome.js.map +1 -1
  77. package/dist/src/render/details.d.ts +79 -0
  78. package/dist/src/render/details.d.ts.map +1 -0
  79. package/dist/src/render/details.js +221 -0
  80. package/dist/src/render/details.js.map +1 -0
  81. package/dist/src/render/figures.d.ts +29 -0
  82. package/dist/src/render/figures.d.ts.map +1 -0
  83. package/dist/src/render/figures.js +59 -0
  84. package/dist/src/render/figures.js.map +1 -0
  85. package/dist/src/render/layout.d.ts +31 -0
  86. package/dist/src/render/layout.d.ts.map +1 -0
  87. package/dist/src/render/layout.js +46 -0
  88. package/dist/src/render/layout.js.map +1 -0
  89. package/dist/src/render/page-head.d.ts +7 -0
  90. package/dist/src/render/page-head.d.ts.map +1 -0
  91. package/dist/src/render/page-head.js +95 -0
  92. package/dist/src/render/page-head.js.map +1 -0
  93. package/dist/src/render/render-block.d.ts +8 -12
  94. package/dist/src/render/render-block.d.ts.map +1 -1
  95. package/dist/src/render/render-block.js +40 -29
  96. package/dist/src/render/render-block.js.map +1 -1
  97. package/dist/src/render/strings.d.ts +15 -0
  98. package/dist/src/render/strings.d.ts.map +1 -0
  99. package/dist/src/render/strings.js +39 -0
  100. package/dist/src/render/strings.js.map +1 -0
  101. package/dist/src/render/term-archive.d.ts.map +1 -1
  102. package/dist/src/render/term-archive.js +33 -25
  103. package/dist/src/render/term-archive.js.map +1 -1
  104. package/dist/src/render/widget-areas.d.ts +14 -0
  105. package/dist/src/render/widget-areas.d.ts.map +1 -0
  106. package/dist/src/render/widget-areas.js +21 -0
  107. package/dist/src/render/widget-areas.js.map +1 -0
  108. package/dist/theme.config.d.ts +1 -1
  109. package/dist/theme.config.js +3 -3
  110. package/dist/theme.config.js.map +1 -1
  111. package/package.json +5 -5
  112. package/src/index.ts +9 -0
  113. package/src/render/blocks/accordion.ts +28 -22
  114. package/src/render/blocks/breakdown.ts +42 -0
  115. package/src/render/blocks/collection-list.ts +234 -103
  116. package/src/render/blocks/cta.ts +48 -19
  117. package/src/render/blocks/embed.ts +47 -29
  118. package/src/render/blocks/faq.ts +22 -31
  119. package/src/render/blocks/feature-grid.ts +73 -41
  120. package/src/render/blocks/gallery.ts +32 -26
  121. package/src/render/blocks/hero.ts +56 -43
  122. package/src/render/blocks/logo-strip.ts +23 -21
  123. package/src/render/blocks/logos.ts +45 -40
  124. package/src/render/blocks/media-figure.ts +49 -24
  125. package/src/render/blocks/pricing-table.ts +31 -40
  126. package/src/render/blocks/prose.ts +16 -6
  127. package/src/render/blocks/quote.ts +34 -27
  128. package/src/render/blocks/stat-counter.ts +35 -29
  129. package/src/render/blocks/stats.ts +46 -38
  130. package/src/render/blocks/testimonial.ts +29 -20
  131. package/src/render/chrome.ts +165 -91
  132. package/src/render/details.ts +276 -0
  133. package/src/render/figures.ts +68 -0
  134. package/src/render/layout.ts +78 -0
  135. package/src/render/page-head.ts +193 -0
  136. package/src/render/render-block.ts +45 -32
  137. package/src/render/strings.ts +74 -0
  138. package/src/render/term-archive.ts +94 -58
  139. package/src/render/widget-areas.ts +24 -0
  140. package/src/styles/archive.css +38 -102
  141. package/src/styles/base.css +503 -554
  142. package/src/styles/blocks.css +913 -666
  143. package/src/styles/chrome.css +506 -0
  144. package/src/styles/listings.css +591 -0
  145. package/src/styles/theme.css +25 -19
  146. package/src/styles/tokens.css +284 -234
  147. package/src/styles/widgets.css +1059 -0
  148. package/tokens.json +18 -18
@@ -1,28 +1,32 @@
1
1
  /*
2
2
  * `@cogenta/theme-association`'s design system.
3
3
  *
4
- * Contract D fixes a *closed* skin token set — seven colours, five type
5
- * tokens, two spacing tokens, three radii, three motion tokens, two shadows
6
- * — and refuses any skin that adds one. So this layer adds nothing to the
7
- * skin: every value below is *derived* from `--cogenta-*` by composition
8
- * (`calc`, `color-mix`, relative colour syntax). A skin swap rewrites the
9
- * generated `--cogenta-*` sheet and this whole system follows, with no
10
- * build step.
4
+ * The register is a neighbourhood charity that people trust with their food,
5
+ * their children's homework and their Saturday mornings: warm paper and a
6
+ * green-black ink, the people in the photographs and the numbers carrying the
7
+ * page, plain words set large. One deep green is the organisation's own
8
+ * colour (links, figures, the footer band, the filled button). One marigold
9
+ * yellow is kept for the donation ask and nothing else: the header's standing
10
+ * action, the hero's first action and the band that asks for a gift.
11
11
  *
12
- * Two rules hold everywhere in this file and the two that import it:
12
+ * Two families. Bricolage Grotesque sets what a visitor reads first: the
13
+ * statement of the cause, titles, figures, dates, quotations. Its optical
14
+ * size follows the font size, and the display sizes are set a little narrow
15
+ * (`font-stretch`) so a long, honest sentence still fits two lines. Source
16
+ * Sans 3 sets everything a visitor reads to act: running text, navigation,
17
+ * labels, times and places. The skin names Bricolage in its `serif` slot,
18
+ * which this theme reads as its display slot.
13
19
  *
14
- * 1. **No colour literal.** Not one hex, `rgb()`, `hsl()` or bare `oklch()`.
15
- * Every colour is either a skin token or a function *of* a skin token.
16
- * 2. **No second scale.** The type steps come from `--cogenta-font-size-*`
17
- * and the spacing multiplier from `--cogenta-space-scale`, both emitted
18
- * by `renderSkin` from the same tokens the validator checked.
20
+ * Contract D fixes a closed skin token set, so nothing here adds a token:
21
+ * every value is derived from a `--cogenta-*` property (`calc`, `color-mix`,
22
+ * relative colour syntax).
19
23
  *
20
- * The default skin (`tokens.json`) is a warm, human palette: a deep forest
21
- * green on a warm ivory ground, generous rounded corners (`--cg-radius-lg`
22
- * lands at 14px, the brief's own number) and soft shadows rather than
23
- * hairlines — a community notice board, not a corporate report cover. The
24
- * dark mode is designed on its own terms (see the colour section below for
25
- * the choices that make it so), never a mechanical inversion.
24
+ * Two rules hold in every stylesheet of this theme:
25
+ *
26
+ * 1. No colour literal. Every colour is a skin token or a function of one.
27
+ * 2. No second scale. Type steps come from `--cogenta-font-size-*`; the
28
+ * display steps above `3xl` continue the same ratio, and fluid sizes only
29
+ * interpolate between steps of that one ladder.
26
30
  */
27
31
 
28
32
  :where(:root) {
@@ -38,295 +42,341 @@
38
42
  }
39
43
 
40
44
  /* --------------------------------------------------------------------------
41
- Space
45
+ Space: one unit, one section rhythm, one twelve-column grid.
42
46
  -------------------------------------------------------------------------- */
43
47
 
44
48
  :where(:root) {
45
- --cg-density: var(--cogenta-space-scale, 1);
46
- --cg-unit: calc(var(--cogenta-space-unit) * var(--cg-density));
47
-
48
- --cg-s1: calc(var(--cg-unit) * 1);
49
- --cg-s2: calc(var(--cg-unit) * 2);
50
- --cg-s3: calc(var(--cg-unit) * 3);
51
- --cg-s4: calc(var(--cg-unit) * 4);
52
- --cg-s5: calc(var(--cg-unit) * 5);
53
- --cg-s6: calc(var(--cg-unit) * 6);
54
- --cg-s8: calc(var(--cg-unit) * 8);
55
- --cg-s10: calc(var(--cg-unit) * 10);
56
- --cg-s12: calc(var(--cg-unit) * 12);
57
- --cg-s16: calc(var(--cg-unit) * 16);
58
- --cg-s20: calc(var(--cg-unit) * 20);
59
- --cg-s28: calc(var(--cg-unit) * 28);
60
-
61
- --cg-gutter: var(--cg-s6);
62
- --cg-gap-tight: var(--cg-s2);
63
- --cg-gap: var(--cg-s5);
64
- --cg-gap-loose: var(--cg-s10);
65
- --cg-section-y: var(--cg-s20);
66
-
67
- --cg-measure: 68ch;
68
- --cg-measure-narrow: 44ch;
69
- --cg-page: 76rem;
70
- --cg-page-narrow: 50rem;
49
+ --ca-density: var(--cogenta-space-scale, 1);
50
+ --ca-unit: calc(var(--cogenta-space-unit) * var(--ca-density));
51
+
52
+ --ca-s1: calc(var(--ca-unit) * 1);
53
+ --ca-s2: calc(var(--ca-unit) * 2);
54
+ --ca-s3: calc(var(--ca-unit) * 3);
55
+ --ca-s4: calc(var(--ca-unit) * 4);
56
+ --ca-s5: calc(var(--ca-unit) * 5);
57
+ --ca-s6: calc(var(--ca-unit) * 6);
58
+ --ca-s8: calc(var(--ca-unit) * 8);
59
+ --ca-s10: calc(var(--ca-unit) * 10);
60
+ --ca-s12: calc(var(--ca-unit) * 12);
61
+ --ca-s16: calc(var(--ca-unit) * 16);
62
+ --ca-s20: calc(var(--ca-unit) * 20);
63
+ --ca-s24: calc(var(--ca-unit) * 24);
64
+ --ca-s28: calc(var(--ca-unit) * 28);
65
+
66
+ /* The only vertical rhythm between blocks. Every block is padded by half of
67
+ it above and below, so any two blocks sit one full step apart, whatever
68
+ their order. */
69
+ --ca-section: clamp(var(--ca-s16), 8vw, var(--ca-s28));
70
+
71
+ --ca-columns: 12;
72
+ --ca-gutter: clamp(var(--ca-s5), 4vw, var(--ca-s12));
73
+ --ca-col-gap: clamp(var(--ca-s4), 2vw, var(--ca-s8));
74
+ --ca-page: 78rem;
75
+ /* The distance from the window's edge to the first column. */
76
+ --ca-edge: max(var(--ca-gutter), calc((100vw - var(--ca-page)) / 2));
77
+
78
+ --ca-measure: 66ch;
79
+ --ca-header-height: 4.5rem;
71
80
  }
72
81
 
73
82
  :where([data-density="compact"]) {
74
- --cg-density: 0.85;
83
+ --ca-density: 0.75;
75
84
  }
76
85
 
77
86
  :where([data-density="comfortable"]) {
78
- --cg-density: 1;
87
+ --ca-density: 1;
79
88
  }
80
89
 
81
90
  :where([data-density="spacious"]) {
82
- --cg-density: 1.2;
91
+ --ca-density: 1.25;
83
92
  }
84
93
 
85
94
  /* --------------------------------------------------------------------------
86
- Type — the skin's scale, named; plus the rhythm the scale does not carry.
95
+ Type: a display grotesque and a text face.
87
96
  -------------------------------------------------------------------------- */
88
97
 
89
98
  :where(:root) {
90
- --cg-text-xs: var(--cogenta-font-size-xs, 0.72rem);
91
- --cg-text-sm: var(--cogenta-font-size-sm, 0.86rem);
92
- --cg-text-md: var(--cogenta-font-size-md, var(--cogenta-font-base-size, 1rem));
93
- --cg-text-lg: var(--cogenta-font-size-lg, 1.2rem);
94
- --cg-text-xl: var(--cogenta-font-size-xl, 1.5rem);
95
- --cg-text-2xl: var(--cogenta-font-size-2xl, 1.9rem);
96
- --cg-text-3xl: var(--cogenta-font-size-3xl, 2.6rem);
97
-
98
- --cg-leading-tight: 1.12;
99
- --cg-leading-snug: 1.28;
100
- --cg-leading-normal: 1.6;
101
- --cg-leading-relaxed: 1.75;
102
-
103
- --cg-tracking-tight: -0.01em;
104
- --cg-tracking-snug: -0.004em;
105
- --cg-tracking-normal: 0em;
106
- --cg-tracking-wide: 0.08em;
107
-
108
- --cg-weight-regular: 400;
109
- --cg-weight-medium: 500;
110
- --cg-weight-semibold: 600;
111
- --cg-weight-bold: 800;
112
-
113
- /* Headings use the theme's own display family (`tokens.json`'s
114
- `font.serif` slot repurposed for Nunito — a rounded, humanist face, not
115
- a literal serif; see `theme.css`'s own comment). Body text stays on
116
- `font.sans` (Source Sans 3). */
117
- --cg-font-display: var(--cogenta-font-serif);
99
+ --ca-font-display: var(--cogenta-font-serif);
100
+ --ca-font-text: var(--cogenta-font-sans);
101
+ --ca-font-code: var(--cogenta-font-mono);
102
+
103
+ --ca-text-xs: var(--cogenta-font-size-xs, 0.68rem);
104
+ --ca-text-sm: var(--cogenta-font-size-sm, 0.85rem);
105
+ --ca-text-md: var(--cogenta-font-size-md, var(--cogenta-font-base-size, 1.0625rem));
106
+ --ca-text-lg: var(--cogenta-font-size-lg, 1.33rem);
107
+ --ca-text-xl: var(--cogenta-font-size-xl, 1.66rem);
108
+ --ca-text-2xl: var(--cogenta-font-size-2xl, 2.08rem);
109
+ --ca-text-3xl: var(--cogenta-font-size-3xl, 2.59rem);
110
+ /* The same ladder, continued: each step is the previous one times the
111
+ skin's own ratio. */
112
+ --ca-text-4xl: calc(var(--ca-text-3xl) * var(--cogenta-font-scale, 1.25));
113
+ --ca-text-5xl: calc(var(--ca-text-4xl) * var(--cogenta-font-scale, 1.25));
114
+ --ca-text-6xl: calc(var(--ca-text-5xl) * var(--cogenta-font-scale, 1.25));
115
+
116
+ /* Labels, captions and small print sit between `sm` and `md`. */
117
+ --ca-text-caption: calc((var(--ca-text-sm) + var(--ca-text-md)) / 2);
118
+
119
+ --ca-size-statement: clamp(var(--ca-text-3xl), calc(1rem + 3.9vw), var(--ca-text-5xl));
120
+ --ca-size-title: clamp(var(--ca-text-2xl), calc(1rem + 3vw), var(--ca-text-4xl));
121
+ --ca-size-section: clamp(var(--ca-text-xl), calc(0.9rem + 1.7vw), var(--ca-text-3xl));
122
+ --ca-size-item: clamp(var(--ca-text-lg), calc(0.9rem + 0.9vw), var(--ca-text-2xl));
123
+ --ca-size-figure: clamp(var(--ca-text-2xl), calc(1rem + 2.6vw), var(--ca-text-4xl));
124
+ --ca-size-day: clamp(var(--ca-text-2xl), calc(1rem + 1.8vw), var(--ca-text-4xl));
125
+ --ca-size-day-large: clamp(var(--ca-text-4xl), calc(1rem + 5vw), var(--ca-text-6xl));
126
+ --ca-size-quote: clamp(var(--ca-text-lg), calc(0.95rem + 1vw), var(--ca-text-2xl));
127
+ --ca-size-lead: clamp(var(--ca-text-md), calc(0.9rem + 0.55vw), var(--ca-text-lg));
128
+ --ca-size-nav: clamp(var(--ca-text-xl), calc(1rem + 3vw), var(--ca-text-2xl));
129
+ --ca-size-wordmark: clamp(var(--ca-text-lg), calc(1rem + 0.3vw), var(--ca-text-xl));
130
+
131
+ --ca-leading-display: 1.02;
132
+ --ca-leading-heading: 1.1;
133
+ --ca-leading-lead: 1.45;
134
+ --ca-leading-text: 1.6;
135
+ --ca-leading-ui: 1.35;
136
+
137
+ --ca-tracking-display: -0.022em;
138
+ --ca-tracking-heading: -0.012em;
139
+ /* Small capitals need a little air between them to read as a word. */
140
+ --ca-tracking-caps: 0.06em;
141
+
142
+ /* Bricolage Grotesque's width axis runs from 75% to 100%. */
143
+ --ca-stretch-display: 88%;
144
+ --ca-stretch-figure: 84%;
145
+
146
+ --ca-weight-regular: 400;
147
+ --ca-weight-medium: 500;
148
+ --ca-weight-semibold: 600;
149
+ --ca-weight-bold: 700;
118
150
  }
119
151
 
120
152
  /* --------------------------------------------------------------------------
121
- Radius — generously rounded, the brief's own "14px cards": `--cg-radius-md`
122
- is the skin's own `radius.md` (14px in `tokens.json`), used for cards;
123
- `--cg-radius-lg` is bigger again for the hero frame and the impact band.
124
- `--cg-radius-pill` is used freely for buttons, badges and the eyebrow tag.
153
+ Shape and motion: corners softened by a hair, motion is a colour or an
154
+ underline.
125
155
  -------------------------------------------------------------------------- */
126
156
 
127
157
  :where(:root) {
128
- --cg-radius-xs: calc(var(--cogenta-radius-sm) / 2);
129
- --cg-radius-sm: var(--cogenta-radius-sm);
130
- --cg-radius-md: var(--cogenta-radius-md);
131
- --cg-radius-lg: var(--cogenta-radius-lg);
132
- --cg-radius-xl: calc(var(--cogenta-radius-lg) * 1.4);
133
- --cg-radius-pill: 999rem;
134
- }
158
+ --ca-radius: 0;
159
+ --ca-radius-control: var(--cogenta-radius-sm);
135
160
 
136
- /* --------------------------------------------------------------------------
137
- Motion
138
- -------------------------------------------------------------------------- */
161
+ --ca-duration: min(var(--cogenta-motion-duration), 150ms);
162
+ --ca-ease: var(--cogenta-motion-easing);
139
163
 
140
- :where(:root) {
141
- --cg-duration-fast: calc(var(--cogenta-motion-duration) * 0.65);
142
- --cg-duration: var(--cogenta-motion-duration);
143
- --cg-duration-slow: calc(var(--cogenta-motion-duration) * 2.6);
144
- --cg-ease: var(--cogenta-motion-easing);
164
+ --ca-rule: 1px;
165
+ --ca-rule-strong: 2px;
166
+ --ca-rule-heavy: 4px;
167
+ --ca-bar: 0.625rem;
168
+
169
+ /* An opening quotation mark hangs into the margin on a wide screen only:
170
+ on a phone the margin is the gutter, and the mark would touch the edge. */
171
+ --ca-hang: 0;
172
+ }
173
+
174
+ @media (min-width: 64rem) {
175
+ :where(:root) {
176
+ --ca-hang: -0.42em;
177
+ }
145
178
  }
146
179
 
147
180
  /* --------------------------------------------------------------------------
148
- Colour — one palette per scheme, both derived from the same seven tokens.
181
+ Colour: paper, ink, the organisation's green, and the yellow that asks.
149
182
  --------------------------------------------------------------------------
150
183
 
151
- The block below declares the **light** palette in plain terms; the
152
- scheme-aware values live in the `@supports` block after it, guarded the
153
- same way `theme-canonical` guards it: a browser that cannot parse
154
- `light-dark()` still gets a usable light palette rather than an `unset`
155
- custom property.
156
-
157
- **This dark palette is designed on its own terms, not inverted:**
158
-
159
- 1. *Canvas is forest, not charcoal.* Dark mode here is not "generic dark
160
- mode grey" — it carries the accent's own hue at very low lightness, so
161
- it reads as "the same warm place at night" rather than a different
162
- product.
163
- 2. *The accent is lifted and desaturated*, exactly the technique
164
- `theme-entreprise` proved: a forest green pushed to the light mode's
165
- own lightness on a dark canvas reads as neon; lifted to L 0.7 and pulled
166
- back a third of its chroma it still reads as the same considered green.
167
- 3. *The accent's foreground flips to ink* — light text on a lifted accent
168
- fails contrast.
169
- 4. *Ink carries a trace of warmth* rather than becoming a flat, colourless
170
- off-white — this palette's whole identity is warmth, and losing it in
171
- the one place text lives everywhere would be the mechanical-inversion
172
- mistake in miniature.
173
- 5. *A border lightens against its surface in dark, darkens in light* — a
174
- darker line on dark ink is invisible.
175
-
176
- Known limit, the same one every sibling theme records: the derivation
177
- assumes a light-first skin (`bg` lighter than `fg`).
184
+ The first block declares the light palette plainly; the scheme-aware
185
+ values follow behind a feature query, so a browser that cannot parse
186
+ `light-dark()` still gets a complete light palette.
187
+
188
+ The signal yellow is the paper's own warm hue turned up to full strength:
189
+ the skin owns the hue, this theme fixes the role's lightness and chroma.
190
+ It is never text, never a line, never a figure: only the ground of the
191
+ donation ask, with ink on it.
192
+
193
+ The dark palette is designed, not inverted. It is the hall after dark:
194
+
195
+ 1. The ground is a deep green-black, taken from the organisation's green
196
+ at a very low chroma. Bands step up in lightness.
197
+ 2. Type is the paper's own warm white, lowered a step from white.
198
+ 3. The green is lifted to a pale sage so it still reads as the same
199
+ colour on the dark ground; the filled button turns sage with ink words.
200
+ 4. The yellow stays the yellow: a donation ask does not change colour when
201
+ the lights go down. Its words stay ink.
202
+ 5. Hairlines are a step up in lightness from the ground.
203
+ 6. Photographs are dimmed a very little, with a brightness step; partner
204
+ wordmarks drawn in ink are inverted so they stay legible.
205
+
206
+ The footer is the green band on paper and a step below the ground in the
207
+ dark, so every page ends on its heaviest band.
208
+
209
+ Every ratio is computed from this file by `test/design-system.test.ts`,
210
+ in both schemes.
178
211
  -------------------------------------------------------------------------- */
179
212
 
180
213
  :where(:root) {
181
- --cg-canvas: var(--cogenta-color-bg);
182
- --cg-surface: var(--cogenta-color-bg);
183
- --cg-surface-raised: var(--cogenta-color-bg);
184
- --cg-surface-sunken: var(--cogenta-color-muted);
185
- --cg-surface-tinted: color-mix(in oklab, var(--cogenta-color-accent) 8%, var(--cogenta-color-bg));
186
-
187
- --cg-ink: var(--cogenta-color-fg);
188
- --cg-ink-muted: var(--cogenta-color-muted-fg);
189
- --cg-ink-subtle: color-mix(in oklab, var(--cogenta-color-muted-fg) 92%, var(--cogenta-color-bg));
190
-
191
- --cg-accent: var(--cogenta-color-accent);
192
- --cg-accent-fg: var(--cogenta-color-accent-fg);
193
- --cg-accent-hover: color-mix(in oklab, var(--cogenta-color-accent) 85%, var(--cogenta-color-fg));
194
- --cg-accent-soft: color-mix(in oklab, var(--cogenta-color-accent) 12%, var(--cogenta-color-bg));
195
- --cg-accent-soft-fg: color-mix(
214
+ --ca-canvas: var(--cogenta-color-bg);
215
+ --ca-band: var(--cogenta-color-muted);
216
+ --ca-raised: color-mix(in oklab, var(--cogenta-color-muted) 55%, var(--cogenta-color-bg));
217
+
218
+ --ca-ink: var(--cogenta-color-fg);
219
+ --ca-ink-muted: var(--cogenta-color-muted-fg);
220
+ --ca-ink-subtle: color-mix(in oklab, var(--cogenta-color-muted-fg) 85%, var(--cogenta-color-bg));
221
+
222
+ --ca-green: var(--cogenta-color-accent);
223
+ --ca-green-fg: var(--cogenta-color-accent-fg);
224
+
225
+ /* A browser without relative colour syntax cannot derive the yellow, so
226
+ the ask falls back to the organisation's green with its own words. */
227
+ --ca-signal: var(--cogenta-color-accent);
228
+ --ca-signal-ink: var(--cogenta-color-accent-fg);
229
+ --ca-signal-hover: color-mix(in oklab, var(--cogenta-color-accent) 78%, var(--cogenta-color-fg));
230
+
231
+ --ca-line: var(--cogenta-color-border);
232
+ --ca-line-strong: color-mix(in oklab, var(--cogenta-color-border) 40%, var(--cogenta-color-fg));
233
+ --ca-line-ink: var(--cogenta-color-fg);
234
+
235
+ --ca-track: var(--cogenta-color-muted);
236
+
237
+ --ca-action: var(--cogenta-color-accent);
238
+ --ca-action-fg: var(--cogenta-color-accent-fg);
239
+ --ca-action-hover: color-mix(in oklab, var(--cogenta-color-accent) 78%, var(--cogenta-color-fg));
240
+ --ca-action-hover-fg: var(--cogenta-color-accent-fg);
241
+
242
+ --ca-footer: var(--cogenta-color-accent);
243
+ --ca-footer-ink: var(--cogenta-color-accent-fg);
244
+ --ca-footer-muted: color-mix(
196
245
  in oklab,
197
- var(--cogenta-color-accent) 72%,
198
- var(--cogenta-color-fg)
246
+ var(--cogenta-color-accent-fg) 78%,
247
+ var(--cogenta-color-accent)
248
+ );
249
+ --ca-footer-line: color-mix(
250
+ in oklab,
251
+ var(--cogenta-color-accent-fg) 26%,
252
+ var(--cogenta-color-accent)
199
253
  );
200
254
 
201
- /* A warm secondary tint — sun-orange beside the deep-green accent, used
202
- sparingly (the impact band's unit text, a decorative halo). Derived by
203
- rotating the accent's own hue toward orange/red rather than a literal
204
- colour, so a site with a different accent still gets a complementary
205
- warm tint of *its own* accent. Pre-`@supports`, it is simply the accent
206
- itself — the safest fallback a browser without relative colour gets. */
207
- --cg-tint: var(--cogenta-color-accent);
208
- --cg-tint-soft: color-mix(in oklab, var(--cogenta-color-accent) 14%, var(--cogenta-color-bg));
209
-
210
- --cg-line: var(--cogenta-color-border);
211
- --cg-line-soft: color-mix(in oklab, var(--cogenta-color-border) 55%, var(--cogenta-color-bg));
212
- --cg-line-strong: color-mix(in oklab, var(--cogenta-color-border) 50%, var(--cogenta-color-fg));
255
+ --ca-image-brightness: 1;
256
+ --ca-mark-invert: 0;
257
+ --ca-mark-blend: multiply;
258
+ }
213
259
 
214
- --cg-scrim: color-mix(in oklab, var(--cogenta-color-fg) 55%, transparent);
260
+ /* Rules drawn on the yellow are its own ink, thinned: they read on the
261
+ yellow in both schemes because the yellow does not change. */
262
+ :where(:root) {
263
+ --ca-signal-line: color-mix(in oklab, var(--ca-signal-ink) 30%, var(--ca-signal));
215
264
  }
216
265
 
217
266
  @supports (color: light-dark(currentColor, currentColor)) and
218
267
  (color: oklch(from currentColor l c h)) {
219
268
  :where(:root) {
220
- --cg-canvas: light-dark(
221
- var(--cogenta-color-bg),
222
- oklch(from var(--cogenta-color-accent) 0.16 calc(c * 0.45) h)
223
- );
224
- --cg-surface: light-dark(
269
+ --ca-canvas: light-dark(
225
270
  var(--cogenta-color-bg),
226
- oklch(from var(--cogenta-color-accent) 0.16 calc(c * 0.45) h)
271
+ oklch(from var(--cogenta-color-accent) 0.215 calc(c * 0.22) h)
227
272
  );
228
- --cg-surface-raised: light-dark(
229
- var(--cogenta-color-bg),
230
- oklch(from var(--cogenta-color-accent) 0.225 calc(c * 0.42) h)
231
- );
232
- --cg-surface-sunken: light-dark(
273
+ --ca-band: light-dark(
233
274
  var(--cogenta-color-muted),
234
- oklch(from var(--cogenta-color-accent) 0.125 calc(c * 0.5) h)
275
+ oklch(from var(--cogenta-color-accent) 0.255 calc(c * 0.24) h)
235
276
  );
236
- --cg-surface-tinted: light-dark(
237
- color-mix(in oklab, var(--cogenta-color-accent) 8%, var(--cogenta-color-bg)),
238
- oklch(from var(--cogenta-color-accent) 0.24 calc(c * 0.5) h)
277
+ --ca-raised: light-dark(
278
+ color-mix(in oklab, var(--cogenta-color-muted) 55%, var(--cogenta-color-bg)),
279
+ oklch(from var(--cogenta-color-accent) 0.28 calc(c * 0.24) h)
239
280
  );
240
281
 
241
- --cg-ink: light-dark(
242
- var(--cogenta-color-fg),
243
- oklch(from var(--cogenta-color-accent) 0.94 0.014 h)
244
- );
245
- --cg-ink-muted: light-dark(
282
+ --ca-ink: light-dark(var(--cogenta-color-fg), oklch(from var(--cogenta-color-bg) 0.94 c h));
283
+ --ca-ink-muted: light-dark(
246
284
  var(--cogenta-color-muted-fg),
247
- oklch(from var(--cogenta-color-accent) 0.78 0.02 h)
285
+ oklch(from var(--cogenta-color-muted) 0.8 c h)
248
286
  );
249
- --cg-ink-subtle: light-dark(
250
- color-mix(in oklab, var(--cogenta-color-muted-fg) 92%, var(--cogenta-color-bg)),
251
- oklch(from var(--cogenta-color-accent) 0.64 0.017 h)
287
+ --ca-ink-subtle: light-dark(
288
+ color-mix(in oklab, var(--cogenta-color-muted-fg) 85%, var(--cogenta-color-bg)),
289
+ oklch(from var(--cogenta-color-muted) 0.74 c h)
252
290
  );
253
291
 
254
- --cg-accent: light-dark(
292
+ --ca-green: light-dark(
255
293
  var(--cogenta-color-accent),
256
- oklch(from var(--cogenta-color-accent) 0.7 calc(c * 0.68) h)
294
+ oklch(from var(--cogenta-color-accent) 0.8 calc(c * 0.8) h)
257
295
  );
258
- --cg-accent-fg: light-dark(
296
+ --ca-green-fg: light-dark(
259
297
  var(--cogenta-color-accent-fg),
260
- oklch(from var(--cogenta-color-accent) 0.15 calc(c * 0.45) h)
298
+ oklch(from var(--cogenta-color-accent) 0.205 calc(c * 0.22) h)
261
299
  );
262
- --cg-accent-hover: light-dark(
263
- color-mix(in oklab, var(--cogenta-color-accent) 85%, var(--cogenta-color-fg)),
264
- oklch(from var(--cogenta-color-accent) 0.79 calc(c * 0.64) h)
300
+
301
+ --ca-signal: light-dark(
302
+ oklch(from var(--cogenta-color-bg) 0.84 0.165 h),
303
+ oklch(from var(--cogenta-color-bg) 0.83 0.16 h)
265
304
  );
266
- --cg-accent-soft: light-dark(
267
- color-mix(in oklab, var(--cogenta-color-accent) 12%, var(--cogenta-color-bg)),
268
- oklch(from var(--cogenta-color-accent) 0.3 calc(c * 0.42) h)
305
+ --ca-signal-ink: light-dark(
306
+ var(--cogenta-color-fg),
307
+ oklch(from var(--cogenta-color-accent) 0.18 calc(c * 0.22) h)
269
308
  );
270
- --cg-accent-soft-fg: light-dark(
271
- color-mix(in oklab, var(--cogenta-color-accent) 72%, var(--cogenta-color-fg)),
272
- oklch(from var(--cogenta-color-accent) 0.89 calc(c * 0.36) h)
309
+ --ca-signal-hover: light-dark(
310
+ oklch(from var(--cogenta-color-bg) 0.78 0.16 h),
311
+ oklch(from var(--cogenta-color-bg) 0.9 0.13 h)
273
312
  );
274
313
 
275
- --cg-tint: light-dark(
276
- oklch(from var(--cogenta-color-accent) l c calc(h - 150)),
277
- oklch(from var(--cogenta-color-accent) 0.74 calc(c * 0.6) calc(h - 150))
314
+ --ca-line: light-dark(
315
+ var(--cogenta-color-border),
316
+ oklch(from var(--cogenta-color-accent) 0.34 calc(c * 0.22) h)
278
317
  );
279
- --cg-tint-soft: light-dark(
280
- color-mix(
281
- in oklab,
282
- oklch(from var(--cogenta-color-accent) l c calc(h - 150)) 14%,
283
- var(--cogenta-color-bg)
284
- ),
285
- oklch(from var(--cogenta-color-accent) 0.32 calc(c * 0.4) calc(h - 150))
318
+ --ca-line-strong: light-dark(
319
+ color-mix(in oklab, var(--cogenta-color-border) 40%, var(--cogenta-color-fg)),
320
+ oklch(from var(--cogenta-color-accent) 0.55 calc(c * 0.2) h)
321
+ );
322
+ --ca-line-ink: light-dark(
323
+ var(--cogenta-color-fg),
324
+ oklch(from var(--cogenta-color-bg) 0.94 c h)
286
325
  );
287
326
 
288
- --cg-line: light-dark(
289
- var(--cogenta-color-border),
290
- oklch(from var(--cogenta-color-accent) 0.36 calc(c * 0.16) h)
327
+ --ca-track: light-dark(
328
+ var(--cogenta-color-muted),
329
+ oklch(from var(--cogenta-color-accent) 0.3 calc(c * 0.24) h)
291
330
  );
292
- --cg-line-soft: light-dark(
293
- color-mix(in oklab, var(--cogenta-color-border) 55%, var(--cogenta-color-bg)),
294
- oklch(from var(--cogenta-color-accent) 0.29 calc(c * 0.14) h)
331
+
332
+ --ca-action: light-dark(
333
+ var(--cogenta-color-accent),
334
+ oklch(from var(--cogenta-color-accent) 0.8 calc(c * 0.8) h)
295
335
  );
296
- --cg-line-strong: light-dark(
297
- color-mix(in oklab, var(--cogenta-color-border) 50%, var(--cogenta-color-fg)),
298
- oklch(from var(--cogenta-color-accent) 0.56 calc(c * 0.2) h)
336
+ --ca-action-fg: light-dark(
337
+ var(--cogenta-color-accent-fg),
338
+ oklch(from var(--cogenta-color-accent) 0.18 calc(c * 0.22) h)
339
+ );
340
+ --ca-action-hover: light-dark(
341
+ color-mix(in oklab, var(--cogenta-color-accent) 78%, var(--cogenta-color-fg)),
342
+ oklch(from var(--cogenta-color-accent) 0.88 calc(c * 0.6) h)
343
+ );
344
+ --ca-action-hover-fg: light-dark(
345
+ var(--cogenta-color-accent-fg),
346
+ oklch(from var(--cogenta-color-accent) 0.18 calc(c * 0.22) h)
299
347
  );
300
- }
301
- }
302
-
303
- /* --------------------------------------------------------------------------
304
- Elevation — soft shadows over hairlines by default (the brief's own
305
- "soft shadows"), reserved to a ring only where a shadow would not read
306
- against the surface (dark mode).
307
- -------------------------------------------------------------------------- */
308
348
 
309
- :where(:root) {
310
- --cg-ring: inset 0 0 0 1px var(--cg-line);
311
- --cg-ring-accent: inset 0 0 0 1px var(--cg-accent);
312
- --cg-ring-strong: inset 0 0 0 1px var(--cg-line-strong);
313
-
314
- --cg-elevation-0: none;
315
- --cg-elevation-1: var(--cogenta-shadow-sm);
316
- --cg-elevation-2: var(--cogenta-shadow-sm);
317
- --cg-elevation-3: var(--cogenta-shadow-md);
349
+ --ca-footer: light-dark(
350
+ var(--cogenta-color-accent),
351
+ oklch(from var(--cogenta-color-accent) 0.165 calc(c * 0.2) h)
352
+ );
353
+ --ca-footer-ink: light-dark(
354
+ var(--cogenta-color-accent-fg),
355
+ oklch(from var(--cogenta-color-bg) 0.94 c h)
356
+ );
357
+ --ca-footer-muted: light-dark(
358
+ color-mix(in oklab, var(--cogenta-color-accent-fg) 78%, var(--cogenta-color-accent)),
359
+ oklch(from var(--cogenta-color-muted) 0.76 c h)
360
+ );
361
+ --ca-footer-line: light-dark(
362
+ color-mix(in oklab, var(--cogenta-color-accent-fg) 26%, var(--cogenta-color-accent)),
363
+ oklch(from var(--cogenta-color-accent) 0.3 calc(c * 0.22) h)
364
+ );
365
+ }
318
366
  }
319
367
 
368
+ /* A photograph on the dark ground is dimmed a very little; a wordmark drawn in
369
+ ink is inverted. A brightness step and an inversion, never a blur. */
320
370
  @media (prefers-color-scheme: dark) {
321
371
  :where(:root:not([data-theme="light"])) {
322
- --cg-elevation-1: var(--cg-ring);
323
- --cg-elevation-2: var(--cg-ring-strong);
324
- --cg-elevation-3: var(--cg-ring-strong), var(--cogenta-shadow-md);
372
+ --ca-image-brightness: 0.9;
373
+ --ca-mark-invert: 1;
374
+ --ca-mark-blend: screen;
325
375
  }
326
376
  }
327
377
 
328
378
  :where(:root[data-theme="dark"]) {
329
- --cg-elevation-1: var(--cg-ring);
330
- --cg-elevation-2: var(--cg-ring-strong);
331
- --cg-elevation-3: var(--cg-ring-strong), var(--cogenta-shadow-md);
379
+ --ca-image-brightness: 0.9;
380
+ --ca-mark-invert: 1;
381
+ --ca-mark-blend: screen;
332
382
  }