@theme-registry/refract 0.1.10 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -5
- package/dist/build.cjs.js +1 -1
- package/dist/build.cjs.js.map +1 -1
- package/dist/build.esm.js +1 -1
- package/dist/build.esm.js.map +1 -1
- package/dist/cli.js +327 -169
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6114,7 +6114,7 @@ const SECTIONS = [
|
|
|
6114
6114
|
{ id: "type", title: "Type scale", eyebrow: "Typography" },
|
|
6115
6115
|
{ id: "space", title: "Spacing and size", eyebrow: "Space",
|
|
6116
6116
|
note: "There is no separate <code>padding</code> token — spacing <em>is</em> the padding scale, so it is shown both as a measure and as an applied inset." },
|
|
6117
|
-
{ id: "shape", title: "Borders, radius and elevation", eyebrow: "Shape &
|
|
6117
|
+
{ id: "shape", title: "Borders, radius and elevation", eyebrow: "Shape & depth" },
|
|
6118
6118
|
{ id: "motion", title: "Transitions", eyebrow: "Motion" },
|
|
6119
6119
|
{ id: "layout", title: "Breakpoints", eyebrow: "Layout",
|
|
6120
6120
|
note: "These drive the Width control at the top — pick one to reflow the whole specimen at that viewport." },
|
|
@@ -6155,6 +6155,64 @@ function lightnessOf(value) {
|
|
|
6155
6155
|
return undefined;
|
|
6156
6156
|
}
|
|
6157
6157
|
}
|
|
6158
|
+
/** WCAG relative luminance of a hex colour, or `undefined` when it isn't one. */
|
|
6159
|
+
function luminance(value) {
|
|
6160
|
+
const hex = value.trim();
|
|
6161
|
+
if (!/^#[0-9a-f]{6}$/i.test(hex))
|
|
6162
|
+
return undefined;
|
|
6163
|
+
const n = parseInt(hex.slice(1), 16);
|
|
6164
|
+
const ch = (c) => {
|
|
6165
|
+
const v = c / 255;
|
|
6166
|
+
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
6167
|
+
};
|
|
6168
|
+
return 0.2126 * ch((n >> 16) & 255) + 0.7152 * ch((n >> 8) & 255) + 0.0722 * ch(n & 255);
|
|
6169
|
+
}
|
|
6170
|
+
/** WCAG contrast ratio between two hex colours, or `undefined` if either isn't parseable. */
|
|
6171
|
+
function contrastRatio(a, b) {
|
|
6172
|
+
const la = luminance(a);
|
|
6173
|
+
const lb = luminance(b);
|
|
6174
|
+
if (la === undefined || lb === undefined)
|
|
6175
|
+
return undefined;
|
|
6176
|
+
return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
|
|
6177
|
+
}
|
|
6178
|
+
function colorProvenance(model) {
|
|
6179
|
+
var _a, _b, _c, _d;
|
|
6180
|
+
const out = new Map();
|
|
6181
|
+
const properties = (_b = (_a = model.subsystems.colors) === null || _a === void 0 ? void 0 : _a.properties) !== null && _b !== void 0 ? _b : {};
|
|
6182
|
+
const mark = (path, ref) => {
|
|
6183
|
+
var _a, _b;
|
|
6184
|
+
if (!ref)
|
|
6185
|
+
return;
|
|
6186
|
+
const derived = ref.ref !== undefined || ref.fn !== undefined || ((_b = (_a = ref.modifiers) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0;
|
|
6187
|
+
out.set(path, derived ? "gen" : "src");
|
|
6188
|
+
};
|
|
6189
|
+
for (const [family, property] of Object.entries(properties)) {
|
|
6190
|
+
mark(`colors.${family}`, property.base);
|
|
6191
|
+
for (const [extra, ref] of Object.entries((_c = property.extras) !== null && _c !== void 0 ? _c : {}))
|
|
6192
|
+
mark(`colors.${family}.${extra}`, ref);
|
|
6193
|
+
for (const [variant, model2] of Object.entries((_d = property.variants) !== null && _d !== void 0 ? _d : {})) {
|
|
6194
|
+
mark(`colors.${family}.${variant}`, model2.base);
|
|
6195
|
+
}
|
|
6196
|
+
}
|
|
6197
|
+
return out;
|
|
6198
|
+
}
|
|
6199
|
+
/**
|
|
6200
|
+
* The masthead wears the theme's own first palette — the one place the chrome takes a hue, and it
|
|
6201
|
+
* takes the theme's rather than asserting one. Falls back to ink when no colour token parses.
|
|
6202
|
+
*/
|
|
6203
|
+
function mastheadColor(leaves) {
|
|
6204
|
+
var _a;
|
|
6205
|
+
const usable = (l) => l.type === "color" && /^#[0-9a-f]{6}$/i.test(String(l.value).trim());
|
|
6206
|
+
// A family's `base` — NOT merely the first colour leaf, which is a ladder rung (`50`) and comes
|
|
6207
|
+
// out near-white. Fall back to any colour only when no family declares a base.
|
|
6208
|
+
const first = (_a = leaves.find(l => usable(l) && l.path[l.path.length - 1] === "base")) !== null && _a !== void 0 ? _a : leaves.find(usable);
|
|
6209
|
+
if (!first)
|
|
6210
|
+
return undefined;
|
|
6211
|
+
const bg = String(first.value).trim();
|
|
6212
|
+
const L = lightnessOf(bg);
|
|
6213
|
+
// A light brand needs dark type on it; anything else takes white.
|
|
6214
|
+
return { bg, fg: L !== undefined && L > 62 ? "#14171c" : "#ffffff" };
|
|
6215
|
+
}
|
|
6158
6216
|
/**
|
|
6159
6217
|
* Which rung the family's `base` LANDS on — never which rung it *is*.
|
|
6160
6218
|
*
|
|
@@ -6181,10 +6239,20 @@ function pxOf(value) {
|
|
|
6181
6239
|
return undefined;
|
|
6182
6240
|
return match[2] === "rem" || match[2] === "em" ? n * 16 : n;
|
|
6183
6241
|
}
|
|
6184
|
-
|
|
6185
|
-
|
|
6242
|
+
/**
|
|
6243
|
+
* Colour, as one CARD per family.
|
|
6244
|
+
*
|
|
6245
|
+
* The flat row-per-token list this replaces gave every family the same weight and let them run
|
|
6246
|
+
* together; a card gives each family an edge, a large base swatch to judge against, and room to
|
|
6247
|
+
* separate what the author WROTE from what refract derived.
|
|
6248
|
+
*/
|
|
6249
|
+
function renderPalette(leaves, model, tokenName) {
|
|
6186
6250
|
var _a, _b, _c;
|
|
6187
|
-
|
|
6251
|
+
const provenance = colorProvenance(model);
|
|
6252
|
+
const tagFor = (path) => {
|
|
6253
|
+
const kind = provenance.get(path);
|
|
6254
|
+
return kind ? `<span class="rfp-tag rfp-${kind}">${kind}</span>` : "";
|
|
6255
|
+
};
|
|
6188
6256
|
const families = new Map();
|
|
6189
6257
|
for (const leaf of leaves) {
|
|
6190
6258
|
const family = (_a = leaf.path[1]) !== null && _a !== void 0 ? _a : "color";
|
|
@@ -6195,63 +6263,80 @@ function renderPalette(leaves, tokenName) {
|
|
|
6195
6263
|
else
|
|
6196
6264
|
families.set(family, [[member, String(leaf.value)]]);
|
|
6197
6265
|
}
|
|
6198
|
-
const
|
|
6199
|
-
const
|
|
6266
|
+
const cards = [];
|
|
6267
|
+
const semantic = [];
|
|
6268
|
+
let total = 0;
|
|
6269
|
+
let passing = 0;
|
|
6200
6270
|
for (const [family, members] of families) {
|
|
6201
|
-
const rungs = members.filter(([name]) => isRung(name));
|
|
6271
|
+
const rungs = members.filter(([name]) => isRung(name)).sort((a, b) => Number(a[0]) - Number(b[0]));
|
|
6202
6272
|
const base = (_b = members.find(([name]) => name === "base")) === null || _b === void 0 ? void 0 : _b[1];
|
|
6273
|
+
const text = (_c = members.find(([name]) => name === "text")) === null || _c === void 0 ? void 0 : _c[1];
|
|
6274
|
+
const path = `colors.${family}`;
|
|
6275
|
+
// The one contrast pairing the author actually declared.
|
|
6276
|
+
if (base && text) {
|
|
6277
|
+
const ratio = contrastRatio(base, text);
|
|
6278
|
+
if (ratio !== undefined) {
|
|
6279
|
+
total += 1;
|
|
6280
|
+
if (ratio >= 4.5)
|
|
6281
|
+
passing += 1;
|
|
6282
|
+
}
|
|
6283
|
+
}
|
|
6203
6284
|
if (rungs.length >= 3) {
|
|
6204
|
-
// A ladder: contiguous rungs read as a ramp in a way a row-per-token list never does.
|
|
6205
|
-
rungs.sort((a, b) => Number(a[0]) - Number(b[0]));
|
|
6206
6285
|
const lands = baseLandsOn(base, rungs);
|
|
6207
6286
|
const strip = rungs
|
|
6208
6287
|
.map(([step, hex]) => {
|
|
6209
6288
|
const isLanding = lands !== undefined && step === lands;
|
|
6210
|
-
return (`<div class="rfp-rung"${isLanding ?
|
|
6289
|
+
return (`<div class="rfp-rung"${isLanding ? " data-lands" : ""}` +
|
|
6211
6290
|
` title="colors.${esc(family)}.${esc(step)} · ${esc(hex)}${isLanding ? " · base lands here" : ""}">` +
|
|
6212
|
-
`<div class="rfp-
|
|
6291
|
+
`<div class="rfp-sw" style="background:${cssValue(hex)}"></div>` +
|
|
6213
6292
|
`<div class="rfp-rung-foot">${esc(step)}</div></div>`);
|
|
6214
6293
|
})
|
|
6215
6294
|
.join("");
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6295
|
+
// Anything that isn't a rung is a declared member — show it with its provenance.
|
|
6296
|
+
const chips = members
|
|
6297
|
+
.filter(([name]) => !isRung(name) && name !== "base")
|
|
6298
|
+
.map(([member, hex]) => chipOf(`${path}.${member}`, member, hex, tagFor(`${path}.${member}`), tokenName))
|
|
6299
|
+
.join("");
|
|
6300
|
+
cards.push(`<section class="rfp-card"><div class="rfp-pal-top">` +
|
|
6301
|
+
`<div class="rfp-pal-base" style="background:${cssValue(base !== null && base !== void 0 ? base : rungs[Math.floor(rungs.length / 2)][1])}"></div>` +
|
|
6302
|
+
`<h3 class="rfp-pal-name">${esc(family)}` +
|
|
6303
|
+
`<small>${base ? `base ${esc(base)}` : ""}${lands ? ` · lands ≈ ${esc(lands)}` : ""} · ${rungs.length} rungs</small>` +
|
|
6304
|
+
idButton(path, tokenName === null || tokenName === void 0 ? void 0 : tokenName(path)) +
|
|
6305
|
+
`</h3></div>` +
|
|
6306
|
+
`<div class="rfp-row-label">Lightness ladder ${tagFor(`${path}.${rungs[0][0]}`) || '<span class="rfp-tag rfp-gen">gen</span>'}</div>` +
|
|
6307
|
+
`<div class="rfp-rungs">${strip}</div>` +
|
|
6308
|
+
(chips ? `<div class="rfp-row-label">Declared members</div><div class="rfp-chips">${chips}</div>` : "") +
|
|
6309
|
+
`</section>`);
|
|
6224
6310
|
continue;
|
|
6225
6311
|
}
|
|
6226
|
-
//
|
|
6227
|
-
//
|
|
6228
|
-
// The contrast readout goes ONLY on the member that genuinely declares the pairing: the family
|
|
6229
|
-
// base against its own `text`. Derived tints (`brand.dark`, `surface.lighter`, …) were never
|
|
6230
|
-
// meant to carry that text, so scoring them produces "fail" badges that read as a defect in the
|
|
6231
|
-
// user's theme when nothing is wrong. On a page whose whole job is to tell the truth about a
|
|
6232
|
-
// theme, inventing a pairing to score is the worst kind of noise.
|
|
6233
|
-
const text = (_c = members.find(([name]) => name === "text")) === null || _c === void 0 ? void 0 : _c[1];
|
|
6312
|
+
// No ladder — the family is a semantic colour (or a small set), so it joins the swatch grid.
|
|
6234
6313
|
for (const [member, hex] of members) {
|
|
6235
6314
|
if (member === "text")
|
|
6236
6315
|
continue;
|
|
6237
6316
|
const isBase = member === "base";
|
|
6238
|
-
const
|
|
6239
|
-
|
|
6240
|
-
pairs.push(`<div class="rfp-pair"><div class="rfp-pair-swatch" data-bg="${esc(hex)}"${paired ? ` data-fg="${esc(paired)}"` : ""}` +
|
|
6241
|
-
` style="background:${cssValue(hex)}${paired ? `;color:${cssValue(paired)}` : ""}">` +
|
|
6242
|
-
(paired ? `<span class="rfp-pair-sample">Aa</span><span class="rfp-pair-ratio"></span>` : "") +
|
|
6243
|
-
`</div><div class="rfp-pair-foot">${idButton(path, tokenName === null || tokenName === void 0 ? void 0 : tokenName(path))}` +
|
|
6244
|
-
`<span class="rfp-hex">${esc(hex)}${paired ? ` on ${esc(paired)}` : ""}</span></div></div>`);
|
|
6317
|
+
const memberPath = isBase ? path : `${path}.${member}`;
|
|
6318
|
+
semantic.push(chipOf(memberPath, isBase ? family : member, hex, tagFor(memberPath), tokenName, isBase ? text : undefined));
|
|
6245
6319
|
}
|
|
6246
6320
|
}
|
|
6247
|
-
let html = "";
|
|
6248
|
-
if (
|
|
6249
|
-
html +=
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6321
|
+
let html = cards.join("");
|
|
6322
|
+
if (semantic.length) {
|
|
6323
|
+
html +=
|
|
6324
|
+
`<section class="rfp-card"><div class="rfp-card-head"><span class="rfp-card-name">Semantic</span>` +
|
|
6325
|
+
`<span class="rfp-card-sub">contrast scored only where a <code>text</code> pairing is declared</span></div>` +
|
|
6326
|
+
`<div class="rfp-chips">${semantic.join("")}</div></section>`;
|
|
6253
6327
|
}
|
|
6254
|
-
return html;
|
|
6328
|
+
return { html, pairings: { total, passing } };
|
|
6329
|
+
}
|
|
6330
|
+
/** One colour chip: swatch (+ live contrast when a pairing is declared), label, tag, value. */
|
|
6331
|
+
function chipOf(path, label, hex, tag, tokenName, pairedText) {
|
|
6332
|
+
return (`<div class="rfp-chip"><div class="rfp-sw rfp-chip-sw"` +
|
|
6333
|
+
(pairedText ? ` data-bg="${esc(hex)}" data-fg="${esc(pairedText)}"` : "") +
|
|
6334
|
+
` style="background:${cssValue(hex)}${pairedText ? `;color:${cssValue(pairedText)}` : ""}">` +
|
|
6335
|
+
(pairedText ? `<span class="rfp-ratio"></span>` : "") +
|
|
6336
|
+
`</div><div class="rfp-cap"><div class="rfp-lbl">${esc(label)}${tag}</div>` +
|
|
6337
|
+
`<div class="rfp-val-sm">${esc(hex)}${pairedText ? ` on ${esc(pairedText)}` : ""}</div>` +
|
|
6338
|
+
idButton(path, tokenName === null || tokenName === void 0 ? void 0 : tokenName(path)) +
|
|
6339
|
+
`</div></div>`);
|
|
6255
6340
|
}
|
|
6256
6341
|
// ── Typography ─────────────────────────────────────────────────────────────
|
|
6257
6342
|
function renderTypography(leaves, tokenName) {
|
|
@@ -6647,6 +6732,33 @@ function renderComposition(recipes, descriptor) {
|
|
|
6647
6732
|
}
|
|
6648
6733
|
return "";
|
|
6649
6734
|
}
|
|
6735
|
+
/**
|
|
6736
|
+
* The contents cover. Built from the sections that actually rendered, so it shrinks with the theme
|
|
6737
|
+
* rather than advertising plates that aren't there. Accent bars borrow the theme's own colour.
|
|
6738
|
+
*/
|
|
6739
|
+
function renderIndex(bodies, counts, accent) {
|
|
6740
|
+
const present = SECTIONS.filter(s => bodies.has(s.id));
|
|
6741
|
+
if (present.length < 2)
|
|
6742
|
+
return "";
|
|
6743
|
+
const cards = present
|
|
6744
|
+
.map((section, i) => {
|
|
6745
|
+
var _a;
|
|
6746
|
+
const n = String(i + 1).padStart(2, "0");
|
|
6747
|
+
const count = (_a = counts.get(section.id)) !== null && _a !== void 0 ? _a : 0;
|
|
6748
|
+
return (`<a class="rfp-idx" href="#rfp-${section.id}" style="text-decoration:none;color:inherit">` +
|
|
6749
|
+
`<span class="rfp-accent" style="background:${accent ? cssValue(accent) : "var(--rfp-spec)"}"></span>` +
|
|
6750
|
+
`<div class="rfp-no">${n} · ${esc(section.eyebrow.toUpperCase())}</div>` +
|
|
6751
|
+
`<h3>${section.title} <span>${count} token(s)</span></h3>` +
|
|
6752
|
+
(section.note ? `<p>${section.note}</p>` : "") +
|
|
6753
|
+
`</a>`);
|
|
6754
|
+
})
|
|
6755
|
+
.join("");
|
|
6756
|
+
return (`<section class="rfp-section" id="rfp-index"><div class="rfp-section-head"><h2>Index</h2>` +
|
|
6757
|
+
`<span class="rfp-count">${present.length} sections</span></div>` +
|
|
6758
|
+
`<p class="rfp-note">A section appears only when the theme has tokens of that kind, so this list ` +
|
|
6759
|
+
`is the shape of the theme rather than a fixed table of contents.</p>` +
|
|
6760
|
+
`<div class="rfp-index">${cards}</div></section>`);
|
|
6761
|
+
}
|
|
6650
6762
|
// ---------------------------------------------------------------------------
|
|
6651
6763
|
// Page chrome
|
|
6652
6764
|
// ---------------------------------------------------------------------------
|
|
@@ -6661,159 +6773,183 @@ function renderComposition(recipes, descriptor) {
|
|
|
6661
6773
|
* dedicated mid-tone reads at the same weight on both grounds.
|
|
6662
6774
|
*/
|
|
6663
6775
|
const CHROME_CSS = `
|
|
6664
|
-
.rfp{--rfp-
|
|
6665
|
-
--rfp-ink-3:#79818f;--rfp-
|
|
6666
|
-
--rfp-spec:#97a1b0;--rfp-spec-2:#c2c9d4;--rfp-hatch:#
|
|
6667
|
-
--rfp-accent:#6b7a99;
|
|
6776
|
+
.rfp{--rfp-paper:#f5f6f8;--rfp-card:#fff;--rfp-sunk:#f0f2f5;--rfp-ink:#14171c;--rfp-ink-2:#4d5563;
|
|
6777
|
+
--rfp-ink-3:#79818f;--rfp-line:#e3e6ea;--rfp-line-2:#d0d5dd;--rfp-focus:#3b4ea8;
|
|
6778
|
+
--rfp-spec:#97a1b0;--rfp-spec-2:#c2c9d4;--rfp-hatch:#dfe3e9;
|
|
6668
6779
|
--rfp-mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
|
|
6669
6780
|
--rfp-ui:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
|
|
6670
6781
|
font-family:var(--rfp-ui);font-size:14px;line-height:1.55;color:var(--rfp-ink);
|
|
6671
|
-
background:var(--rfp-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6782
|
+
background:var(--rfp-paper);-webkit-font-smoothing:antialiased;
|
|
6783
|
+
width:100%;min-height:100vh;box-sizing:border-box}
|
|
6784
|
+
/* Full-bleed geometry. :where() gives these ZERO specificity, so a theme's own globals rules still
|
|
6785
|
+
win - the chrome resets the UA gutter without ever outranking the theme it is displaying.
|
|
6786
|
+
color-scheme is pinned to light: this sheet does NOT follow the OS (see below). */
|
|
6787
|
+
:where(html){color-scheme:light}
|
|
6788
|
+
:where(body){margin:0}
|
|
6678
6789
|
.rfp *{box-sizing:border-box}
|
|
6679
6790
|
.rfp *:focus-visible{outline:2px solid var(--rfp-focus);outline-offset:2px;border-radius:3px}
|
|
6680
|
-
|
|
6681
|
-
.rfp-
|
|
6682
|
-
|
|
6791
|
+
/* ── Masthead: the theme wearing its own first palette ── */
|
|
6792
|
+
.rfp-masthead{padding:52px 40px 36px}
|
|
6793
|
+
.rfp-kicker{font-family:var(--rfp-mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;opacity:.75;margin:0 0 12px}
|
|
6794
|
+
.rfp-masthead h1{margin:0;font-size:38px;font-weight:680;letter-spacing:-.028em;text-wrap:balance}
|
|
6795
|
+
.rfp-lede{margin:12px 0 0;max-width:66ch;opacity:.88;font-size:15px}
|
|
6796
|
+
.rfp-metrics{margin-top:28px;display:flex;gap:34px;flex-wrap:wrap}
|
|
6797
|
+
.rfp-metric b{display:block;font-size:26px;font-weight:700;line-height:1.1;font-variant-numeric:tabular-nums}
|
|
6798
|
+
.rfp-metric span{font-size:12px;opacity:.72;font-family:var(--rfp-mono)}
|
|
6799
|
+
/* ── Shell ── */
|
|
6800
|
+
.rfp-shell{display:grid;grid-template-columns:204px minmax(0,1fr);gap:44px;padding:0 40px 96px;align-items:start}
|
|
6801
|
+
.rfp-rail{position:sticky;top:0;padding:28px 0;max-height:100vh;overflow-y:auto}
|
|
6802
|
+
.rfp-brand{font-family:var(--rfp-mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
|
|
6803
|
+
color:var(--rfp-ink-3);padding-bottom:12px;margin-bottom:12px;border-bottom:1px solid var(--rfp-line)}
|
|
6683
6804
|
.rfp-nav{display:flex;flex-direction:column;gap:1px}
|
|
6684
6805
|
.rfp-nav a{display:flex;justify-content:space-between;align-items:baseline;gap:10px;padding:5px 8px;
|
|
6685
|
-
border-radius:
|
|
6686
|
-
.rfp-nav a:hover{background:var(--rfp-
|
|
6687
|
-
.rfp-nav a[aria-current="true"]{background:var(--rfp-ink);color:var(--rfp-
|
|
6806
|
+
border-radius:5px;color:var(--rfp-ink-2);text-decoration:none;font-size:13px}
|
|
6807
|
+
.rfp-nav a:hover{background:var(--rfp-card);color:var(--rfp-ink)}
|
|
6808
|
+
.rfp-nav a[aria-current="true"]{background:var(--rfp-ink);color:var(--rfp-paper)}
|
|
6688
6809
|
.rfp-nav .rfp-n{font-family:var(--rfp-mono);font-size:11px;font-variant-numeric:tabular-nums;color:var(--rfp-ink-3)}
|
|
6689
|
-
.rfp-nav a[aria-current="true"] .rfp-n{color:var(--rfp-
|
|
6690
|
-
.rfp-main{padding-top:
|
|
6691
|
-
.rfp-
|
|
6692
|
-
.rfp-eyebrow{font-family:var(--rfp-mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--rfp-ink-3)}
|
|
6693
|
-
.rfp-masthead h1{font-size:34px;line-height:1.1;letter-spacing:-.025em;font-weight:640;margin:10px 0 0;text-wrap:balance}
|
|
6694
|
-
.rfp-meta{display:flex;flex-wrap:wrap;gap:6px 10px;margin-top:16px;font-family:var(--rfp-mono);font-size:11.5px;color:var(--rfp-ink-2)}
|
|
6695
|
-
.rfp-meta span{display:inline-flex;align-items:center;gap:6px}
|
|
6696
|
-
.rfp-meta span+span::before{content:"";width:1px;height:11px;background:var(--rfp-rule-2)}
|
|
6697
|
-
.rfp-meta b{font-weight:600;color:var(--rfp-ink)}
|
|
6698
|
-
.rfp-dot{width:6px;height:6px;border-radius:50%;background:var(--rfp-live)}
|
|
6699
|
-
.rfp-controls{display:flex;flex-wrap:wrap;gap:24px;padding:18px 0;border-bottom:1px solid var(--rfp-rule);
|
|
6700
|
-
position:sticky;top:0;background:var(--rfp-ground);z-index:5}
|
|
6810
|
+
.rfp-nav a[aria-current="true"] .rfp-n{color:var(--rfp-paper);opacity:.6}
|
|
6811
|
+
.rfp-main{padding-top:28px;min-width:0}
|
|
6812
|
+
.rfp-controls{display:flex;flex-wrap:wrap;gap:22px;padding:14px 0 18px;position:sticky;top:0;background:var(--rfp-paper);z-index:5}
|
|
6701
6813
|
.rfp-ctl{display:flex;align-items:center;gap:8px}
|
|
6702
6814
|
.rfp-ctl-label{font-family:var(--rfp-mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--rfp-ink-3)}
|
|
6703
|
-
.rfp-seg{display:flex;border:1px solid var(--rfp-
|
|
6704
|
-
.rfp-seg button{font:inherit;font-family:var(--rfp-mono);font-size:11.5px;padding:4px
|
|
6705
|
-
border-left:1px solid var(--rfp-
|
|
6815
|
+
.rfp-seg{display:flex;border:1px solid var(--rfp-line-2);border-radius:7px;overflow:hidden;background:var(--rfp-card)}
|
|
6816
|
+
.rfp-seg button{font:inherit;font-family:var(--rfp-mono);font-size:11.5px;padding:4px 11px;border:0;
|
|
6817
|
+
border-left:1px solid var(--rfp-line-2);background:transparent;color:var(--rfp-ink-2);cursor:pointer}
|
|
6706
6818
|
.rfp-seg button:first-child{border-left:0}
|
|
6707
|
-
.rfp-seg button:hover{background:var(--rfp-
|
|
6708
|
-
.rfp-seg button[aria-pressed="true"]{background:var(--rfp-ink);color:var(--rfp-
|
|
6709
|
-
|
|
6710
|
-
.rfp-section
|
|
6711
|
-
.rfp-section-head
|
|
6712
|
-
.rfp-
|
|
6819
|
+
.rfp-seg button:hover{background:var(--rfp-sunk);color:var(--rfp-ink)}
|
|
6820
|
+
.rfp-seg button[aria-pressed="true"]{background:var(--rfp-ink);color:var(--rfp-card)}
|
|
6821
|
+
/* ── Sections + cards ── */
|
|
6822
|
+
.rfp-section{padding-top:44px;scroll-margin-top:64px}
|
|
6823
|
+
.rfp-section-head{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap}
|
|
6824
|
+
.rfp-section-head h2{margin:0;font-size:21px;letter-spacing:-.018em;font-weight:640}
|
|
6825
|
+
.rfp-count{font-family:var(--rfp-mono);font-size:11px;color:var(--rfp-ink-2);background:var(--rfp-card);
|
|
6826
|
+
border:1px solid var(--rfp-line);border-radius:999px;padding:2px 10px;white-space:nowrap}
|
|
6827
|
+
.rfp-note{margin:8px 0 20px;color:var(--rfp-ink-2);font-size:13.5px;max-width:72ch}
|
|
6713
6828
|
.rfp-note-sm{color:var(--rfp-ink-3);font-size:12.5px;margin:10px 0 0;max-width:64ch}
|
|
6714
|
-
.rfp-
|
|
6715
|
-
.rfp-
|
|
6716
|
-
.rfp-
|
|
6717
|
-
.rfp-
|
|
6718
|
-
.rfp-
|
|
6829
|
+
.rfp-card{background:var(--rfp-card);border:1px solid var(--rfp-line);border-radius:14px;padding:18px 20px;margin-top:14px}
|
|
6830
|
+
.rfp-card-head{display:flex;align-items:baseline;gap:10px;margin-bottom:14px;flex-wrap:wrap}
|
|
6831
|
+
.rfp-card-name{font-family:var(--rfp-mono);font-size:12.5px;font-weight:600}
|
|
6832
|
+
.rfp-card-sub{font-family:var(--rfp-mono);font-size:11px;color:var(--rfp-ink-3)}
|
|
6833
|
+
.rfp-row-label{font-family:var(--rfp-mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
|
|
6834
|
+
color:var(--rfp-ink-3);margin:16px 0 9px;display:flex;align-items:center;gap:8px}
|
|
6835
|
+
.rfp-divider{display:flex;align-items:center;gap:14px;margin:52px 0 4px}
|
|
6836
|
+
.rfp-divider span{font-family:var(--rfp-mono);font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;
|
|
6837
|
+
color:var(--rfp-ink-3);white-space:nowrap}
|
|
6838
|
+
.rfp-divider::before,.rfp-divider::after{content:"";height:1px;background:var(--rfp-line);flex:1}
|
|
6839
|
+
/* ── Index cover ── */
|
|
6840
|
+
.rfp-index{display:grid;grid-template-columns:repeat(auto-fill,minmax(272px,1fr));gap:14px}
|
|
6841
|
+
.rfp-idx{position:relative;background:var(--rfp-card);border:1px solid var(--rfp-line);border-radius:14px;
|
|
6842
|
+
padding:18px 18px 15px 22px;overflow:hidden}
|
|
6843
|
+
.rfp-idx .rfp-accent{position:absolute;inset:0 auto 0 0;width:5px}
|
|
6844
|
+
.rfp-idx .rfp-no{font-family:var(--rfp-mono);font-size:10.5px;font-weight:700;letter-spacing:.12em;color:var(--rfp-ink-3)}
|
|
6845
|
+
.rfp-idx h3{margin:6px 0 2px;font-size:18px;letter-spacing:-.015em;font-weight:620}
|
|
6846
|
+
.rfp-idx h3 span{font-family:var(--rfp-mono);font-size:11px;font-weight:500;color:var(--rfp-ink-3)}
|
|
6847
|
+
.rfp-idx p{margin:7px 0 0;font-size:12.5px;color:var(--rfp-ink-2)}
|
|
6848
|
+
/* ── Identifiers ── */
|
|
6719
6849
|
.rfp-id{font-family:var(--rfp-mono);font-size:11.5px;color:var(--rfp-ink-2);background:none;border:0;
|
|
6720
6850
|
padding:1px 4px;margin-left:-4px;border-radius:3px;cursor:copy;text-align:left;display:inline-block}
|
|
6721
|
-
.rfp-id:hover{background:var(--rfp-
|
|
6722
|
-
.rfp-id.rfp-copied{background:var(--rfp-ink);color:var(--rfp-
|
|
6851
|
+
.rfp-id:hover{background:var(--rfp-sunk);color:var(--rfp-ink)}
|
|
6852
|
+
.rfp-id.rfp-copied{background:var(--rfp-ink);color:var(--rfp-card)}
|
|
6723
6853
|
.rfp-var{font-family:var(--rfp-mono);font-size:10.5px;color:var(--rfp-ink-3);display:block;margin-top:1px}
|
|
6724
6854
|
.rfp-hex{font-family:var(--rfp-mono);font-size:11px;color:var(--rfp-ink-3);font-variant-numeric:tabular-nums;display:block;margin-top:1px}
|
|
6725
|
-
|
|
6726
|
-
.rfp-
|
|
6727
|
-
|
|
6728
|
-
.rfp-
|
|
6729
|
-
.rfp-
|
|
6855
|
+
/* ── Provenance tags ── */
|
|
6856
|
+
.rfp-tag{font-family:var(--rfp-mono);font-size:9px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
|
|
6857
|
+
padding:1px 5px;border-radius:4px}
|
|
6858
|
+
.rfp-src{background:color-mix(in srgb,var(--rfp-focus) 12%,transparent);color:var(--rfp-focus)}
|
|
6859
|
+
.rfp-gen{background:var(--rfp-sunk);color:var(--rfp-ink-3);border:1px solid var(--rfp-line)}
|
|
6860
|
+
/* ── Palette ── */
|
|
6861
|
+
.rfp-pal-top{display:flex;align-items:center;gap:16px}
|
|
6862
|
+
.rfp-pal-base{width:84px;height:84px;border-radius:12px;flex:none;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1)}
|
|
6863
|
+
.rfp-pal-name{margin:0;font-size:18px;font-weight:680;letter-spacing:-.015em}
|
|
6864
|
+
.rfp-pal-name small{display:block;font-family:var(--rfp-mono);font-weight:400;color:var(--rfp-ink-3);font-size:11.5px;margin-top:4px}
|
|
6865
|
+
.rfp-rungs{display:flex;border-radius:9px;overflow:hidden;border:1px solid var(--rfp-line)}
|
|
6730
6866
|
.rfp-rung{flex:1 1 0;min-width:0}
|
|
6731
|
-
.rfp-rung-
|
|
6732
|
-
.rfp-rung
|
|
6733
|
-
.rfp-rung[data-lands="true"] .rfp-rung-foot::before{content:"◆ "}
|
|
6734
|
-
.rfp-rung-foot{padding:5px 2px 6px;text-align:center;background:var(--rfp-panel);border-top:1px solid var(--rfp-rule);
|
|
6867
|
+
.rfp-rung .rfp-sw{height:54px}
|
|
6868
|
+
.rfp-rung-foot{padding:6px 2px 7px;text-align:center;background:var(--rfp-sunk);border-top:1px solid var(--rfp-line);
|
|
6735
6869
|
font-family:var(--rfp-mono);font-size:10px;font-variant-numeric:tabular-nums;color:var(--rfp-ink-2)}
|
|
6736
|
-
.rfp-
|
|
6737
|
-
.rfp-
|
|
6738
|
-
.rfp-
|
|
6739
|
-
.rfp-
|
|
6740
|
-
.rfp-
|
|
6741
|
-
|
|
6742
|
-
.rfp-
|
|
6870
|
+
.rfp-rung[data-lands] .rfp-rung-foot{color:var(--rfp-ink);font-weight:700}
|
|
6871
|
+
.rfp-rung[data-lands] .rfp-rung-foot::before{content:"◆ "}
|
|
6872
|
+
.rfp-chips{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:10px}
|
|
6873
|
+
.rfp-chip{border:1px solid var(--rfp-line);border-radius:10px;overflow:hidden;background:var(--rfp-card)}
|
|
6874
|
+
.rfp-chip-sw{height:50px;box-shadow:inset 0 0 0 1px rgba(0,0,0,.05);display:flex;align-items:flex-end;padding:6px}
|
|
6875
|
+
.rfp-cap{padding:8px 9px 9px}
|
|
6876
|
+
.rfp-lbl{font-size:12px;font-weight:600;display:flex;align-items:center;gap:6px;justify-content:space-between}
|
|
6877
|
+
.rfp-val-sm{font-family:var(--rfp-mono);font-size:10.5px;color:var(--rfp-ink-3);margin-top:3px;font-variant-numeric:tabular-nums}
|
|
6878
|
+
.rfp-ratio{font-family:var(--rfp-mono);font-size:10px;padding:1px 6px;border-radius:4px;border:1px solid currentColor}
|
|
6879
|
+
/* ── Rows ── */
|
|
6743
6880
|
.rfp-rows{display:flex;flex-direction:column}
|
|
6744
|
-
.rfp-row{display:grid;grid-template-columns:
|
|
6745
|
-
padding:11px 0;border-top:1px solid var(--rfp-
|
|
6881
|
+
.rfp-row{display:grid;grid-template-columns:200px minmax(0,1fr) 104px;gap:20px;align-items:baseline;
|
|
6882
|
+
padding:11px 0;border-top:1px solid var(--rfp-line)}
|
|
6746
6883
|
.rfp-row:first-child{border-top:0}
|
|
6747
6884
|
.rfp-row.rfp-centred{align-items:center}
|
|
6748
6885
|
.rfp-rowval{font-family:var(--rfp-mono);font-size:11px;color:var(--rfp-ink-3);font-variant-numeric:tabular-nums;text-align:right;overflow-wrap:anywhere}
|
|
6749
6886
|
.rfp-specimen{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:-.015em}
|
|
6750
6887
|
.rfp-leading{font-size:13px;color:var(--rfp-ink-2);max-width:52ch}
|
|
6751
|
-
.rfp-bar{height:
|
|
6888
|
+
.rfp-bar{height:13px;background:var(--rfp-spec);border-radius:3px;max-width:100%}
|
|
6752
6889
|
.rfp-bar.rfp-ghost{background:var(--rfp-spec-2)}
|
|
6753
|
-
.rfp-gap{display:flex;
|
|
6890
|
+
.rfp-gap{display:flex;border:1px dashed var(--rfp-line-2);border-radius:8px;padding:10px;background:var(--rfp-sunk)}
|
|
6754
6891
|
.rfp-gap>i{flex:1 1 0;height:30px;background:var(--rfp-spec-2);border-radius:3px}
|
|
6755
|
-
.rfp-inset{border:1px solid var(--rfp-
|
|
6892
|
+
.rfp-inset{border:1px solid var(--rfp-line-2);border-radius:10px;
|
|
6756
6893
|
background:repeating-linear-gradient(-45deg,var(--rfp-hatch) 0 4px,transparent 4px 8px)}
|
|
6757
|
-
.rfp-inset-core{background:var(--rfp-spec);color:var(--rfp-
|
|
6758
|
-
font-size:10.5px;font-weight:
|
|
6759
|
-
|
|
6760
|
-
.rfp-
|
|
6761
|
-
.rfp-
|
|
6762
|
-
|
|
6763
|
-
|
|
6894
|
+
.rfp-inset-core{background:var(--rfp-spec);color:var(--rfp-card);border-radius:4px;font-family:var(--rfp-mono);
|
|
6895
|
+
font-size:10.5px;font-weight:700;text-align:center;padding:9px 4px}
|
|
6896
|
+
/* ── Tiles ── */
|
|
6897
|
+
.rfp-tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(146px,1fr));gap:12px}
|
|
6898
|
+
.rfp-tile{border:1px solid var(--rfp-line);border-radius:12px;padding:14px;background:var(--rfp-card)}
|
|
6899
|
+
.rfp-stage{height:76px;display:grid;place-items:center;background:var(--rfp-sunk);border-radius:8px;
|
|
6900
|
+
margin-bottom:11px;color:var(--rfp-spec)}
|
|
6901
|
+
.rfp-obj{width:60px;height:60px;background:var(--rfp-spec)}
|
|
6764
6902
|
.rfp-obj.rfp-outlined{background:transparent}
|
|
6765
|
-
.rfp-obj.rfp-raised{background:var(--rfp-
|
|
6766
|
-
.rfp-obj.rfp-accent{background:var(--rfp-
|
|
6767
|
-
.rfp-numeral{font-family:var(--rfp-mono);font-size:
|
|
6768
|
-
.rfp-track{height:34px;border-radius:
|
|
6903
|
+
.rfp-obj.rfp-raised{background:var(--rfp-card)}
|
|
6904
|
+
.rfp-obj.rfp-accent{background:var(--rfp-spec)}
|
|
6905
|
+
.rfp-numeral{font-family:var(--rfp-mono);font-size:19px;font-variant-numeric:tabular-nums;color:var(--rfp-ink-2)}
|
|
6906
|
+
.rfp-track{height:34px;border-radius:8px;background:var(--rfp-sunk);border:1px solid var(--rfp-line);position:relative;overflow:hidden}
|
|
6769
6907
|
.rfp-dot{position:absolute;top:6px;left:6px;width:22px;height:22px;border-radius:5px;background:var(--rfp-spec)}
|
|
6770
|
-
.rfp-play{font:inherit;font-family:var(--rfp-mono);font-size:11.5px;padding:3px 10px;border-radius:
|
|
6771
|
-
border:1px solid var(--rfp-
|
|
6908
|
+
.rfp-play{font:inherit;font-family:var(--rfp-mono);font-size:11.5px;padding:3px 10px;border-radius:5px;
|
|
6909
|
+
border:1px solid var(--rfp-line-2);background:var(--rfp-sunk);color:var(--rfp-ink);cursor:pointer;margin-left:auto}
|
|
6910
|
+
/* ── Tables ── */
|
|
6772
6911
|
.rfp-scroll{overflow-x:auto}
|
|
6773
|
-
.rfp-diff{
|
|
6774
|
-
.rfp-diff th{text-align:left;font-family:var(--rfp-mono);font-size:10.5px;letter-spacing:.1em;
|
|
6775
|
-
color:var(--rfp-ink-3);font-weight:500;padding:0 12px
|
|
6776
|
-
.rfp-diff td{padding:
|
|
6912
|
+
.rfp-diff,.rfp-matrix{border-collapse:collapse;width:100%}
|
|
6913
|
+
.rfp-diff th,.rfp-matrix th{text-align:left;font-family:var(--rfp-mono);font-size:10.5px;letter-spacing:.1em;
|
|
6914
|
+
text-transform:uppercase;color:var(--rfp-ink-3);font-weight:500;padding:0 12px 9px 0;white-space:nowrap}
|
|
6915
|
+
.rfp-diff td{padding:9px 12px 9px 0;border-top:1px solid var(--rfp-line);vertical-align:middle}
|
|
6916
|
+
.rfp-matrix{min-width:560px}
|
|
6917
|
+
.rfp-matrix th{text-align:center;padding:0 8px 10px}
|
|
6918
|
+
.rfp-matrix th:first-child{text-align:left}
|
|
6919
|
+
.rfp-matrix td{padding:13px 8px;border-top:1px solid var(--rfp-line);text-align:center}
|
|
6920
|
+
.rfp-matrix td:first-child{text-align:left;width:208px}
|
|
6921
|
+
.rfp-none{font-family:var(--rfp-mono);font-size:11px;color:var(--rfp-ink-3);opacity:.55}
|
|
6777
6922
|
.rfp-swatch-cell{display:flex;align-items:center;gap:8px}
|
|
6778
|
-
.rfp-chip{width:18px;height:18px;border-radius:
|
|
6923
|
+
.rfp-chip-sm{width:18px;height:18px;border-radius:5px;border:1px solid var(--rfp-line-2);flex:none}
|
|
6779
6924
|
.rfp-arrow{color:var(--rfp-ink-3);font-family:var(--rfp-mono)}
|
|
6780
|
-
|
|
6781
|
-
.rfp-
|
|
6782
|
-
.rfp-
|
|
6783
|
-
|
|
6784
|
-
.rfp-
|
|
6785
|
-
.rfp-matrix td{padding:12px 8px;border-top:1px solid var(--rfp-rule);text-align:center}
|
|
6786
|
-
.rfp-matrix td:first-child{text-align:left;width:210px}
|
|
6787
|
-
.rfp-none{font-family:var(--rfp-mono);font-size:11px;color:var(--rfp-ink-3);opacity:.6}
|
|
6788
|
-
.rfp-recipes{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:14px}
|
|
6789
|
-
.rfp-recipe{border:1px solid var(--rfp-rule);border-radius:6px;overflow:hidden}
|
|
6790
|
-
.rfp-recipe-stage{min-height:96px;display:grid;place-items:center;padding:20px 16px;
|
|
6791
|
-
background:linear-gradient(45deg,var(--rfp-panel) 25%,transparent 25%,transparent 75%,var(--rfp-panel) 75%),
|
|
6792
|
-
linear-gradient(45deg,var(--rfp-panel) 25%,transparent 25%,transparent 75%,var(--rfp-panel) 75%);
|
|
6793
|
-
background-size:14px 14px;background-position:0 0,7px 7px}
|
|
6794
|
-
.rfp-recipe-foot{padding:9px 12px;border-top:1px solid var(--rfp-rule);background:var(--rfp-panel)}
|
|
6925
|
+
/* ── Recipes + prose ── */
|
|
6926
|
+
.rfp-recipes{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}
|
|
6927
|
+
.rfp-recipe{border:1px solid var(--rfp-line);border-radius:12px;overflow:hidden;background:var(--rfp-card)}
|
|
6928
|
+
.rfp-recipe-stage{min-height:92px;display:grid;place-items:center;padding:18px;background:var(--rfp-sunk)}
|
|
6929
|
+
.rfp-recipe-foot{padding:9px 12px;border-top:1px solid var(--rfp-line)}
|
|
6795
6930
|
.rfp-addr{font-family:var(--rfp-mono);font-size:11px;color:var(--rfp-ink-3);display:block}
|
|
6796
6931
|
.rfp-compose{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
|
|
6797
|
-
.rfp-cls{font-family:var(--rfp-mono);font-size:11.5px;padding:3px
|
|
6798
|
-
border:1px solid var(--rfp-
|
|
6932
|
+
.rfp-cls{font-family:var(--rfp-mono);font-size:11.5px;padding:3px 9px;border-radius:6px;
|
|
6933
|
+
border:1px solid var(--rfp-line);background:var(--rfp-sunk)}
|
|
6799
6934
|
.rfp-cls b{font-weight:600;color:var(--rfp-ink)}
|
|
6800
6935
|
.rfp-cls span{color:var(--rfp-ink-3)}
|
|
6801
6936
|
.rfp-plus{color:var(--rfp-ink-3);font-family:var(--rfp-mono)}
|
|
6802
|
-
.rfp-
|
|
6803
|
-
|
|
6937
|
+
.rfp-prose{border:1px solid var(--rfp-line);border-radius:14px;padding:26px 28px;background:var(--rfp-card);overflow:hidden}
|
|
6938
|
+
.rfp-notice{display:grid;grid-template-columns:auto minmax(0,1fr);gap:12px;padding:14px 16px;
|
|
6939
|
+
border:1px solid var(--rfp-line-2);border-radius:12px;background:var(--rfp-card);margin-top:16px}
|
|
6804
6940
|
.rfp-notice-mark{font-family:var(--rfp-mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;
|
|
6805
|
-
padding:2px
|
|
6941
|
+
padding:2px 7px;border-radius:5px;background:var(--rfp-ink);color:var(--rfp-card);white-space:nowrap;height:fit-content}
|
|
6806
6942
|
.rfp-notice p{margin:0;color:var(--rfp-ink-2);font-size:13px;max-width:68ch}
|
|
6807
6943
|
.rfp-notice p+p{margin-top:6px}
|
|
6808
|
-
.rfp-notice strong{color:var(--rfp-ink)
|
|
6944
|
+
.rfp-notice strong{color:var(--rfp-ink)}
|
|
6809
6945
|
.rfp-frame{margin:0 auto}
|
|
6810
6946
|
@media (prefers-reduced-motion:reduce){.rfp *{transition:none!important;animation:none!important}}
|
|
6811
6947
|
@media (max-width:900px){
|
|
6812
|
-
.rfp{grid-template-columns:minmax(0,1fr);gap:0;padding:0 20px 72px}
|
|
6813
|
-
.rfp-
|
|
6948
|
+
.rfp-shell{grid-template-columns:minmax(0,1fr);gap:0;padding:0 20px 72px}
|
|
6949
|
+
.rfp-masthead{padding:36px 20px 28px}
|
|
6950
|
+
.rfp-rail{position:static;max-height:none;padding:20px 0 0}
|
|
6814
6951
|
.rfp-nav{flex-direction:row;overflow-x:auto;gap:4px;padding-bottom:4px}
|
|
6815
6952
|
.rfp-nav a{white-space:nowrap}
|
|
6816
|
-
.rfp-ladder{grid-template-columns:minmax(0,1fr);gap:10px}
|
|
6817
6953
|
.rfp-row{grid-template-columns:130px minmax(0,1fr)}
|
|
6818
6954
|
.rfp-rowval{grid-column:1/-1;text-align:left}
|
|
6819
6955
|
}
|
|
@@ -6878,7 +7014,7 @@ function renderThemeLinks(stylesheets, contents, inline) {
|
|
|
6878
7014
|
// Entry point
|
|
6879
7015
|
// ---------------------------------------------------------------------------
|
|
6880
7016
|
function buildPreview(source, options) {
|
|
6881
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
7017
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
6882
7018
|
const { usage, preview, tokens, model } = source;
|
|
6883
7019
|
const fileName = (_a = options.file) !== null && _a !== void 0 ? _a : DEFAULT_FILE;
|
|
6884
7020
|
const inline = (_b = options.inline) !== null && _b !== void 0 ? _b : true;
|
|
@@ -6893,6 +7029,7 @@ function buildPreview(source, options) {
|
|
|
6893
7029
|
// entirely, so a theme without shadows shows no elevation plate rather than an empty box.
|
|
6894
7030
|
const bodies = new Map();
|
|
6895
7031
|
const counts = new Map();
|
|
7032
|
+
let pairings = { total: 0, passing: 0 };
|
|
6896
7033
|
for (const [group, items] of groups) {
|
|
6897
7034
|
const section = (_d = SECTION_OF[group]) !== null && _d !== void 0 ? _d : "other";
|
|
6898
7035
|
counts.set(section, ((_e = counts.get(section)) !== null && _e !== void 0 ? _e : 0) + items.length);
|
|
@@ -6902,8 +7039,11 @@ function buildPreview(source, options) {
|
|
|
6902
7039
|
if (!own.length)
|
|
6903
7040
|
continue;
|
|
6904
7041
|
let body = "";
|
|
6905
|
-
if (section.id === "palette")
|
|
6906
|
-
|
|
7042
|
+
if (section.id === "palette") {
|
|
7043
|
+
const palette = renderPalette(own.flatMap(([, l]) => l), model, tokenName);
|
|
7044
|
+
body = palette.html;
|
|
7045
|
+
pairings = palette.pairings;
|
|
7046
|
+
}
|
|
6907
7047
|
else if (section.id === "type")
|
|
6908
7048
|
body = renderTypography(own.flatMap(([, l]) => l), tokenName);
|
|
6909
7049
|
else if (section.id === "space")
|
|
@@ -6931,7 +7071,7 @@ function buildPreview(source, options) {
|
|
|
6931
7071
|
for (const section of SECTIONS) {
|
|
6932
7072
|
if (!bodies.has(section.id))
|
|
6933
7073
|
continue;
|
|
6934
|
-
navItems.push(`<a href="#rfp-${section.id}">${section.eyebrow}<span class="rfp-n">${(_h = counts.get(section.id)) !== null && _h !== void 0 ? _h : 0}</span></a>`);
|
|
7074
|
+
navItems.push(`<a href="#rfp-${section.id}">${esc(section.eyebrow)}<span class="rfp-n">${(_h = counts.get(section.id)) !== null && _h !== void 0 ? _h : 0}</span></a>`);
|
|
6935
7075
|
}
|
|
6936
7076
|
if (modesHtml)
|
|
6937
7077
|
navItems.push(`<a href="#rfp-modes">Appearance</a>`);
|
|
@@ -6941,16 +7081,18 @@ function buildPreview(source, options) {
|
|
|
6941
7081
|
// ── Masthead ────────────────────────────────────────────────────────────
|
|
6942
7082
|
const title = (_j = options.title) !== null && _j !== void 0 ? _j : `${usage.format} theme`;
|
|
6943
7083
|
const totalBytes = options.files.reduce((sum, f) => { var _a, _b, _c; return sum + ((_c = (_b = (_a = options.contents) === null || _a === void 0 ? void 0 : _a[f]) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0); }, 0);
|
|
6944
|
-
const
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
7084
|
+
const subsystems = Object.keys(model.subsystems).length;
|
|
7085
|
+
const elements = Object.keys((_m = (_l = (_k = model.subsystems.globals) === null || _k === void 0 ? void 0 : _k.ruleSets) === null || _l === void 0 ? void 0 : _l.elements) !== null && _m !== void 0 ? _m : {}).length;
|
|
7086
|
+
const metrics = [
|
|
7087
|
+
{ value: String(leaves.length), label: "tokens" },
|
|
7088
|
+
{ value: String(subsystems), label: "subsystems" },
|
|
7089
|
+
{ value: `${usage.recipes.length}${elements ? ` + ${elements}` : ""}`, label: elements ? "recipes + elements" : "recipes" },
|
|
7090
|
+
pairings.total ? { value: `${pairings.passing}/${pairings.total}`, label: "WCAG AA+ pairings" } : undefined,
|
|
7091
|
+
totalBytes ? { value: bytes(totalBytes), label: (_o = options.files[0]) !== null && _o !== void 0 ? _o : "output" } : undefined,
|
|
7092
|
+
].filter((m) => m !== undefined);
|
|
6951
7093
|
const modeAttribute = preview === null || preview === void 0 ? void 0 : preview.modeAttribute;
|
|
6952
7094
|
const modes = collectModes(model);
|
|
6953
|
-
const breakpoints = (
|
|
7095
|
+
const breakpoints = (_p = model.breakpoints) !== null && _p !== void 0 ? _p : {};
|
|
6954
7096
|
const controls = [];
|
|
6955
7097
|
if (modeAttribute && modes.length) {
|
|
6956
7098
|
const buttons = [`<button type="button" data-rfp-mode data-value="" aria-pressed="true">auto</button>`]
|
|
@@ -6967,11 +7109,14 @@ function buildPreview(source, options) {
|
|
|
6967
7109
|
}
|
|
6968
7110
|
// ── Sections ────────────────────────────────────────────────────────────
|
|
6969
7111
|
const sectionHtml = SECTIONS.filter(s => bodies.has(s.id))
|
|
6970
|
-
.map(s =>
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
7112
|
+
.map(s => {
|
|
7113
|
+
var _a;
|
|
7114
|
+
return `<section class="rfp-section" id="rfp-${s.id}"><div class="rfp-section-head">` +
|
|
7115
|
+
`<h2>${s.title}</h2><span class="rfp-count">${(_a = counts.get(s.id)) !== null && _a !== void 0 ? _a : 0} token(s)</span></div>` +
|
|
7116
|
+
(s.note ? `<p class="rfp-note">${s.note}</p>` : "") +
|
|
7117
|
+
bodies.get(s.id) +
|
|
7118
|
+
`</section>`;
|
|
7119
|
+
})
|
|
6975
7120
|
.join("");
|
|
6976
7121
|
const head = [
|
|
6977
7122
|
`<meta charset="utf-8">`,
|
|
@@ -6985,15 +7130,28 @@ function buildPreview(source, options) {
|
|
|
6985
7130
|
]
|
|
6986
7131
|
.filter(Boolean)
|
|
6987
7132
|
.join("\n");
|
|
7133
|
+
// The masthead is the ONE place the chrome takes a hue, and it takes the theme's own first
|
|
7134
|
+
// palette — the theme colouring itself rather than the tool asserting a brand.
|
|
7135
|
+
const brand = mastheadColor(leaves);
|
|
7136
|
+
const mastheadStyle = brand
|
|
7137
|
+
? ` style="background:${cssValue(brand.bg)};color:${cssValue(brand.fg)}"`
|
|
7138
|
+
: ` style="background:var(--rfp-ink);color:var(--rfp-card)"`;
|
|
7139
|
+
const indexHtml = renderIndex(bodies, counts, brand === null || brand === void 0 ? void 0 : brand.bg);
|
|
6988
7140
|
const body = `<div class="rfp">` +
|
|
7141
|
+
`<header class="rfp-masthead"${mastheadStyle}>` +
|
|
7142
|
+
`<p class="rfp-kicker">Theme specimen · ${esc(usage.format)} · ${esc(options.plan.type)}${live ? "" : " · tokens only"}</p>` +
|
|
7143
|
+
`<h1>${esc(title)}</h1>` +
|
|
7144
|
+
`<div class="rfp-metrics">` +
|
|
7145
|
+
metrics.map(m => `<div class="rfp-metric"><b>${esc(m.value)}</b><span>${esc(m.label)}</span></div>`).join("") +
|
|
7146
|
+
`</div></header>` +
|
|
7147
|
+
`<div class="rfp-shell">` +
|
|
6989
7148
|
`<aside class="rfp-rail"><div class="rfp-brand">refract preview</div>` +
|
|
6990
7149
|
`<nav class="rfp-nav">${navItems.join("")}</nav></aside>` +
|
|
6991
7150
|
`<main class="rfp-main">` +
|
|
6992
|
-
`<header class="rfp-masthead"><div class="rfp-eyebrow">Theme specimen</div>` +
|
|
6993
|
-
`<h1>${esc(title)}</h1><div class="rfp-meta">${metaBits.join("")}</div></header>` +
|
|
6994
7151
|
(controls.length ? `<div class="rfp-controls">${controls.join("")}</div>` : "") +
|
|
6995
7152
|
notes.map(n => `<p class="rfp-note">${esc(n)}</p>`).join("") +
|
|
6996
7153
|
`<div class="rfp-frame" id="rfp-frame">` +
|
|
7154
|
+
indexHtml +
|
|
6997
7155
|
sectionHtml +
|
|
6998
7156
|
modesHtml +
|
|
6999
7157
|
globalsHtml +
|
|
@@ -7002,7 +7160,7 @@ function buildPreview(source, options) {
|
|
|
7002
7160
|
`<span class="rfp-tag">${live ? "rendered live" : "names only"}</span></div>` +
|
|
7003
7161
|
renderRecipes(usage, preview, live) +
|
|
7004
7162
|
`</section>` +
|
|
7005
|
-
`</div></main></div>` +
|
|
7163
|
+
`</div></main></div></div>` +
|
|
7006
7164
|
`<script>\n${CHROME_JS}\n</script>`;
|
|
7007
7165
|
const html = `<!doctype html>\n<html lang="en"${modeAttribute ? ` data-rfp-mode-attr="${esc(modeAttribute)}"` : ""}>\n` +
|
|
7008
7166
|
`<head>\n${head}\n</head>\n<body>\n${body}\n</body>\n</html>\n`;
|