From 77b2ca8f10640955780b5b1da7cbc0e90f3d3865 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 27 Jul 2026 07:25:07 +0000
Subject: [PATCH 1/2] refactor: split build-docs.js into lib modules for easier
review
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
scripts/build-docs.js | 1786 +---------------------------------
scripts/lib/docs-css.js | 1231 +++++++++++++++++++++++
scripts/lib/marked-setup.js | 135 +++
scripts/lib/page-template.js | 261 +++++
scripts/lib/utils.js | 66 ++
scripts/lib/workshop.js | 154 +++
6 files changed, 1858 insertions(+), 1775 deletions(-)
create mode 100644 scripts/lib/docs-css.js
create mode 100644 scripts/lib/marked-setup.js
create mode 100644 scripts/lib/page-template.js
create mode 100644 scripts/lib/utils.js
create mode 100644 scripts/lib/workshop.js
diff --git a/scripts/build-docs.js b/scripts/build-docs.js
index af2ce9df..c8be457b 100644
--- a/scripts/build-docs.js
+++ b/scripts/build-docs.js
@@ -3,312 +3,21 @@
const fs = require('fs');
const path = require('path');
-const { marked } = require('marked');
-const { default: GithubSlugger } = require('github-slugger');
-const markedAlert = require('marked-alert');
-const { markedHighlight } = require('marked-highlight');
-const hljs = require('highlight.js');
-const defaultRenderer = new marked.Renderer();
-const relAttrRegex = /\brel=(["'])(.*?)\1/i;
+const { setupBasePlugins } = require('./lib/marked-setup');
+const { buildWorkshopContent, workshopDir, workshopImagesDir } = require('./lib/workshop');
+const { generateAlertsCss, generateHljsCss, generateDocsCss } = require('./lib/docs-css');
+const { generatePage } = require('./lib/page-template');
-// Prefix every selector in a flat (non-nested) CSS string with the given string.
-// Used to scope highlight.js dark-theme rules under dark-mode selectors.
-function prefixCssSelectors(css, prefix) {
- const stripped = css.replace(/\/\*[\s\S]*?\*\//g, '');
- return stripped.replace(/([^{}]+)\{([^{}]*)\}/g, (_, selectors, props) => {
- const prefixed = selectors.trim().split(',').map(s => `${prefix} ${s.trim()}`).join(', ');
- return `${prefixed} { ${props.trim()} }\n`;
- });
-}
-
-function flattenTokenText(tokenOrTokens) {
- if (Array.isArray(tokenOrTokens)) {
- return tokenOrTokens.map(flattenTokenText).join('');
- }
- if (!tokenOrTokens) return '';
- return tokenOrTokens.tokens
- ? flattenTokenText(tokenOrTokens.tokens)
- : (tokenOrTokens.text || tokenOrTokens.raw || '');
-}
-
-function escapeHtml(value) {
- return String(value)
- .replaceAll('&', '&')
- .replaceAll('"', '"')
- .replaceAll('<', '<')
- .replaceAll('>', '>')
- .replaceAll('\'', ''');
-}
-
-function isExternalWebLink(href) {
- return /^https?:\/\//i.test(href);
-}
-
-function addExternalLinkTargetAttrs(anchorHtml) {
- return anchorHtml.replace(/^]*)>/i, (match, attrs) => {
- let updatedAttrs = attrs;
-
- if (!/\btarget\s*=/.test(updatedAttrs)) {
- updatedAttrs += ' target="_blank"';
- }
-
- const relMatch = updatedAttrs.match(relAttrRegex);
- if (relMatch) {
- const relValues = new Set(relMatch[2].split(/\s+/).filter(Boolean));
- relValues.add('noopener');
- relValues.add('noreferrer');
- updatedAttrs = updatedAttrs.replace(relAttrRegex, `rel="${[...relValues].join(' ')}"`);
- } else {
- updatedAttrs += ' rel="noopener noreferrer"';
- }
-
- return ``;
- });
-}
-
-// Plugin: clickable heading anchors with GitHub-compatible IDs
-const slugger = new GithubSlugger();
-marked.use({
- // Reset the slugger before each marked() call to avoid duplicate-ID drift
- hooks: {
- preprocess(src) { slugger.reset(); return src; },
- },
- useNewRenderer: true,
- renderer: {
- heading({ tokens, depth }) {
- const text = this.parser.parseInline(tokens);
- // Extract plain text from tokens (avoids regex-based HTML stripping)
- const raw = flattenTokenText(tokens).trim();
- // slugger.slug() always returns a URL-safe [a-z0-9-] string, safe for attribute interpolation
- const id = slugger.slug(raw);
- // text is the HTML output of parseInline(), which escapes user content
- return `${text} #\n`;
- },
- // Plugin: render GFM task list items with GitHub-compatible CSS classes
- listitem(item) {
- if (item.task) {
- // Extract inline tokens after the checkbox token. In tight lists the
- // item tokens are [checkbox, ...inline]; in loose lists they are
- // [paragraph{ tokens: [checkbox, ...inline] }, ...].
- const inlineTokens = item.loose && item.tokens[0]?.tokens
- ? item.tokens[0].tokens.slice(1)
- : item.tokens.slice(1);
- const text = this.parser.parseInline(inlineTokens);
- const accessibleName = flattenTokenText(inlineTokens).replace(/\s+/g, ' ').trim();
- const status = item.checked ? 'completed' : 'pending';
- const markerClass = item.checked
- ? 'task-list-item-marker is-complete'
- : 'task-list-item-marker is-pending';
- const labelAttr = accessibleName
- ? ` aria-label="Checkpoint item (${status}): ${escapeHtml(accessibleName)}"`
- : ` aria-label="Checkpoint item (${status})"`;
- const markerSymbol = item.checked ? '●' : '○';
- return `${markerSymbol} ${text}\n`;
- }
- return false; // use default rendering for non-task items
- },
- },
-});
-
-// Plugin: render GitHub GFM alert callouts (> [!NOTE], > [!TIP], etc.)
-marked.use(markedAlert());
-
-// Plugin: syntax-highlight fenced code blocks at build time using highlight.js
-marked.use(markedHighlight({
- langPrefix: 'hljs language-',
- highlight(code, lang) {
- const language = hljs.getLanguage(lang) ? lang : 'plaintext';
- return hljs.highlight(code, { language }).value;
- },
-}));
-// Plugin: render shell, terminal output, and agent prompt code blocks with distinct UI wrappers
-const shellLangs = new Set(['bash', 'sh', 'shell', 'zsh']);
-const terminalOutputLangs = new Set(['console', 'output', 'plaintext', 'text']);
-marked.use({
- useNewRenderer: true,
- renderer: {
- code({ text, lang, escaped }) {
- const langKey = (lang || '').match(/^\S*/)?.[0]?.toLowerCase() ?? '';
- const codeText = text.replace(/\n$/, '') + '\n';
- const codeHtml = escaped ? codeText : escapeHtml(codeText);
- if (langKey === 'prompt') {
- return `\n
✦Agent prompt
\n
${codeHtml}
\n
\n`;
- }
- if (langKey === 'markdown' || langKey === 'md') {
- return `\n`;
- }
- if (langKey === 'yaml' || langKey === 'yml') {
- return `\n`;
- }
- const terminalLabel = shellLangs.has(langKey) ? langKey : terminalOutputLangs.has(langKey) ? 'output' : '';
- if (!terminalLabel) return false;
- const escapedLang = escapeHtml(langKey);
- return `\n
${terminalLabel}
\n
${codeHtml}
\n
\n`;
- },
- },
-});
-
-const workshopDir = path.join(__dirname, '..', 'workshop');
const distDir = path.join(__dirname, '..', 'dist');
-const workshopImagesDir = path.join(workshopDir, 'images');
const distImagesDir = path.join(distDir, 'images');
const monaSansDir = path.join(
__dirname, '..', 'node_modules', '@fontsource-variable', 'mona-sans'
);
const distFontsDir = path.join(distDir, 'fonts');
-const headingRegex = /^#{1,6}\s+(.+)$/m;
-
-// Collect and sort workshop markdown files (excludes non-md files; keeps README)
-const files = fs.readdirSync(workshopDir)
- .filter(f => f.endsWith('.md'))
- .sort();
-
-const sectionIdsByFile = new Map(
- files.map(f => [f, path.basename(f, '.md')])
-);
-
-const markdownByFile = new Map(
- files.map(f => [f, fs.readFileSync(path.join(workshopDir, f), 'utf8').trim()])
-);
-const pageTitleByFile = new Map(
- [...markdownByFile].map(([f, markdown]) => {
- const headingMatch = markdown.match(headingRegex);
- const slug = path.basename(f, '.md').replace(/^\d+-?/, '').replace(/-/g, ' ');
- const title = headingMatch
- ? headingMatch[1].trim()
- : slug.charAt(0).toUpperCase() + slug.slice(1);
- return [f, title];
- })
-);
-const adventureByFile = new Map(
- [...markdownByFile].map(([f, markdown]) => {
- const adventureMatch = markdown.match(/^/m);
- return [f, adventureMatch?.[1] ?? 'other'];
- })
-);
-const nextLinkRegex = /\*\*Next:\*\*\s*(?:Open\s+)?\[([^\]]+)\]\(([^)#?]+\.md)(?:#[^)]*)?\)\.?/g;
-const previousFileByFile = new Map();
-
-for (const [sourceFile, markdown] of markdownByFile) {
- for (const match of markdown.matchAll(nextLinkRegex)) {
- const targetFile = match[2];
- if (sectionIdsByFile.has(targetFile) && !previousFileByFile.has(targetFile)) {
- previousFileByFile.set(targetFile, sourceFile);
- }
- }
-}
-
-function renderWorkshopNavigation(markdown, currentFile) {
- const previousFile = previousFileByFile.get(currentFile);
- const previousSectionId = previousFile ? sectionIdsByFile.get(previousFile) : null;
- const previousLabel = previousFile ? marked.parseInline(pageTitleByFile.get(previousFile)) : '';
-
- // Collect all valid next links from this page up front so we can render them
- // together in a single nav block (one previous, one or more next buttons).
- const nextButtons = [];
- for (const match of markdown.matchAll(nextLinkRegex)) {
- const nextFile = match[2];
- const nextSectionId = sectionIdsByFile.get(nextFile);
- if (nextSectionId) {
- nextButtons.push(
- `${marked.parseInline(match[1])} →`
- );
- }
- }
-
- if (nextButtons.length === 0) return markdown;
-
- const previousDiv = previousSectionId
- ? `
`
- : '';
-
- const navHtml = ``;
-
- // Replace the first known next-link match with the full nav; remove the rest.
- let navInserted = false;
- return markdown.replace(nextLinkRegex, (_match, _label, nextFile) => {
- const sectionId = sectionIdsByFile.get(nextFile);
- if (!sectionId) return _match; // preserve links to unknown pages unchanged
- if (!navInserted) {
- navInserted = true;
- return navHtml;
- }
- return ''; // subsequent next-link occurrences are folded into the single nav
- });
-}
-marked.use({
- useNewRenderer: true,
- renderer: {
- link(link) {
- const { href } = link;
- if (href) {
- const markdownPageLink = href.match(/^(?[^/?#]+\.md)(?#[^?]+)?$/);
- if (markdownPageLink) {
- const targetFile = markdownPageLink.groups?.file;
- const targetHash = markdownPageLink.groups?.hash;
- const targetSectionId = sectionIdsByFile.get(targetFile);
- if (targetSectionId) {
- const rewrittenHref = targetHash ?? `#${targetSectionId}`;
- return defaultRenderer.link.call(this, { ...link, href: rewrittenHref });
- }
- }
-
- if (isExternalWebLink(href)) {
- return addExternalLinkTargetAttrs(defaultRenderer.link.call(this, link));
- }
- }
- return false;
- },
- },
-});
-
-// Render each file as a closed section with the first heading as
-const htmlContent = files.map((f, index) => {
- const markdown = markdownByFile.get(f);
- // Extract plain text of the first heading (strip leading # characters).
- // Workshop files use HTML comments (not YAML frontmatter), so the multiline
- // regex safely finds the first heading regardless of leading comment lines.
- const headingMatch = markdown.match(headingRegex);
- const title = pageTitleByFile.get(f);
- const titleHtml = escapeHtml(title);
- const sectionId = sectionIdsByFile.get(f);
- const sectionTitleId = `${sectionId}-title`;
- // Intentionally remove only the first heading because it is promoted to .
- const markdownWithoutTitle = headingMatch ? markdown.replace(headingRegex, '').trimStart() : markdown;
- const content = marked(renderWorkshopNavigation(markdownWithoutTitle, f));
- const detailsOpenAttr = index === 0 ? ' open' : '';
- return `\n${titleHtml}
\n${titleHtml}
\n${content}\n `;
-}).join('\n\n');
-
-const menuGroups = [
- ['core', 'Main workshop'],
- ['setup', 'Setup paths'],
- ['advanced', 'Advanced topics'],
- ['side-quest', 'Side quests'],
- ['other', 'Other pages'],
-];
-const workshopMenu = menuGroups.map(([adventure, label]) => {
- const links = files
- .filter(f => adventureByFile.get(f) === adventure)
- .map(f => {
- const sectionId = sectionIdsByFile.get(f);
- const title = marked.parseInline(pageTitleByFile.get(f));
- return `${title}`;
- })
- .join('\n');
-
- if (!links) return '';
- return ``;
-}).join('\n');
+// Set up marked plugins, then build all workshop content.
+setupBasePlugins();
+const { files, htmlContent, workshopMenu } = buildWorkshopContent();
// Set up output directory
fs.mkdirSync(distDir, { recursive: true });
@@ -357,1226 +66,9 @@ for (const subset of ['vietnamese', 'latin-ext', 'latin']) {
}
}
-// Generate alert callout CSS for marked-alert GFM rendering
-const alertsCss = `/* Alert callout styles for GitHub GFM > [!NOTE] / [!TIP] / etc. */
-.markdown-alert {
- padding: 0.5rem 1rem;
- margin-bottom: 16px;
- border-left: 0.25em solid;
- border-radius: 6px;
-}
-.markdown-alert > :first-child { margin-top: 0; }
-.markdown-alert > :last-child { margin-bottom: 0; }
-.markdown-alert-title {
- display: flex;
- align-items: center;
- font-weight: 600;
- margin-bottom: 4px;
-}
-.markdown-alert-title svg { margin-right: 8px; }
-.markdown-alert-note {
- border-color: var(--borderColor-accent-emphasis, #0969da);
- background-color: var(--bgColor-accent-muted, #ddf4ff);
-}
-.markdown-alert-note .markdown-alert-title { color: var(--fgColor-accent, #0969da); }
-.markdown-alert-tip {
- border-color: var(--borderColor-success-emphasis, #1a7f37);
- background-color: var(--bgColor-success-muted, #dafbe1);
-}
-.markdown-alert-tip .markdown-alert-title { color: var(--fgColor-success, #1a7f37); }
-.markdown-alert-important {
- border-color: var(--borderColor-done-emphasis, #8250df);
- background-color: var(--bgColor-done-muted, #fbefff);
-}
-.markdown-alert-important .markdown-alert-title { color: var(--fgColor-done, #8250df); }
-.markdown-alert-warning {
- border-color: var(--borderColor-attention-emphasis, #9a6700);
- background-color: var(--bgColor-attention-muted, #fff8c5);
-}
-.markdown-alert-warning .markdown-alert-title { color: var(--fgColor-attention, #9a6700); }
-.markdown-alert-caution {
- border-color: var(--borderColor-danger-emphasis, #d1242f);
- background-color: var(--bgColor-danger-muted, #ffebe9);
-}
-.markdown-alert-caution .markdown-alert-title { color: var(--fgColor-danger, #d1242f); }
-`;
-fs.writeFileSync(path.join(distDir, 'alerts.css'), alertsCss);
-
-// Generate highlight.js syntax highlighting CSS (GitHub light + dark themes)
-// The dark theme rules are scoped to the data-color-mode="dark" attribute and
-// to the prefers-color-scheme: dark media query for data-color-mode="auto".
-const hljsStylesDir = path.join(__dirname, '..', 'node_modules', 'highlight.js', 'styles');
-const hljsLightCss = fs.readFileSync(path.join(hljsStylesDir, 'github.min.css'), 'utf8');
-const hljsDarkCss = fs.readFileSync(path.join(hljsStylesDir, 'github-dark.min.css'), 'utf8');
-const hljsCss = [
- '/* highlight.js – GitHub light theme (default) */',
- hljsLightCss,
- '',
- '/* highlight.js – GitHub Dark theme (terminal blocks) */',
- prefixCssSelectors(hljsDarkCss, '.terminal-block'),
- '',
- '/* highlight.js – GitHub Dark theme (explicit dark mode) */',
- prefixCssSelectors(hljsDarkCss, 'html[data-color-mode="dark"]'),
- '',
- '/* highlight.js – GitHub Dark theme (system dark preference) */',
- '@media (prefers-color-scheme: dark) {',
- prefixCssSelectors(hljsDarkCss, 'html[data-color-mode="auto"]'),
- '}',
-].join('\n');
-fs.writeFileSync(path.join(distDir, 'hljs.css'), hljsCss);
-
-// Generate docs CSS – link discoverability + reveal.js scrollable slides
-const docsCss = `/* Improve link discoverability in rendered workshop docs */
-:root {
- --workshop-sticky-header-offset: 72px;
- --workshop-link-color: var(--fgColor-accent, #0969da);
- --workshop-link-visited-color: var(--fgColor-done, #8250df);
- --workshop-link-hover-color: var(--fgColor-accent, #0550ae);
-}
-
-@media (prefers-color-scheme: dark) {
- html[data-color-mode="auto"] {
- --workshop-link-color: var(--fgColor-accent, #58a6ff);
- --workshop-link-visited-color: var(--fgColor-done, #bc8cff);
- --workshop-link-hover-color: var(--fgColor-accent, #79c0ff);
- }
-}
-
-html[data-color-mode="dark"] {
- --workshop-link-color: var(--fgColor-accent, #58a6ff);
- --workshop-link-visited-color: var(--fgColor-done, #bc8cff);
- --workshop-link-hover-color: var(--fgColor-accent, #79c0ff);
-}
-
-body,
-.markdown-body {
- font-family: 'Mona Sans Variable', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
-}
-
-html {
- scroll-padding-top: var(--workshop-sticky-header-offset);
-}
-
-.site-header {
- position: sticky;
- z-index: 10;
- top: 0;
- display: flex;
- gap: 12px;
- align-items: center;
- min-height: 56px;
- padding: 0 16px;
- color: var(--fgColor-default, #1f2328);
- background-color: var(--bgColor-default, #ffffff);
- border-bottom: 1px solid var(--borderColor-muted, #d0d7de);
-}
-.site-title {
- margin: 0;
- font-size: 16px;
- font-weight: 600;
-}
-.site-title a {
- color: inherit;
- text-decoration: none;
-}
-.site-title a:hover {
- color: var(--workshop-link-hover-color);
-}
-.menu-toggle,
-.menu-close {
- display: inline-grid;
- flex: 0 0 auto;
- place-items: center;
- width: 36px;
- height: 36px;
- padding: 0;
- color: var(--fgColor-default, #1f2328);
- background: transparent;
- border: 1px solid transparent;
- border-radius: 6px;
- cursor: pointer;
-}
-.menu-toggle:hover,
-.menu-close:hover {
- background-color: var(--bgColor-muted, #f6f8fa);
-}
-.menu-toggle:focus-visible,
-.menu-close:focus-visible {
- outline: 2px solid var(--fgColor-accent, #0969da);
- outline-offset: -2px;
-}
-.menu-icon,
-.menu-icon::before,
-.menu-icon::after {
- width: 18px;
- height: 2px;
- background-color: currentColor;
- border-radius: 1px;
-}
-.menu-icon {
- position: relative;
-}
-.menu-icon::before,
-.menu-icon::after {
- position: absolute;
- left: 0;
- content: '';
-}
-.menu-icon::before { top: -6px; }
-.menu-icon::after { top: 6px; }
-
-.workshop-menu {
- width: min(384px, calc(100vw - 32px));
- max-width: none;
- height: 100dvh;
- max-height: none;
- margin: 0;
- padding: 0;
- color: var(--fgColor-default, #1f2328);
- background-color: var(--bgColor-default, #ffffff);
- border: 0;
- border-right: 1px solid var(--borderColor-muted, #d0d7de);
-}
-.workshop-menu::backdrop {
- background: rgba(0, 0, 0, 0.48);
-}
-.workshop-menu-panel {
- display: flex;
- flex-direction: column;
- height: 100%;
-}
-.workshop-menu-header {
- display: flex;
- flex: 0 0 auto;
- align-items: center;
- justify-content: space-between;
- min-height: 56px;
- padding: 0 12px 0 20px;
- border-bottom: 1px solid var(--borderColor-muted, #d0d7de);
-}
-.workshop-menu-header h2 {
- margin: 0;
- font-size: 16px;
-}
-.menu-close {
- font-size: 26px;
- font-weight: 300;
- line-height: 1;
-}
-.workshop-menu-nav {
- flex: 1 1 auto;
- padding: 12px;
- overflow-y: auto;
- overscroll-behavior: contain;
-}
-.workshop-menu-group + .workshop-menu-group {
- margin-top: 20px;
-}
-.workshop-menu-group h3 {
- margin: 0 8px 6px;
- color: var(--fgColor-muted, #59636e);
- font-size: 12px;
- font-weight: 600;
- letter-spacing: 0;
- text-transform: uppercase;
-}
-.workshop-menu-group ul {
- margin: 0;
- padding: 0;
- list-style: none;
-}
-.workshop-menu-group a {
- display: block;
- padding: 8px;
- color: var(--fgColor-default, #1f2328);
- line-height: 1.35;
- text-decoration: none;
- border-radius: 6px;
-}
-.workshop-menu-group a:hover {
- color: var(--workshop-link-hover-color);
- background-color: var(--bgColor-muted, #f6f8fa);
-}
-.workshop-menu-group a[aria-current="page"] {
- color: var(--workshop-link-color);
- font-weight: 600;
- background-color: var(--bgColor-accent-muted, #ddf4ff);
-}
-
-.markdown-body > details:not([open]) {
- display: none;
-}
-.markdown-body > details {
- scroll-margin-top: var(--workshop-sticky-header-offset);
-}
-.markdown-body > details > summary {
- display: none;
-}
-.markdown-body > details > .workshop-page-title {
- margin: 0;
- font-size: 32px;
- line-height: 1.25;
- scroll-margin-top: var(--workshop-sticky-header-offset);
-}
-
-.markdown-body {
- max-width: 650px;
- margin-inline: auto;
-}
-.markdown-body li.task-list-item {
- list-style: none;
-}
-.markdown-body li.task-list-item > .task-list-item-marker {
- display: inline-block;
- width: 1.2em;
- font-weight: 700;
- color: var(--fgColor-success, #1a7f37);
-}
-.markdown-body li.task-list-item > .task-list-item-marker.is-pending {
- color: var(--fgColor-default, #1f2328);
- font-weight: 400;
-}
-
-@media (max-width: 543px) {
- .markdown-body > details > .workshop-page-title {
- font-size: 28px;
- }
- .markdown-body pre {
- white-space: pre-wrap;
- overflow-wrap: anywhere;
- }
- .markdown-body pre > code {
- white-space: inherit;
- }
- .markdown-body {
- padding-inline: 12px !important;
- }
-}
-
-/* Responsive images: full-width on mobile, capped on larger screens — no media query needed */
-.markdown-body img {
- display: block;
- width: min(100%, 720px);
- height: auto;
- margin-inline: auto;
- border-radius: 6px;
-}
-
-.markdown-body img[data-image-inspector-ready] {
- cursor: zoom-in;
-}
-
-.markdown-body img[data-image-inspector-ready]:focus-visible {
- outline: 2px solid var(--fgColor-accent, #0969da);
- outline-offset: 4px;
-}
-
-.image-inspector {
- width: min(96vw, 1200px);
- max-width: none;
- max-height: 96vh;
- padding: 0;
- color: var(--fgColor-default, #1f2328);
- background: transparent;
- border: 0;
-}
-
-.image-inspector::backdrop {
- background: rgba(13, 17, 23, 0.82);
- backdrop-filter: blur(4px);
-}
-
-.image-inspector-panel {
- position: relative;
- display: grid;
- gap: 12px;
- justify-items: center;
- max-height: 96vh;
- padding: 16px 16px 20px;
- background: var(--bgColor-default, #ffffff);
- border: 1px solid var(--borderColor-muted, #d0d7de);
- border-radius: 20px;
- box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
-}
-
-.image-inspector-close {
- position: absolute;
- top: 12px;
- right: 12px;
- display: inline-grid;
- place-items: center;
- min-width: 32px;
- height: 32px;
- padding: 0 12px;
- color: var(--button-default-fgColor-rest, #1f2328);
- font-family: inherit;
- font-size: 14px;
- font-weight: 500;
- line-height: 20px;
- white-space: nowrap;
- background-color: var(--button-default-bgColor-rest, #f6f8fa);
- border: 1px solid var(--button-default-borderColor-rest, rgba(31, 35, 40, 0.15));
- border-radius: 6px;
- box-shadow: var(--shadow-resting-small, 0 1px 0 rgba(31, 35, 40, 0.04));
- cursor: pointer;
- transition: background-color 0.1s, border-color 0.1s;
-}
-
-.image-inspector-close:hover {
- background-color: var(--button-default-bgColor-hover, #f3f4f6);
- border-color: var(--button-default-borderColor-hover, rgba(31, 35, 40, 0.15));
-}
-
-.image-inspector-close:focus-visible {
- outline: 2px solid var(--fgColor-accent, #0969da);
- outline-offset: 2px;
-}
-
-.image-inspector-figure {
- display: grid;
- gap: 12px;
- margin: 0;
-}
-
-.image-inspector-image {
- display: block;
- max-width: min(88vw, 1120px);
- max-height: calc(96vh - 96px);
- width: auto;
- height: auto;
- margin: 0 auto;
- border-radius: 6px;
-}
-
-.image-inspector-caption {
- max-width: min(88vw, 1120px);
- margin: 0;
- color: var(--fgColor-muted, #59636e);
- text-align: center;
-}
-
-.markdown-body .anchor {
- display: none;
-}
-
-.markdown-body .anchor:focus-visible {
- display: inline;
- outline: 2px solid var(--fgColor-accent, #0969da);
- outline-offset: 2px;
- border-radius: 2px;
-}
-
-.markdown-body a:not(.anchor):not(.workshop-nav-btn),
-.workshop-navigation a:not(.anchor):not(.workshop-nav-btn) {
- color: var(--workshop-link-color);
- text-decoration: underline;
- text-underline-offset: 0.08em;
-}
-
-.markdown-body a:not(.anchor):not(.workshop-nav-btn):visited,
-.workshop-navigation a:not(.anchor):not(.workshop-nav-btn):visited {
- color: var(--workshop-link-visited-color);
-}
-
-.markdown-body a:not(.anchor):not(.workshop-nav-btn):hover,
-.markdown-body a:not(.anchor):not(.workshop-nav-btn):focus-visible,
-.workshop-navigation a:not(.anchor):not(.workshop-nav-btn):hover,
-.workshop-navigation a:not(.anchor):not(.workshop-nav-btn):focus-visible {
- color: var(--workshop-link-hover-color);
-}
-
-.workshop-navigation {
- display: flex;
- align-items: flex-start;
- gap: 16px;
- margin-top: 32px;
- padding-top: 16px;
- border-top: 1px solid var(--borderColor-muted, #d0d7de);
-}
-.workshop-navigation-previous {
- flex: 0 0 auto;
- min-width: 0;
-}
-.workshop-navigation-next {
- display: flex;
- flex-direction: column;
- gap: 8px;
- align-items: flex-end;
- flex: 0 0 auto;
- min-width: 0;
- margin-left: auto;
-}
-.workshop-nav-btn {
- display: inline-flex;
- gap: 0.4em;
- align-items: center;
- padding: 8px 16px;
- font-size: 14px;
- font-weight: 600;
- line-height: 1.4;
- border-radius: 6px;
- text-decoration: none;
- cursor: pointer;
-}
-.workshop-nav-btn:hover,
-.workshop-nav-btn:focus-visible {
- text-decoration: none;
-}
-.workshop-nav-btn-primary {
- color: #ffffff;
- background-color: var(--bgColor-accent-emphasis, #0969da);
- border: 1px solid transparent;
-}
-.workshop-nav-btn-primary:hover,
-.workshop-nav-btn-primary:focus-visible {
- color: #ffffff;
- background-color: var(--bgColor-accent-emphasis, #0550ae);
- filter: brightness(0.9);
-}
-.workshop-nav-btn-secondary {
- color: var(--fgColor-default, #1f2328);
- background-color: var(--bgColor-muted, #f6f8fa);
- border: 1px solid var(--borderColor-default, #d0d7de);
-}
-.workshop-nav-btn-secondary:hover,
-.workshop-nav-btn-secondary:focus-visible {
- color: var(--fgColor-default, #1f2328);
- background-color: var(--bgColor-subtle, #eaeef2);
-}
-
-@media (prefers-color-scheme: dark) {
- html[data-color-mode="auto"] .workshop-nav-btn-primary {
- background-color: var(--bgColor-accent-emphasis, #1f6feb);
- color: #ffffff;
- }
- html[data-color-mode="auto"] .workshop-nav-btn-primary:hover,
- html[data-color-mode="auto"] .workshop-nav-btn-primary:focus-visible {
- background-color: var(--bgColor-accent-emphasis, #1f6feb);
- color: #ffffff;
- filter: brightness(0.9);
- }
- html[data-color-mode="auto"] .workshop-nav-btn-secondary {
- color: var(--fgColor-default, #e6edf3);
- background-color: var(--bgColor-muted, #161b22);
- border-color: var(--borderColor-default, #30363d);
- }
- html[data-color-mode="auto"] .workshop-nav-btn-secondary:hover,
- html[data-color-mode="auto"] .workshop-nav-btn-secondary:focus-visible {
- color: var(--fgColor-default, #e6edf3);
- background-color: var(--bgColor-subtle, #1c2128);
- }
-}
-
-html[data-color-mode="dark"] .workshop-nav-btn-primary {
- background-color: var(--bgColor-accent-emphasis, #1f6feb);
- color: #ffffff;
-}
-html[data-color-mode="dark"] .workshop-nav-btn-primary:hover,
-html[data-color-mode="dark"] .workshop-nav-btn-primary:focus-visible {
- background-color: var(--bgColor-accent-emphasis, #1f6feb);
- color: #ffffff;
- filter: brightness(0.9);
-}
-html[data-color-mode="dark"] .workshop-nav-btn-secondary {
- color: var(--fgColor-default, #e6edf3);
- background-color: var(--bgColor-muted, #161b22);
- border-color: var(--borderColor-default, #30363d);
-}
-html[data-color-mode="dark"] .workshop-nav-btn-secondary:hover,
-html[data-color-mode="dark"] .workshop-nav-btn-secondary:focus-visible {
- color: var(--fgColor-default, #e6edf3);
- background-color: var(--bgColor-subtle, #1c2128);
-}
-
-@media (max-width: 799px) {
- .workshop-navigation {
- flex-wrap: wrap;
- gap: 8px;
- }
- .workshop-navigation-previous,
- .workshop-navigation-next {
- align-items: stretch;
- width: 100%;
- }
- .workshop-nav-btn {
- box-sizing: border-box;
- max-width: 100%;
- width: 100%;
- overflow-wrap: anywhere;
- white-space: normal;
- align-items: flex-start;
- }
-}
-
-.workshop-menu-footer {
- flex: 0 0 auto;
- padding: 12px 20px;
- border-top: 1px solid var(--borderColor-muted, #d0d7de);
-}
-.workshop-menu-controls {
- display: flex;
- flex-direction: column;
- gap: 8px;
-}
-.workshop-theme-chooser {
- display: flex;
- border: 1px solid var(--borderColor-default, #d0d7de);
- border-radius: 6px;
- overflow: hidden;
-}
-.workshop-theme-btn {
- flex: 1;
- padding: 6px 4px;
- font-size: 12px;
- font-weight: 500;
- font-family: inherit;
- color: var(--fgColor-muted, #59636e);
- background: transparent;
- border: 0;
- border-right: 1px solid var(--borderColor-default, #d0d7de);
- cursor: pointer;
-}
-.workshop-theme-btn:last-child {
- border-right: 0;
-}
-.workshop-theme-btn:hover {
- background-color: var(--bgColor-muted, #f6f8fa);
- color: var(--fgColor-default, #1f2328);
-}
-.workshop-theme-btn:focus-visible {
- outline: 2px solid var(--fgColor-accent, #0969da);
- outline-offset: -2px;
-}
-.workshop-theme-btn[aria-pressed="true"] {
- background-color: var(--bgColor-accent-muted, #ddf4ff);
- color: var(--fgColor-accent, #0969da);
- font-weight: 600;
-}
-.workshop-progress-reset-btn {
- width: 100%;
- padding: 6px 10px;
- font-size: 12px;
- font-weight: 500;
- font-family: inherit;
- line-height: 1.4;
- color: var(--fgColor-muted, #59636e);
- background-color: transparent;
- border: 1px solid var(--borderColor-default, #d0d7de);
- border-radius: 6px;
- cursor: pointer;
-}
-.workshop-progress-reset-btn:hover {
- background-color: var(--bgColor-muted, #f6f8fa);
- color: var(--fgColor-default, #1f2328);
-}
-.workshop-progress-reset-btn:focus-visible {
- outline: 2px solid var(--fgColor-accent, #0969da);
- outline-offset: 2px;
-}
-
-/* Code block copy button */
-.markdown-body pre {
- position: relative;
-}
-.code-copy-btn {
- position: absolute;
- top: 8px;
- right: 8px;
- padding: 4px 8px;
- font-size: 12px;
- font-weight: 500;
- font-family: inherit;
- line-height: 1.4;
- color: var(--fgColor-muted, #59636e);
- background-color: var(--bgColor-default, #ffffff);
- border: 1px solid var(--borderColor-muted, #d0d7de);
- border-radius: 6px;
- cursor: pointer;
- opacity: 0;
- transition: opacity 0.15s, background-color 0.1s, color 0.1s, border-color 0.1s;
-}
-.markdown-body pre:hover .code-copy-btn,
-.code-copy-btn:focus-visible {
- opacity: 1;
-}
-.code-copy-btn:hover {
- background-color: var(--bgColor-muted, #f6f8fa);
- color: var(--fgColor-default, #1f2328);
-}
-.code-copy-btn--copied {
- color: var(--fgColor-success, #1a7f37);
- background-color: var(--bgColor-success-muted, #dafbe1);
- border-color: var(--borderColor-success-emphasis, #1a7f37);
- opacity: 1;
-}
-
-@media (prefers-color-scheme: dark) {
- html[data-color-mode="auto"] .code-copy-btn {
- background-color: var(--bgColor-default, #0d1117);
- }
- html[data-color-mode="auto"] .code-copy-btn:hover {
- background-color: var(--bgColor-muted, #161b22);
- color: var(--fgColor-default, #e6edf3);
- }
-}
-
-html[data-color-mode="dark"] .code-copy-btn {
- background-color: var(--bgColor-default, #0d1117);
-}
-html[data-color-mode="dark"] .code-copy-btn:hover {
- background-color: var(--bgColor-muted, #161b22);
- color: var(--fgColor-default, #e6edf3);
-}
-
-/* Terminal-style shell code blocks (bash / sh / shell / zsh) */
-.terminal-block {
- border-radius: 8px;
- overflow: hidden;
- border: 1px solid #30363d;
- margin-bottom: 16px;
-}
-
-.terminal-bar {
- display: flex;
- align-items: center;
- gap: 6px;
- padding: 8px 14px;
- background-color: #161b22;
- border-bottom: 1px solid #30363d;
-}
-
-.terminal-dot {
- flex-shrink: 0;
- width: 12px;
- height: 12px;
- border-radius: 50%;
-}
-
-.terminal-dot:nth-child(1) { background-color: #f78166; }
-.terminal-dot:nth-child(2) { background-color: #e3b341; }
-.terminal-dot:nth-child(3) { background-color: #3fb950; }
-
-.terminal-label {
- margin-left: 8px;
- font-size: 11px;
- color: #8b949e;
- font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
-}
-
-.markdown-body .terminal-pre {
- margin: 0;
- padding: 16px;
- background-color: #0d1117;
- border-radius: 0;
- border: none;
- overflow-x: auto;
-}
-
-.markdown-body .terminal-pre > code {
- color: #e6edf3;
- background: transparent;
- padding: 0;
- border-radius: 0;
- font-size: 0.875em;
-}
-
-/* Copy button inside terminal blocks — always use dark-theme colours */
-.terminal-block .code-copy-btn {
- background-color: #161b22;
- border-color: #30363d;
- color: #8b949e;
-}
-
-.terminal-block .code-copy-btn:hover {
- background-color: #1c2128;
- color: #e6edf3;
-}
-
-/* Agent prompt blocks */
-.agent-prompt-block {
- border-radius: 8px;
- overflow: hidden;
- border: 1px solid #8957e5;
- margin-bottom: 16px;
- box-shadow: 0 0 0 1px rgb(163 113 247 / 10%), 0 8px 24px rgb(27 12 54 / 18%);
-}
-
-.agent-prompt-bar {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 8px 14px;
- background: linear-gradient(90deg, #271052, #3b1b6f);
- border-bottom: 1px solid #8957e5;
-}
-
-.agent-prompt-icon {
- display: grid;
- flex-shrink: 0;
- place-items: center;
- width: 22px;
- height: 22px;
- border-radius: 6px;
- color: #f0e7ff;
- background-color: #6e40c9;
- font-size: 14px;
- line-height: 1;
-}
-
-.agent-prompt-label {
- color: #f0e7ff;
- font-size: 12px;
- font-weight: 600;
- letter-spacing: 0.02em;
-}
-
-.markdown-body .agent-prompt-pre {
- margin: 0;
- padding: 16px 16px 16px 20px;
- background-color: #120b1f;
- border: none;
- border-radius: 0;
- box-shadow: inset 3px 0 #a371f7;
- overflow-x: auto;
-}
-
-.markdown-body .agent-prompt-pre > code {
- color: #f0e7ff;
- background: transparent;
- padding: 0;
- border-radius: 0;
- font-size: 0.875em;
-}
-
-.agent-prompt-block .code-copy-btn {
- color: #c6a7ff;
- background-color: #271052;
- border-color: #6e40c9;
-}
-
-.agent-prompt-block .code-copy-btn:hover {
- color: #ffffff;
- background-color: #3b1b6f;
-}
-
-/* Interactive task-list checkboxes */
-.markdown-body li.task-list-item {
- cursor: pointer;
- user-select: none;
- border-radius: 4px;
- padding-inline: 4px;
- transition: background-color 0.1s;
-}
-.markdown-body li.task-list-item:hover {
- background-color: var(--bgColor-muted, #f6f8fa);
-}
-.markdown-body li.task-list-item:focus-visible {
- outline: 2px solid var(--fgColor-accent, #0969da);
- outline-offset: 2px;
- border-radius: 4px;
-}
-
-@media (prefers-color-scheme: dark) {
- html[data-color-mode="auto"] .markdown-body li.task-list-item:hover {
- background-color: var(--bgColor-muted, #161b22);
- }
-}
-html[data-color-mode="dark"] .markdown-body li.task-list-item:hover {
- background-color: var(--bgColor-muted, #161b22);
-}
-
-/* Task progress bar */
-.task-progress {
- display: flex;
- align-items: center;
- gap: 10px;
- margin: 10px 0 18px;
- font-size: 13px;
- color: var(--fgColor-muted, #59636e);
-}
-.task-progress-bar {
- flex: 0 0 auto;
- width: min(160px, 30vw);
- height: 6px;
- background-color: var(--borderColor-muted, #d0d7de);
- border-radius: 3px;
- overflow: hidden;
-}
-.task-progress-bar-fill {
- height: 100%;
- background-color: var(--fgColor-success, #1a7f37);
- border-radius: 3px;
- transition: width 0.2s ease;
-}
-.task-progress-label {
- white-space: nowrap;
-}
-.task-progress--done {
- color: var(--fgColor-success, #1a7f37);
- font-weight: 600;
-}
-
-/* Victory banner — shown when all checkboxes on a page are checked */
-@keyframes victory-in {
- from { opacity: 0; transform: translate(-50%, 20px) scale(0.88); }
- to { opacity: 1; transform: translate(-50%, 0) scale(1); }
-}
-@keyframes victory-out {
- from { opacity: 1; transform: translate(-50%, 0) scale(1); }
- to { opacity: 0; transform: translate(-50%, -16px) scale(0.94); }
-}
-@keyframes victory-sparkle {
- 0%, 100% { opacity: 1; transform: scale(1) rotate(0deg); }
- 40% { opacity: 0.7; transform: scale(1.35) rotate(18deg); }
-}
-@keyframes victory-star-float {
- 0% { opacity: 0; transform: translateY(0) scale(0.5); }
- 30% { opacity: 1; }
- 100% { opacity: 0; transform: translateY(-40px) scale(1.1); }
-}
-.page-victory {
- position: fixed;
- bottom: 36px;
- left: 50%;
- transform: translateX(-50%);
- z-index: 9999;
- display: inline-flex;
- align-items: center;
- gap: 10px;
- padding: 14px 26px;
- color: #ffffff;
- font-family: 'Mona Sans Variable', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
- font-size: 15px;
- font-weight: 600;
- line-height: 1.3;
- white-space: nowrap;
- background: linear-gradient(135deg, #1a7f37 0%, #2da44e 60%, #3fb950 100%);
- border-radius: 14px;
- box-shadow: 0 8px 32px rgba(26, 127, 55, 0.45), 0 2px 8px rgba(0, 0, 0, 0.18);
- animation: victory-in 0.38s cubic-bezier(0.22, 1, 0.36, 1) forwards;
- pointer-events: none;
-}
-.page-victory--leaving {
- animation: victory-out 0.45s ease-in forwards;
-}
-.page-victory-icon {
- display: inline-block;
- font-size: 18px;
- line-height: 1;
- animation: victory-sparkle 1.1s ease-in-out infinite;
-}
-.page-victory-stars {
- position: absolute;
- inset: 0;
- overflow: hidden;
- border-radius: inherit;
- pointer-events: none;
-}
-.page-victory-stars::before,
-.page-victory-stars::after {
- content: '✦';
- position: absolute;
- font-size: 11px;
- color: rgba(255, 255, 255, 0.7);
- animation: victory-star-float 1.6s ease-out infinite;
-}
-.page-victory-stars::before {
- top: 6px;
- left: 18px;
- animation-delay: 0.2s;
-}
-.page-victory-stars::after {
- top: 8px;
- right: 22px;
- animation-delay: 0.75s;
-}
-
-/* Completed page indicator in the sidebar menu */
-.workshop-menu-group a[data-page-complete]::after {
- content: '\\a0✓';
- color: var(--fgColor-success, #1a7f37);
- font-weight: 700;
-}
-
-/* Micro progress bar under each menu item */
-.menu-item-progress {
- display: none;
- height: 3px;
- margin: 0 8px 4px;
- background-color: var(--borderColor-muted, #d0d7de);
- border-radius: 2px;
- overflow: hidden;
-}
-.menu-item-progress[data-has-checkpoints] {
- display: block;
-}
-.menu-item-progress-fill {
- height: 100%;
- width: 0%;
- background-color: var(--fgColor-success, #1a7f37);
- border-radius: 2px;
- transition: width 0.2s ease;
-}
-.workshop-menu-group a[data-page-complete] + .menu-item-progress .menu-item-progress-fill {
- opacity: 0.6;
-}
-
-/* Markdown text-editor style blocks */
-.markdown-editor-block {
- border-radius: 8px;
- overflow: hidden;
- border: 1px solid var(--borderColor-muted, #d0d7de);
- margin-bottom: 16px;
-}
-
-.markdown-editor-bar {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 8px 14px;
- background-color: var(--bgColor-muted, #f6f8fa);
- border-bottom: 1px solid var(--borderColor-muted, #d0d7de);
-}
-
-.markdown-editor-icon {
- flex-shrink: 0;
- color: var(--fgColor-muted, #59636e);
- font-size: 14px;
- line-height: 1;
-}
-
-.markdown-body .markdown-editor-pre {
- margin: 0;
- padding: 12px 12px 12px 16px;
- background-color: var(--bgColor-default, #ffffff);
- border: none;
- border-radius: 0;
- box-shadow: inset 3px 0 var(--borderColor-muted, #d0d7de);
- overflow-x: auto;
-}
-
-.markdown-body .markdown-editor-pre > code {
- color: var(--fgColor-default, #1f2328);
- background: transparent;
- padding: 0;
- border-radius: 0;
- font-size: 0.875em;
-}
-
-.markdown-editor-block .code-copy-btn {
- background-color: var(--bgColor-default, #ffffff);
- border-color: var(--borderColor-muted, #d0d7de);
- color: var(--fgColor-muted, #59636e);
-}
-
-.markdown-editor-block .code-copy-btn:hover {
- background-color: var(--bgColor-muted, #f6f8fa);
- color: var(--fgColor-default, #1f2328);
-}
-
-@media (prefers-color-scheme: dark) {
- html[data-color-mode="auto"] .markdown-editor-block {
- border-color: #30363d;
- }
- html[data-color-mode="auto"] .markdown-editor-bar {
- background-color: #161b22;
- border-bottom-color: #30363d;
- }
- html[data-color-mode="auto"] .markdown-editor-icon {
- color: #8b949e;
- }
- html[data-color-mode="auto"] .markdown-body .markdown-editor-pre {
- background-color: #0d1117;
- box-shadow: inset 3px 0 #30363d;
- }
- html[data-color-mode="auto"] .markdown-body .markdown-editor-pre > code {
- color: #e6edf3;
- }
- html[data-color-mode="auto"] .markdown-editor-block .code-copy-btn {
- background-color: #0d1117;
- border-color: #30363d;
- color: #8b949e;
- }
- html[data-color-mode="auto"] .markdown-editor-block .code-copy-btn:hover {
- background-color: #161b22;
- color: #e6edf3;
- }
-}
-
-html[data-color-mode="dark"] .markdown-editor-block {
- border-color: #30363d;
-}
-html[data-color-mode="dark"] .markdown-editor-bar {
- background-color: #161b22;
- border-bottom-color: #30363d;
-}
-html[data-color-mode="dark"] .markdown-editor-icon {
- color: #8b949e;
-}
-html[data-color-mode="dark"] .markdown-body .markdown-editor-pre {
- background-color: #0d1117;
- box-shadow: inset 3px 0 #30363d;
-}
-html[data-color-mode="dark"] .markdown-body .markdown-editor-pre > code {
- color: #e6edf3;
-}
-html[data-color-mode="dark"] .markdown-editor-block .code-copy-btn {
- background-color: #0d1117;
- border-color: #30363d;
- color: #8b949e;
-}
-html[data-color-mode="dark"] .markdown-editor-block .code-copy-btn:hover {
- background-color: #161b22;
- color: #e6edf3;
-}
-
-/* YAML editor-style code blocks */
-.yaml-editor-block {
- border-radius: 8px;
- overflow: hidden;
- border: 1px solid var(--borderColor-muted, #d0d7de);
- margin-bottom: 16px;
-}
-
-.yaml-editor-bar {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 8px 14px;
- background-color: var(--bgColor-muted, #f6f8fa);
- border-bottom: 1px solid var(--borderColor-muted, #d0d7de);
-}
-
-.yaml-editor-icon {
- flex-shrink: 0;
- color: var(--fgColor-muted, #59636e);
- font-size: 14px;
- line-height: 1;
-}
-
-.markdown-body .yaml-editor-pre {
- margin: 0;
- padding: 12px;
- background-color: var(--bgColor-default, #ffffff);
- border: none;
- border-radius: 0;
- overflow-x: auto;
-}
-
-.markdown-body .yaml-editor-pre > code {
- color: var(--fgColor-default, #1f2328);
- background: transparent;
- padding: 0;
- border-radius: 0;
- font-size: 0.875em;
-}
-
-.yaml-editor-block .code-copy-btn {
- background-color: var(--bgColor-default, #ffffff);
- border-color: var(--borderColor-muted, #d0d7de);
- color: var(--fgColor-muted, #59636e);
-}
-
-.yaml-editor-block .code-copy-btn:hover {
- background-color: var(--bgColor-muted, #f6f8fa);
- color: var(--fgColor-default, #1f2328);
-}
-
-@media (prefers-color-scheme: dark) {
- html[data-color-mode="auto"] .yaml-editor-block {
- border-color: #30363d;
- }
- html[data-color-mode="auto"] .yaml-editor-bar {
- background-color: #161b22;
- border-bottom-color: #30363d;
- }
- html[data-color-mode="auto"] .yaml-editor-icon {
- color: #8b949e;
- }
- html[data-color-mode="auto"] .markdown-body .yaml-editor-pre {
- background-color: #0d1117;
- }
- html[data-color-mode="auto"] .markdown-body .yaml-editor-pre > code {
- color: #e6edf3;
- }
- html[data-color-mode="auto"] .yaml-editor-block .code-copy-btn {
- background-color: #0d1117;
- border-color: #30363d;
- color: #8b949e;
- }
- html[data-color-mode="auto"] .yaml-editor-block .code-copy-btn:hover {
- background-color: #161b22;
- color: #e6edf3;
- }
-}
-
-html[data-color-mode="dark"] .yaml-editor-block {
- border-color: #30363d;
-}
-html[data-color-mode="dark"] .yaml-editor-bar {
- background-color: #161b22;
- border-bottom-color: #30363d;
-}
-html[data-color-mode="dark"] .yaml-editor-icon {
- color: #8b949e;
-}
-html[data-color-mode="dark"] .markdown-body .yaml-editor-pre {
- background-color: #0d1117;
-}
-html[data-color-mode="dark"] .markdown-body .yaml-editor-pre > code {
- color: #e6edf3;
-}
-html[data-color-mode="dark"] .yaml-editor-block .code-copy-btn {
- background-color: #0d1117;
- border-color: #30363d;
- color: #8b949e;
-}
-html[data-color-mode="dark"] .yaml-editor-block .code-copy-btn:hover {
- background-color: #161b22;
- color: #e6edf3;
-}
-
-/* ========================
- CSS View Transitions
- ======================== */
-@media (prefers-reduced-motion: no-preference) {
- .markdown-body > details[open] {
- view-transition-name: workshop-page;
- }
-
- @keyframes vt-slide-in-right {
- from { opacity: 0; transform: translateX(48px); }
- to { opacity: 1; transform: translateX(0); }
- }
- @keyframes vt-slide-out-left {
- from { opacity: 1; transform: translateX(0); }
- to { opacity: 0; transform: translateX(-48px); }
- }
- @keyframes vt-slide-in-left {
- from { opacity: 0; transform: translateX(-48px); }
- to { opacity: 1; transform: translateX(0); }
- }
- @keyframes vt-slide-out-right {
- from { opacity: 1; transform: translateX(0); }
- to { opacity: 0; transform: translateX(48px); }
- }
-
- ::view-transition-old(workshop-page) {
- animation: 300ms cubic-bezier(0.4, 0, 1, 1) both vt-slide-out-left;
- }
- ::view-transition-new(workshop-page) {
- animation: 300ms cubic-bezier(0, 0, 0.2, 1) both vt-slide-in-right;
- }
-
- html[data-nav-backward] ::view-transition-old(workshop-page) {
- animation: 300ms cubic-bezier(0.4, 0, 1, 1) both vt-slide-out-right;
- }
- html[data-nav-backward] ::view-transition-new(workshop-page) {
- animation: 300ms cubic-bezier(0, 0, 0.2, 1) both vt-slide-in-left;
- }
-}
-`;
-fs.writeFileSync(path.join(distDir, 'docs.css'), docsCss);
+fs.writeFileSync(path.join(distDir, 'alerts.css'), generateAlertsCss());
+fs.writeFileSync(path.join(distDir, 'hljs.css'), generateHljsCss());
+fs.writeFileSync(path.join(distDir, 'docs.css'), generateDocsCss());
const parallaxBackgroundSvgEncoded = encodeURIComponent([
'