@humanforest/tokens 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +67 -0
- package/dataviz/dataviz.css +149 -0
- package/dataviz/tokens.json +1591 -0
- package/dataviz/unovis.css +151 -0
- package/deck/deck.css +515 -0
- package/deck/deck.json +358 -0
- package/geo/london-boroughs.json +1 -0
- package/geo/london-dots-coarse.json +1 -0
- package/geo/london-dots-fine.json +1 -0
- package/geo/london-dots-medium.json +1 -0
- package/geo/london-dots-ultra.json +1 -0
- package/geo/london-wards.json +1 -0
- package/glyphs/glyphs.json +1 -0
- package/logos/f-rot.svg +4 -0
- package/logos/f.svg +4 -0
- package/logos/favicon-c2w.svg +9 -0
- package/logos/favicon-console.svg +9 -0
- package/logos/favicon-ds.svg +9 -0
- package/logos/favicon-fleet.svg +9 -0
- package/logos/favicon-flex.svg +9 -0
- package/logos/favicon-plus.svg +9 -0
- package/logos/favicon-radar.svg +9 -0
- package/logos/favicon-tower.svg +9 -0
- package/logos/lockup-horizontal.svg +17 -0
- package/logos/lockup-vertical.svg +17 -0
- package/logos/mark-mono.svg +4 -0
- package/logos/mark.svg +7 -0
- package/logos/wordmark.svg +9 -0
- package/motion/motion.css +104 -0
- package/motion/motion.json +85 -0
- package/motion/motion.theme.css +16 -0
- package/package.json +50 -0
- package/scales/ramps.css +182 -0
- package/scales/ramps.json +605 -0
- package/scales/theme.css +256 -0
- package/src/colourEngine.ts +604 -0
- package/src/glyphs.ts +127 -0
- package/src/logo.ts +50 -0
- package/src/subbrands.ts +44 -0
- package/src/sublogo.ts +80 -0
- package/src/sublogoSvg.ts +134 -0
- package/type/type.css +232 -0
- package/type/type.deck.css +74 -0
- package/type/type.json +548 -0
- package/type/type.theme.css +31 -0
package/deck/deck.css
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
/* Forest deck surface — generated by scripts/deck.ts. Do not edit.
|
|
2
|
+
|
|
3
|
+
The presentation context's token layer: colour, space and shape for a 1920x1080 slide canvas. The
|
|
4
|
+
deck TYPE ramp is a separate artefact (type.deck.css, from scripts/type.ts) and the motion ladder is
|
|
5
|
+
shared with every other surface (motion.css).
|
|
6
|
+
|
|
7
|
+
A deck is a real Forest surface — the bold voice at projector scale — but NOT a UTheme context:
|
|
8
|
+
Nuxt UI components do not render on a slide, so the context tag/manifest/register machinery has
|
|
9
|
+
nothing to govern there. These roles are how the voice is actually delivered.
|
|
10
|
+
|
|
11
|
+
★ FRAMEWORK-AGNOSTIC. Not one Tailwind at-rule. Slidev compiles through UnoCSS, which has no parser
|
|
12
|
+
for @theme / @utility / @custom-variant and passes them through silently — one at-rule here would
|
|
13
|
+
orphan the file with no warning. Plain custom properties only.
|
|
14
|
+
|
|
15
|
+
Consumers reference --deck-* and never a raw ramp step, so a slide cannot express an off-brand
|
|
16
|
+
colour, an off-ladder corner or a hand-picked px. */
|
|
17
|
+
:root {
|
|
18
|
+
/* ── Spacing ─────────────────────────────────────────────────────────────────────────────
|
|
19
|
+
--deck-grid is the layout unit (margins, gutters, the safe area). The numbered steps are the
|
|
20
|
+
CONTENT rhythm, every one a multiple of 4px like the web scale. */
|
|
21
|
+
--deck-grid: 24px;
|
|
22
|
+
--deck-space-1: calc(var(--deck-grid) / 3); /* 8px */
|
|
23
|
+
--deck-space-2: calc(var(--deck-grid) * 2 / 3); /* 16px */
|
|
24
|
+
--deck-space-3: var(--deck-grid); /* 24px */
|
|
25
|
+
--deck-space-4: calc(var(--deck-grid) * 4 / 3); /* 32px */
|
|
26
|
+
--deck-space-5: calc(var(--deck-grid) * 5 / 3); /* 40px */
|
|
27
|
+
--deck-space-6: calc(var(--deck-grid) * 2.5); /* 60px */
|
|
28
|
+
--deck-space-7: calc(var(--deck-grid) * 10 / 3); /* 80px */
|
|
29
|
+
|
|
30
|
+
/* ── Insets — text for its MEASURE, media for its FRAME, and two more ────────────────────
|
|
31
|
+
Text needs a line length and a margin; a photograph has a hard edge and reads as inset too
|
|
32
|
+
far at the same value a paragraph reads correctly at. Chrome (the running mark, page number,
|
|
33
|
+
section pill) is a third, uniform value — furniture, not content. Display is a fourth: the
|
|
34
|
+
beat layouts set one line at 96–128px, and a margin is read relative to the type it frames.
|
|
35
|
+
Full reasoning above INSET.
|
|
36
|
+
chrome/media SHARE a value (one grid unit) but mean different things: chrome is a margin from
|
|
37
|
+
every edge, media is a margin from the left/right edges only.
|
|
38
|
+
★ MEDIA'S VERTICAL BOUND, and why it is not one number. A figure's top and bottom follow the
|
|
39
|
+
NOTCH, together: a notched figure rises to --deck-inset-media on both, because the cut is what
|
|
40
|
+
keeps the running mark clear and the mark's own corner and the figure's are then the same
|
|
41
|
+
point; an un-notched one (notch: false, chrome: false, or a media:none second content column)
|
|
42
|
+
takes --deck-inset-text on both, which is the pre-notch geometry the escape hatch is
|
|
43
|
+
documented to restore. What it is NOT is 36 on three sides and 90 on the fourth — that was the
|
|
44
|
+
shipped state on all 86 media figures, and 54px of unexplained bottom-heaviness is not a rule,
|
|
45
|
+
it is a rule applied to half a box. See split.vue's .split-figure. */
|
|
46
|
+
--deck-inset-chrome: calc(var(--deck-grid) * 1.5); /* 36px · corner furniture (mark, page number, section pill) — all four edges */
|
|
47
|
+
--deck-inset-media: calc(var(--deck-grid) * 1.5); /* 36px · figures and illustrations — HORIZONTAL edges only; vertical bound is --deck-inset-media on a notched figure, --deck-inset-text otherwise */
|
|
48
|
+
--deck-inset-text: calc(var(--deck-grid) * 4); /* 96px · text content — all four edges */
|
|
49
|
+
--deck-inset-display: calc(var(--deck-grid) * 5); /* 120px · the beat layouts (cover/quote/statement/divider/end) — HORIZONTAL edges only, sized against 96–128px display type */
|
|
50
|
+
|
|
51
|
+
/* ── Layout anchors and extras — points and gaps, not edge margins ───────────────────────
|
|
52
|
+
task-14b-brief.md. Two things split.vue needs beyond the three insets above:
|
|
53
|
+
anchor-third the text column's fixed vertical START, "so the headings dont jump between
|
|
54
|
+
slides" (Jose). A FRACTION of the canvas, not a hard-coded 360px, so it stays
|
|
55
|
+
correct if the canvas itself ever changes — see split.vue's own comment on
|
|
56
|
+
.split-grid for the one place its 100% basis is actually the full 1080px
|
|
57
|
+
canvas rather than some padded descendant of it.
|
|
58
|
+
heading-top-space extra air above a NON-split heading, so it starts clear of the top edge
|
|
59
|
+
rather than flush against it. One full grid unit — see default.vue.
|
|
60
|
+
heading-bottom-space the gap under a slide's h1, before its first block — base.css. Paired
|
|
61
|
+
with the one above so the air on both sides of a title is retuned in one
|
|
62
|
+
place, and so a deck that budgets from where content starts (apps/deck
|
|
63
|
+
does) reads the number instead of restating it. h2 keeps its own tighter gap:
|
|
64
|
+
it sits INSIDE the content rather than starting it. */
|
|
65
|
+
--deck-anchor-third: 360px; /* 360px · split.vue's text column start — one third of the canvas down */
|
|
66
|
+
--deck-heading-top-space: var(--deck-space-5); /* 40px · extra air above a non-split heading — see default.vue */
|
|
67
|
+
--deck-heading-bottom-space: var(--deck-space-4); /* 32px · the gap under a slide's h1, before its first block — see base.css */
|
|
68
|
+
--deck-split-gutter-same: var(--deck-inset-text); /* 96px · split.vue, same-kind columns only (text|text, media|media) — mixed splits use 0 and pad the content column instead */
|
|
69
|
+
|
|
70
|
+
/* ── The running mark, and the notch it leaves in a panel ────────────────────────────────
|
|
71
|
+
task-15-brief.md. The cut-out is DERIVED from its occupant and never sized beside it: the
|
|
72
|
+
occupant's own box is the input, the notch is that box plus one gap, and changing the mark
|
|
73
|
+
moves both with no second edit. Two readers agree on these because they are tokens rather than
|
|
74
|
+
a number inside one component — slide-top.vue draws the mark, split.vue cuts room for it.
|
|
75
|
+
|
|
76
|
+
The ring is the CHROME INSET again, not a new number: the mark already keeps 36px of clear
|
|
77
|
+
space on the two sides facing the slide's edge, so the same value on the two sides facing into
|
|
78
|
+
the panel gives it a uniform ring and makes it read as seated rather than parked. The occupant
|
|
79
|
+
sits FLUSH in the panel's outer corner (chrome and media share an inset, so the two corners
|
|
80
|
+
coincide), which is why the cut is occupant + ONE gap.
|
|
81
|
+
|
|
82
|
+
--deck-notch-occupant-w/-h are NOT declared here on purpose. Consumers read them as
|
|
83
|
+
var(--deck-notch-occupant-w, var(--deck-chrome-mark)) so the default lives in the fallback: a
|
|
84
|
+
custom property declared at :root resolves ONCE, there, and a slide overriding the occupant
|
|
85
|
+
further down would inherit the stale :root value of anything derived from it. Left undeclared,
|
|
86
|
+
an override on the slide root reaches every reader — which is what lets one mark and two marks
|
|
87
|
+
produce correctly-shaped notches with no code change. */
|
|
88
|
+
--deck-chrome-mark: 72px; /* 72px · the running chrome's Forest mark — and the notch's default occupant */
|
|
89
|
+
--deck-chrome-band: calc(var(--deck-inset-chrome) + var(--deck-chrome-mark)); /* 108px · how deep the running chrome reaches from the canvas edge — inset + mark */
|
|
90
|
+
--deck-chrome-pair-gap: var(--deck-space-2); /* 16px · between the Forest mark and a partner's, in a co-branded lockup (`partner:`) */
|
|
91
|
+
--deck-notch-gap: calc(var(--deck-grid) * 1); /* 24px · the breathing ring cut between occupant and panel — tighter than the slide margin, see scripts/deck.ts */
|
|
92
|
+
--deck-mark-radius: 15.75px; /* 15.75px · the mark's own corner, read from logo.ts's square path — what a co-brand partner is clipped to */
|
|
93
|
+
--deck-mark-ring-width: 3px; /* 3px · matched against the artwork's own ring at 72 */
|
|
94
|
+
--deck-notch-radius: 39.75px; /* 39.75px · concentric with the mark: its 15.75px corner + the 24px ring; split.vue clamps it to half the notch */
|
|
95
|
+
|
|
96
|
+
/* ── Radius contract — one lever, everything derives ─────────────────────────────────────
|
|
97
|
+
Same model and same lever value as the web's --ui-radius. The card step is *6 rather than the
|
|
98
|
+
web's xl/*3 on purpose: a deck is a BOLD surface, and on a 1920px canvas a 24px corner reads as
|
|
99
|
+
a hairline at presenting size. */
|
|
100
|
+
--deck-radius: 0.5rem;
|
|
101
|
+
--deck-radius-item: calc(var(--deck-radius) * 1); /* 8px · code chips, tags, swatches */
|
|
102
|
+
--deck-radius-control: calc(var(--deck-radius) * 1.5); /* 12px · buttons, pills */
|
|
103
|
+
--deck-radius-card: calc(var(--deck-radius) * 6); /* 48px · the slide card */
|
|
104
|
+
|
|
105
|
+
/* Concentric corners: a nested surface = parent radius − parent padding, floored at 8px, so the
|
|
106
|
+
inner curve stays parallel to the outer one. Two steps (48 → 16 → 8), like .forest-card. */
|
|
107
|
+
--deck-card-pad: var(--deck-space-4); /* 32px */
|
|
108
|
+
--deck-radius-nested: max(calc(var(--deck-radius-card) - var(--deck-card-pad)), 0.5rem);
|
|
109
|
+
--deck-radius-nested-2: max(calc(var(--deck-radius-card) - 2 * var(--deck-card-pad)), 0.5rem);
|
|
110
|
+
|
|
111
|
+
/* Fully rounded — the pill/circle end of the ladder, NOT a step on it. Deliberately a large
|
|
112
|
+
constant rather than a multiple of the lever: a pill's corner is "half my own height, whatever
|
|
113
|
+
that turns out to be", which no fixed multiplier expresses. Moving the lever must not turn a
|
|
114
|
+
pill back into a rounded rectangle. Used by the running chrome's page marker and by the small
|
|
115
|
+
chips, both of which read as markers rather than as surfaces. */
|
|
116
|
+
--deck-radius-full: 9999px;
|
|
117
|
+
|
|
118
|
+
/* ── Colour roles — light, and light IS the deck ─────────────────────────────────────────
|
|
119
|
+
Ice Cream (--warm-50) is a named brand pin, not a tint: warm paper, near-black ink, the accent
|
|
120
|
+
doing all of the shouting. Boldness comes from the display tier, the full-bleed accent sections
|
|
121
|
+
and the scale of the type — not from inverting the deck. */
|
|
122
|
+
--deck-bg: var(--warm-50);
|
|
123
|
+
--deck-fg: var(--neutral-900); /* neutral, not forest-950 — text is one ramp, so dimming is lightness and never a hue shift */
|
|
124
|
+
--deck-fg-muted: var(--neutral-600); /* 600, not 500 — the web contrast floor for muted text on light */
|
|
125
|
+
--deck-fg-subtle: var(--neutral-500);
|
|
126
|
+
--deck-accent: var(--forest-700);
|
|
127
|
+
--deck-accent-strong: var(--forest-800);
|
|
128
|
+
--deck-on-accent: #ffffff;
|
|
129
|
+
|
|
130
|
+
/* Named backgrounds and their ink, FOLLOWING the register — what anything that is PART OF the
|
|
131
|
+
deck reads: a panel, a band, a card ground. See PANEL for why the names are relative ('warm',
|
|
132
|
+
not 'bark'). The pinned halves are emitted once, below. */
|
|
133
|
+
--deck-bg-warm: var(--warm-200);
|
|
134
|
+
--deck-on-bg-warm: var(--warm-950);
|
|
135
|
+
--deck-bg-accent: var(--forest-100);
|
|
136
|
+
--deck-on-bg-accent: var(--forest-950);
|
|
137
|
+
--deck-bg-vivid: var(--forest-300);
|
|
138
|
+
--deck-on-bg-vivid: var(--forest-950);
|
|
139
|
+
--deck-bg-neutral: var(--neutral-100);
|
|
140
|
+
--deck-on-bg-neutral: var(--neutral-900);
|
|
141
|
+
|
|
142
|
+
/* The same four names as INK on the page, for anything that draws the tone as a stroke or a label
|
|
143
|
+
rather than as a ground: an outline badge, a rule, a keyline. See PANEL's ★ note on why this is
|
|
144
|
+
the OPPOSITE half from the one directly above. */
|
|
145
|
+
--deck-ink-warm: var(--warm-700);
|
|
146
|
+
--deck-ink-accent: var(--forest-950);
|
|
147
|
+
--deck-ink-vivid: var(--forest-700);
|
|
148
|
+
--deck-ink-neutral: var(--neutral-800);
|
|
149
|
+
|
|
150
|
+
/* ── the MARK a background carries ──────────────────────────────────────────────────────────
|
|
151
|
+
★★ A SMALL SHAPE DRAWN ON THE BACKGROUND, IN THAT BACKGROUND'S OWN FAMILY — a list bullet
|
|
152
|
+
today, and anything else of that size later. Not the ink pair above, which is the OPPOSITE half
|
|
153
|
+
and exists for drawing this name on the PAGE; not on-bg, which is the body ink and reads as
|
|
154
|
+
text rather than as a mark. This is the liveliest step of the same family that still clears the
|
|
155
|
+
3:1 a graphical object is held to against the fill it lands on.
|
|
156
|
+
|
|
157
|
+
Chosen by measuring the whole ramp against each fill rather than by picking a rung. Warm wanted
|
|
158
|
+
an orange rather than the bark: on peach nothing lighter than 600 clears the floor (500 is
|
|
159
|
+
2.66) so 600 it is, and on bark the orange 300 clears at 3.84. The green fields wanted the
|
|
160
|
+
vivid green: on the quiet accent field forest-700 gives 5.45, and on the night step forest-300
|
|
161
|
+
gives 8.51. Vivid itself cannot take a mint on its light half — every light green is invisible
|
|
162
|
+
on forest-300, and 200 measures 1.28 — so it takes 800 there and the mint 200 on its dark half,
|
|
163
|
+
4.53.
|
|
164
|
+
|
|
165
|
+
MEASURED, mark against its own fill: warm 3.83 light / 3.84 dark, accent 5.45 / 8.51, vivid
|
|
166
|
+
4.78 / 4.53, neutral 4.18 / 5.74.
|
|
167
|
+
|
|
168
|
+
Named bg-NAME-mark rather than mark-NAME: --deck-mark-radius is the LOGO mark's corner and
|
|
169
|
+
--deck-status-STATE-mark is a semantic state's fill, so the prefix is already spoken for. This
|
|
170
|
+
one belongs to the background, and is named where it lives. */
|
|
171
|
+
--deck-bg-warm-mark: var(--warm-600);
|
|
172
|
+
--deck-bg-accent-mark: var(--forest-700);
|
|
173
|
+
--deck-bg-vivid-mark: var(--forest-800);
|
|
174
|
+
--deck-bg-neutral-mark: var(--neutral-500);
|
|
175
|
+
|
|
176
|
+
/* Chart series alias the published categorical palette in the product's ORDER, so a deck chart and
|
|
177
|
+
a product chart of the same data are the same chart. */
|
|
178
|
+
--deck-series-1: var(--dataviz-categorical-vivid-green);
|
|
179
|
+
--deck-series-2: var(--dataviz-categorical-vivid-amber);
|
|
180
|
+
--deck-series-3: var(--dataviz-categorical-vivid-sky);
|
|
181
|
+
--deck-series-4: var(--dataviz-categorical-vivid-indigo);
|
|
182
|
+
--deck-series-5: var(--dataviz-categorical-vivid-pink);
|
|
183
|
+
--deck-series-6: var(--dataviz-categorical-vivid-red);
|
|
184
|
+
|
|
185
|
+
/* The sequential ramp — one hue, five steps, for a quantity rather than a category. Light register
|
|
186
|
+
runs pale to deep, so more ink means more of whatever is being mapped. */
|
|
187
|
+
--deck-shade-1: var(--dataviz-sequential-forest-2);
|
|
188
|
+
--deck-shade-2: var(--dataviz-sequential-forest-3);
|
|
189
|
+
--deck-shade-3: var(--dataviz-sequential-forest-4);
|
|
190
|
+
--deck-shade-4: var(--dataviz-sequential-forest-6);
|
|
191
|
+
--deck-shade-5: var(--dataviz-sequential-forest-8);
|
|
192
|
+
|
|
193
|
+
/* The Thames takes the palette's own river pair rather than a grey — it is the one feature that
|
|
194
|
+
tells an audience which city they are looking at, a data colour doing a wayfinding job. */
|
|
195
|
+
--deck-dot-river: var(--dataviz-categorical-pairs-river-soft);
|
|
196
|
+
|
|
197
|
+
/* ── The pinned halves — PAIRED with their ink, never emitted alone ──────────────────────
|
|
198
|
+
The same four backgrounds, each half nailed to one register and never re-pointed. This is what
|
|
199
|
+
an OBJECT sitting on the deck reads — a badge, an icon tile, a running pill — where the names
|
|
200
|
+
above are what a SURFACE of the deck reads. A component picks "<name>-<half>" and never
|
|
201
|
+
assembles a fill and an ink from two different rows.
|
|
202
|
+
|
|
203
|
+
★ THE INK IS "on-bg-<name>", NOT "on-<name>", and the bg- is load-bearing. This file already
|
|
204
|
+
has a --deck-accent role (the brand green for claims and chrome) whose ink is --deck-on-accent,
|
|
205
|
+
so a shortened on-accent here silently redefined it — measured, the role's forest-700 fill
|
|
206
|
+
ended up paired with forest-950 ink. The on- prefix wraps the FULL name of the fill it belongs
|
|
207
|
+
to, which is what on-status-danger and the old on-panel-accent already did.
|
|
208
|
+
|
|
209
|
+
★★ ONE TABLE, WHICH IS THE POINT. This was CHIP, holding the same literals PANEL held, and the
|
|
210
|
+
two drifted the first time one moved: deep was accent's dark half until that half went to the
|
|
211
|
+
night step, and nothing said so. A name is a background plus a half now, so a value cannot go
|
|
212
|
+
stale in one copy.
|
|
213
|
+
|
|
214
|
+
⚠ PINNED IS NOT THE SAME AS FOLLOWING, and the caller owns the difference. "accent-dark" on a
|
|
215
|
+
dark slide IS that slide's own ground and disappears — measured 1.00:1. That is not a fault in
|
|
216
|
+
the token; it is what a fixed dark object on a dark page means. The follow tokens above exist
|
|
217
|
+
so a surface never has to make that choice. */
|
|
218
|
+
--deck-bg-warm-light: var(--warm-200);
|
|
219
|
+
--deck-on-bg-warm-light: var(--warm-950);
|
|
220
|
+
--deck-bg-warm-dark: var(--warm-700);
|
|
221
|
+
--deck-on-bg-warm-dark: var(--neutral-0);
|
|
222
|
+
--deck-bg-accent-light: var(--forest-100);
|
|
223
|
+
--deck-on-bg-accent-light: var(--forest-950);
|
|
224
|
+
--deck-bg-accent-dark: var(--forest-950);
|
|
225
|
+
--deck-on-bg-accent-dark: var(--neutral-0);
|
|
226
|
+
--deck-bg-vivid-light: var(--forest-300);
|
|
227
|
+
--deck-on-bg-vivid-light: var(--forest-950);
|
|
228
|
+
--deck-bg-vivid-dark: var(--forest-700);
|
|
229
|
+
--deck-on-bg-vivid-dark: var(--neutral-0);
|
|
230
|
+
--deck-bg-neutral-light: var(--neutral-100);
|
|
231
|
+
--deck-on-bg-neutral-light: var(--neutral-900);
|
|
232
|
+
--deck-bg-neutral-dark: var(--neutral-800);
|
|
233
|
+
--deck-on-bg-neutral-dark: var(--neutral-0);
|
|
234
|
+
|
|
235
|
+
/* Status roles, a SET per state — see the STATUS table. The subtle four are alpha over the
|
|
236
|
+
semantic role, which is stock's own construction; the dark block restates them off the 400
|
|
237
|
+
because a var() inside a custom property is substituted where that property is DECLARED. */
|
|
238
|
+
--deck-status-info-fill: color-mix(in oklab, var(--river-500) 10%, transparent);
|
|
239
|
+
--deck-status-info-ink: var(--river-600);
|
|
240
|
+
--deck-status-info-icon: var(--river-500);
|
|
241
|
+
--deck-status-info-edge: color-mix(in oklab, var(--river-500) 25%, transparent);
|
|
242
|
+
--deck-status-info-solid: var(--river-500);
|
|
243
|
+
--deck-status-info-mark: var(--river-500);
|
|
244
|
+
--deck-on-status-info: #ffffff;
|
|
245
|
+
--deck-status-success-fill: color-mix(in oklab, var(--forest-500) 10%, transparent);
|
|
246
|
+
--deck-status-success-ink: var(--forest-600);
|
|
247
|
+
--deck-status-success-icon: var(--forest-500);
|
|
248
|
+
--deck-status-success-edge: color-mix(in oklab, var(--forest-500) 25%, transparent);
|
|
249
|
+
--deck-status-success-solid: var(--forest-500);
|
|
250
|
+
--deck-status-success-mark: var(--forest-500);
|
|
251
|
+
--deck-on-status-success: #ffffff;
|
|
252
|
+
--deck-status-warning-fill: color-mix(in oklab, var(--amber-500) 10%, transparent);
|
|
253
|
+
--deck-status-warning-ink: var(--amber-600);
|
|
254
|
+
--deck-status-warning-icon: var(--amber-500);
|
|
255
|
+
--deck-status-warning-edge: color-mix(in oklab, var(--amber-500) 25%, transparent);
|
|
256
|
+
--deck-status-warning-solid: var(--amber-500);
|
|
257
|
+
--deck-status-warning-mark: var(--amber-500);
|
|
258
|
+
--deck-on-status-warning: #ffffff;
|
|
259
|
+
--deck-status-danger-fill: color-mix(in oklab, var(--maple-500) 10%, transparent);
|
|
260
|
+
--deck-status-danger-ink: var(--maple-600);
|
|
261
|
+
--deck-status-danger-icon: var(--maple-500);
|
|
262
|
+
--deck-status-danger-edge: color-mix(in oklab, var(--maple-500) 25%, transparent);
|
|
263
|
+
--deck-status-danger-solid: var(--maple-500);
|
|
264
|
+
--deck-status-danger-mark: var(--maple-500);
|
|
265
|
+
--deck-on-status-danger: #ffffff;
|
|
266
|
+
--deck-status-neutral-fill: color-mix(in oklab, var(--neutral-500) 10%, transparent);
|
|
267
|
+
--deck-status-neutral-ink: var(--neutral-600);
|
|
268
|
+
--deck-status-neutral-icon: var(--neutral-500);
|
|
269
|
+
--deck-status-neutral-edge: color-mix(in oklab, var(--neutral-500) 25%, transparent);
|
|
270
|
+
--deck-status-neutral-solid: var(--neutral-500);
|
|
271
|
+
--deck-status-neutral-mark: var(--neutral-500);
|
|
272
|
+
--deck-on-status-neutral: #ffffff;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* ── Dark — punctuation, not the ground ───────────────────────────────────────────────────────
|
|
276
|
+
The deck runs LIGHT. Dark is a per-slide instrument: a hard cut marking a pivot, landing a
|
|
277
|
+
statement, or letting a chart sit on a black ground.
|
|
278
|
+
|
|
279
|
+
Bound to TWO selectors: `.dark` is the whole-deck toggle (Slidev stamps it on <html>), and
|
|
280
|
+
`.deck-dark` is a single slide opting in from frontmatter. */
|
|
281
|
+
.dark,
|
|
282
|
+
.deck-dark {
|
|
283
|
+
--deck-bg: var(--forest-950);
|
|
284
|
+
--deck-fg: var(--neutral-0);
|
|
285
|
+
--deck-fg-muted: var(--neutral-400);
|
|
286
|
+
--deck-fg-subtle: var(--neutral-500);
|
|
287
|
+
--deck-accent: var(--forest-300);
|
|
288
|
+
--deck-accent-strong: var(--forest-200);
|
|
289
|
+
--deck-on-accent: var(--forest-950);
|
|
290
|
+
|
|
291
|
+
/* The same panel grounds, on the other side of the register — the half that did not exist. */
|
|
292
|
+
--deck-bg-warm: var(--warm-700);
|
|
293
|
+
--deck-on-bg-warm: var(--neutral-0);
|
|
294
|
+
--deck-bg-accent: var(--forest-950);
|
|
295
|
+
--deck-on-bg-accent: var(--neutral-0);
|
|
296
|
+
--deck-bg-vivid: var(--forest-700);
|
|
297
|
+
--deck-on-bg-vivid: var(--neutral-0);
|
|
298
|
+
--deck-bg-neutral: var(--neutral-800);
|
|
299
|
+
--deck-on-bg-neutral: var(--neutral-0);
|
|
300
|
+
--deck-ink-warm: var(--warm-200);
|
|
301
|
+
--deck-ink-accent: var(--forest-100);
|
|
302
|
+
--deck-ink-vivid: var(--forest-300);
|
|
303
|
+
--deck-ink-neutral: var(--neutral-100);
|
|
304
|
+
--deck-bg-warm-mark: var(--warm-300);
|
|
305
|
+
--deck-bg-accent-mark: var(--forest-300);
|
|
306
|
+
--deck-bg-vivid-mark: var(--forest-200);
|
|
307
|
+
--deck-bg-neutral-mark: var(--neutral-400);
|
|
308
|
+
--deck-dot-river: var(--dataviz-categorical-pairs-river-deep);
|
|
309
|
+
|
|
310
|
+
/* ★ THE RAMP REVERSES ON A DARK GROUND, because "more" is a bigger distance FROM the page and the
|
|
311
|
+
page moved. Deep forest on near-black is the step that disappears, exactly as pale forest is the
|
|
312
|
+
one that disappears on paper — so the same five steps run the other way and the reading ("more
|
|
313
|
+
ink means more") survives the register change. */
|
|
314
|
+
--deck-shade-1: var(--dataviz-sequential-forest-8);
|
|
315
|
+
--deck-shade-2: var(--dataviz-sequential-forest-6);
|
|
316
|
+
--deck-shade-3: var(--dataviz-sequential-forest-4);
|
|
317
|
+
--deck-shade-4: var(--dataviz-sequential-forest-3);
|
|
318
|
+
--deck-shade-5: var(--dataviz-sequential-forest-2);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/* ── The design system's own dual-mode tokens, answered in the DECK's register ────────────────
|
|
322
|
+
★★ WITHOUT THIS BLOCK A CHART ON A DARK SLIDE PAINTS THE LIGHT PALETTE, and nothing anywhere
|
|
323
|
+
says so. The series and the Thames alias published dataviz tokens rather than restating them —
|
|
324
|
+
which is the point, so a deck chart and a product chart of the same data are the same chart. But
|
|
325
|
+
those tokens flip on .dark, and a dark SLIDE is .deck-dark: Slidev stamps .dark on <html>
|
|
326
|
+
only when the whole deck is dark. Measured on the built deck — html.dark false, no .dark
|
|
327
|
+
ancestor anywhere in the document — so on a .deck-dark slide the alias resolved to the LIGHT
|
|
328
|
+
value and the dark half of a dual-mode palette was unreachable.
|
|
329
|
+
|
|
330
|
+
It is the same shape as the shiki defect this theme already carries a note about: html.dark and
|
|
331
|
+
.deck-dark are different things, and code that assumes one covers the other is wrong quietly.
|
|
332
|
+
|
|
333
|
+
What it cost, measured against the deck's dark ground (forest-950):
|
|
334
|
+
|
|
335
|
+
series light (what was drawn) dark (what should be)
|
|
336
|
+
green 4.72 8.70
|
|
337
|
+
indigo 2.39 ← under 3:1 5.00
|
|
338
|
+
amber 4.84 9.04
|
|
339
|
+
pink 3.34 5.60
|
|
340
|
+
sky 3.78 7.02
|
|
341
|
+
|
|
342
|
+
Indigo sat below the 3:1 floor a graphical object is held to, and no gate could see it: the
|
|
343
|
+
audit's contrast pass measures TEXT, and a chart fill is not text.
|
|
344
|
+
|
|
345
|
+
★★ THE FIX IS BOTH HALVES, AND THE SECOND ONE IS NOT OPTIONAL. Re-pointing the source token
|
|
346
|
+
alone looks sufficient and is not: a var() inside a custom property is substituted where that
|
|
347
|
+
property is DECLARED, and --deck-series-N is declared on :root, so its alias resolves against
|
|
348
|
+
:root's value no matter what this block says. Measured on the built deck after the source
|
|
349
|
+
re-point alone — --deck-series-4 (indigo) still read #4f39f6, the LIGHT indigo, on a .deck-dark slide.
|
|
350
|
+
The ROLE has to be re-declared here too, which is what re-resolves its alias in this register.
|
|
351
|
+
(--deck-dot-river needed nothing: it is already declared in the dark role block above, on the
|
|
352
|
+
same element, so its alias re-resolved on its own. That asymmetry is the whole rule — a role
|
|
353
|
+
declared only on :root is frozen there; one declared here is not.)
|
|
354
|
+
|
|
355
|
+
Re-pointing the token as well is still worth doing: it keeps the re-declared role pointing at
|
|
356
|
+
the PUBLISHED token rather than at a hex, so the palette stays the single source, and anything
|
|
357
|
+
reading a dataviz token directly in this register gets the right value.
|
|
358
|
+
|
|
359
|
+
Values come from colourEngine's own tables, the same source scripts/dataviz.ts generates from, so
|
|
360
|
+
there is no second copy of the palette to drift. packages/slidev-theme/test/deckRegister.static.test.ts
|
|
361
|
+
asserts this block covers every dual-mode dataviz token deck.css references.
|
|
362
|
+
|
|
363
|
+
.dark needs none of this: dataviz.css already answers it there. */
|
|
364
|
+
.deck-dark {
|
|
365
|
+
--dataviz-categorical-vivid-green: #05df72;
|
|
366
|
+
--dataviz-categorical-vivid-amber: #fabc00;
|
|
367
|
+
--dataviz-categorical-vivid-sky: #00bbfd;
|
|
368
|
+
--dataviz-categorical-vivid-indigo: #7d87ff;
|
|
369
|
+
--dataviz-categorical-vivid-pink: #fb64b6;
|
|
370
|
+
--dataviz-categorical-vivid-red: #ff6568;
|
|
371
|
+
--dataviz-categorical-pairs-forest-deep: #0abb7f;
|
|
372
|
+
--dataviz-categorical-pairs-forest-soft: #99e9bc;
|
|
373
|
+
--dataviz-categorical-pairs-warm-deep: #f48519;
|
|
374
|
+
--dataviz-categorical-pairs-warm-soft: #ffd6a6;
|
|
375
|
+
--dataviz-categorical-pairs-river-deep: #43a2ff;
|
|
376
|
+
--dataviz-categorical-pairs-river-soft: #b2d9ff;
|
|
377
|
+
|
|
378
|
+
/* The semantic mark, one rung lighter — see STATUS_MARK_DARK for the measurement. */
|
|
379
|
+
--deck-status-info-mark: var(--river-400);
|
|
380
|
+
--deck-status-success-mark: var(--forest-400);
|
|
381
|
+
--deck-status-warning-mark: var(--amber-400);
|
|
382
|
+
--deck-status-danger-mark: var(--maple-400);
|
|
383
|
+
--deck-status-neutral-mark: var(--neutral-400);
|
|
384
|
+
|
|
385
|
+
/* ★★ AND THE SUBTLE FOUR WITH IT, restated rather than inherited. They are color-mix results
|
|
386
|
+
built off the mark, and a custom property computes where it is DECLARED — re-pointing the mark
|
|
387
|
+
above would leave a fill declared at :root holding the 500 it was substituted with there. Same
|
|
388
|
+
trap the derived surfaces and the series roles record. This is the whole of what stock gets for
|
|
389
|
+
free from a dark: class never appearing in its theme: the token moves, so the variant moves. */
|
|
390
|
+
--deck-status-info-fill: color-mix(in oklab, var(--river-400) 10%, transparent);
|
|
391
|
+
--deck-status-info-ink: var(--river-400);
|
|
392
|
+
--deck-status-info-icon: var(--river-400);
|
|
393
|
+
--deck-status-info-edge: color-mix(in oklab, var(--river-400) 25%, transparent);
|
|
394
|
+
--deck-status-success-fill: color-mix(in oklab, var(--forest-400) 10%, transparent);
|
|
395
|
+
--deck-status-success-ink: var(--forest-400);
|
|
396
|
+
--deck-status-success-icon: var(--forest-400);
|
|
397
|
+
--deck-status-success-edge: color-mix(in oklab, var(--forest-400) 25%, transparent);
|
|
398
|
+
--deck-status-warning-fill: color-mix(in oklab, var(--amber-400) 10%, transparent);
|
|
399
|
+
--deck-status-warning-ink: var(--amber-400);
|
|
400
|
+
--deck-status-warning-icon: var(--amber-400);
|
|
401
|
+
--deck-status-warning-edge: color-mix(in oklab, var(--amber-400) 25%, transparent);
|
|
402
|
+
--deck-status-danger-fill: color-mix(in oklab, var(--maple-400) 10%, transparent);
|
|
403
|
+
--deck-status-danger-ink: var(--maple-400);
|
|
404
|
+
--deck-status-danger-icon: var(--maple-400);
|
|
405
|
+
--deck-status-danger-edge: color-mix(in oklab, var(--maple-400) 25%, transparent);
|
|
406
|
+
--deck-status-neutral-fill: color-mix(in oklab, var(--neutral-400) 10%, transparent);
|
|
407
|
+
--deck-status-neutral-ink: var(--neutral-400);
|
|
408
|
+
--deck-status-neutral-icon: var(--neutral-400);
|
|
409
|
+
--deck-status-neutral-edge: color-mix(in oklab, var(--neutral-400) 25%, transparent);
|
|
410
|
+
|
|
411
|
+
/* The solid panel and its ink, as ONE PAIR — see STATUS_SOLID_DARK. The fill lifts so the block
|
|
412
|
+
separates from a near-black slide; the ink turns over because white cannot survive the lighter
|
|
413
|
+
fill it just moved to. */
|
|
414
|
+
--deck-status-info-solid: var(--river-400);
|
|
415
|
+
--deck-on-status-info: var(--river-950);
|
|
416
|
+
--deck-status-success-solid: var(--forest-400);
|
|
417
|
+
--deck-on-status-success: var(--forest-950);
|
|
418
|
+
--deck-status-warning-solid: var(--amber-400);
|
|
419
|
+
--deck-on-status-warning: var(--amber-950);
|
|
420
|
+
--deck-status-danger-solid: var(--maple-400);
|
|
421
|
+
--deck-on-status-danger: var(--maple-950);
|
|
422
|
+
--deck-status-neutral-solid: var(--neutral-400);
|
|
423
|
+
--deck-on-status-neutral: var(--neutral-950);
|
|
424
|
+
|
|
425
|
+
/* ★★ AND THE SERIES ROLES THEMSELVES, not only the token they alias. A var() inside a custom
|
|
426
|
+
property is substituted where that property is DECLARED — --deck-series-N is declared at :root,
|
|
427
|
+
so its alias resolves against :root and re-pointing the source here never reaches it. Measured
|
|
428
|
+
on the built deck after the source re-point alone: --deck-series-4 (indigo) still read #4f39f6, the LIGHT
|
|
429
|
+
indigo, on a .deck-dark slide. Re-declaring the role here is what re-resolves the alias in this
|
|
430
|
+
register. It still points at the published token rather than a hex, so there is no second copy
|
|
431
|
+
of the palette; the token beside it is what makes that reference land on the dark value. */
|
|
432
|
+
--deck-series-1: var(--dataviz-categorical-vivid-green);
|
|
433
|
+
--deck-series-2: var(--dataviz-categorical-vivid-amber);
|
|
434
|
+
--deck-series-3: var(--dataviz-categorical-vivid-sky);
|
|
435
|
+
--deck-series-4: var(--dataviz-categorical-vivid-indigo);
|
|
436
|
+
--deck-series-5: var(--dataviz-categorical-vivid-pink);
|
|
437
|
+
--deck-series-6: var(--dataviz-categorical-vivid-red);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/* ── The brand-pairs opt-in ───────────────────────────────────────────────────────────────────
|
|
441
|
+
A slide-level class, written beside `class: deck-dark` in frontmatter, that re-points the series
|
|
442
|
+
roles to the published BRAND pairs: three brand hues, each contributing a deep and a soft tone.
|
|
443
|
+
Nothing in a chart component knows about it — a declaration on the slide element beats :root's
|
|
444
|
+
inherited value, which is the same cascade rule the dark register already relies on.
|
|
445
|
+
|
|
446
|
+
★ FAMILY ORDER, exactly as the product's own pairsVar() walks it (packages/charts/src/
|
|
447
|
+
useChartPalette.ts), so consecutive slots are the SAME hue. That is the whole semantics: a pair
|
|
448
|
+
says "these two series are two views of one thing". It also means a pairs chart wants an EVEN
|
|
449
|
+
series count — at five, slot 5 is river-deep with its soft tone out of reach, and the last series
|
|
450
|
+
reads as a lone hue rather than half a pair.
|
|
451
|
+
|
|
452
|
+
★★ THE CEILING, WRITTEN DOWN, because it is severe and it is invisible to every gate this repo
|
|
453
|
+
has. On the LIGHT register the pairs do not clear the 3:1 a graphical mark is held to. Measured
|
|
454
|
+
against the deck's own grounds — bare cream / --deck-surface / the since-folded 8% bg-subtle:
|
|
455
|
+
|
|
456
|
+
forest-deep 3.25 / 2.90 / 2.69 forest-soft 1.74 / 1.55 / 1.44
|
|
457
|
+
warm-deep 3.46 / 3.09 / 2.87 warm-soft 1.75 / 1.56 / 1.45
|
|
458
|
+
river-deep 3.50 / 3.12 / 2.90 river-soft 1.84 / 1.64 / 1.53
|
|
459
|
+
|
|
460
|
+
The soft tones are the deck's lowest-contrast marks by a distance — below the 2.39 that got the
|
|
461
|
+
vivid indigo re-pointed one register over. Even the DEEP tones only clear 3:1 on bare cream, and
|
|
462
|
+
Bars draws its track in --deck-surface. So: pairs belong on a `deck-dark` slide, where all six
|
|
463
|
+
measure 4.72-11.37. That is not a workaround; a saturated brand chart on a dark ground is one of
|
|
464
|
+
the three things the dark register exists for.
|
|
465
|
+
|
|
466
|
+
★ The cost on dark is COLOUR-VISION, not contrast, and it is why this is a small instrument
|
|
467
|
+
rather than a replacement for the vivid five. Cross-family the soft tones converge — forest-soft
|
|
468
|
+
against warm-soft is worst-case-CVD dE00 5, where vivid-5 holds 8. Within a pair the separation
|
|
469
|
+
is carried by lightness (a constant +17 L*) and survives every dichromacy at 13-18. Read that as
|
|
470
|
+
the instruction it is: pairs is at its best as TWO series from ONE family, and degrades as it is
|
|
471
|
+
asked to carry more unrelated categories.
|
|
472
|
+
|
|
473
|
+
NOT RE-WINDOWED for the deck. Taking each pair a rung darker clears contrast on cream but costs
|
|
474
|
+
the brand: warm-700 is #8a462e, a brown, and warm-500 is the only warm step that is both above
|
|
475
|
+
3:1 and still Acer orange. The published pairs are brand ramp steps exactly (light 500/300, dark
|
|
476
|
+
400/200); a deck-local re-derivation would be a second palette, which is the thing this file is
|
|
477
|
+
organised to avoid. */
|
|
478
|
+
/* ★★ TWO SELECTORS, ONE TABLE, AND THE SECOND IS NOT REDUNDANT. A custom property substitutes its
|
|
479
|
+
var() where it is DECLARED, so on `.deck-pairs` alone every slot resolves against the slide
|
|
480
|
+
element — and a `deck-dark` PANEL inside that slide inherits the finished LIGHT colour, however
|
|
481
|
+
correctly the source token re-points beneath it. The panel would draw the light pairs on a dark
|
|
482
|
+
ground, which is the pairing this whole block exists to make unreachable.
|
|
483
|
+
|
|
484
|
+
Re-declaring under `.deck-pairs .deck-dark` makes the substitution happen again inside the
|
|
485
|
+
panel, where `.deck-dark` has already re-pointed --dataviz-categorical-pairs-* to their dark
|
|
486
|
+
values. Same trap, same fix, as the derived surfaces below and the dataviz aliases above. */
|
|
487
|
+
.deck-pairs,
|
|
488
|
+
.deck-pairs .deck-dark {
|
|
489
|
+
--deck-series-1: var(--dataviz-categorical-pairs-forest-deep);
|
|
490
|
+
--deck-series-2: var(--dataviz-categorical-pairs-forest-soft);
|
|
491
|
+
--deck-series-3: var(--dataviz-categorical-pairs-warm-deep);
|
|
492
|
+
--deck-series-4: var(--dataviz-categorical-pairs-warm-soft);
|
|
493
|
+
--deck-series-5: var(--dataviz-categorical-pairs-river-deep);
|
|
494
|
+
--deck-series-6: var(--dataviz-categorical-pairs-river-soft);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/* ── Surfaces and borders — DERIVED from the ground, not picked off a ramp ────────────────────
|
|
498
|
+
Each level is the page mixed with a little ink — the same mechanism as .forest-card's l1/l2/l3.
|
|
499
|
+
It obeys "surfaces step AWAY from the page: light DARKER, dark LIGHTER" automatically, because the
|
|
500
|
+
ink flips with the mode; and it re-tunes itself the moment --deck-bg moves, which a ramp step
|
|
501
|
+
cannot (the warm ramp has nothing between 50 and 100, a real peach).
|
|
502
|
+
|
|
503
|
+
★★ Declared on EVERY mode boundary, NOT just :root. A custom property computes ONCE where it is
|
|
504
|
+
declared and then inherits that fixed colour — so on :root alone a `class: deck-dark` slide would
|
|
505
|
+
re-point --deck-bg and still inherit the LIGHT surface resolved at :root. Same trap, same fix, as
|
|
506
|
+
forest.css's card levels. */
|
|
507
|
+
:root,
|
|
508
|
+
.dark,
|
|
509
|
+
.deck-dark {
|
|
510
|
+
--deck-surface: color-mix(in oklab, var(--deck-bg), var(--deck-fg) 5%); /* L1 — a card on the page */
|
|
511
|
+
--deck-surface-strong: color-mix(in oklab, var(--deck-bg), var(--deck-fg) 10%); /* L2 — a card on a card. Was surface-raised: a name claiming a direction the ladder has none of */
|
|
512
|
+
--deck-border: color-mix(in oklab, var(--deck-bg), var(--deck-fg) 14%);
|
|
513
|
+
--deck-border-strong: color-mix(in oklab, var(--deck-bg), var(--deck-fg) 26%); /* the heavier rule — an axis against its gridlines, an edge against a hatch */
|
|
514
|
+
--deck-dot-land: color-mix(in oklab, var(--deck-bg), var(--deck-fg) 34%); /* the map dot grid — has to read as a SHAPE across a room */
|
|
515
|
+
}
|