diff --git a/.github/workflows/capture.yml b/.github/workflows/capture.yml index 20cf8d3..2207747 100644 --- a/.github/workflows/capture.yml +++ b/.github/workflows/capture.yml @@ -10,16 +10,29 @@ on: type: choice options: - '0.5' + - '0.75' - '1' + - '1.25' - '1.5' - - '3' + - '2' + num_workers: + description: Number of Chromium workers to run in parallel + required: false + default: '8' + type: choice + options: + - '1' + - '2' + - '4' + - '6' + - '8' permissions: contents: write jobs: screenshot: - runs-on: ubuntu-latest + runs-on: blacksmith-8vcpu-ubuntu-2404 steps: - name: Checkout uses: actions/checkout@v6 @@ -47,201 +60,19 @@ jobs: - name: Start server and take screenshots env: SCREENSHOT_ZOOM_LEVEL: ${{ inputs.zoom_level || '1' }} + SCREENSHOT_NUM_WORKERS: ${{ inputs.num_workers || '4' }} + SCREENSHOT_OUT_DIR: ${{ github.workspace }}/.screenshots run: | - # Start static server in background - bunx --bun serve . -p 1313 > /dev/null 2>&1 & - SERVER_PID=$! - - # Wait for server to be ready - echo "Waiting for server to start..." - for i in {1..30}; do - if curl -s http://localhost:1313/ > /dev/null 2>&1; then - echo "Server is ready!" - break - fi - sleep 1 - done - - # Create screenshot directories and capture slides - node << 'EOF' - const { chromium } = require('playwright'); - const fs = require('fs'); - const path = require('path'); - const zoomLevel = Number(process.env.SCREENSHOT_ZOOM_LEVEL || '1'); - - if (!Number.isFinite(zoomLevel) || zoomLevel <= 0) { - throw new Error(`Invalid SCREENSHOT_ZOOM_LEVEL: ${process.env.SCREENSHOT_ZOOM_LEVEL}`); - } - - // URLs to capture: [url, folderName] or [url, folderName, waitTimeMs] - // Optional waitTimeMs: wait after load before screenshot (for animated slides) - // Main slides 1-17, plus basement slides at 8 and 16 - const urls = [ - ['/', 'slide-01'], - ['/#/2', 'slide-02'], - ['/#/3', 'slide-03'], - ['/#/4', 'slide-04'], - // ['/#/5', 'slide-05'], - // ['/#/6', 'slide-06'], - // ['/#/7', 'slide-07'], - ['/#/8', 'slide-08-01'], - ['/#/8/2', 'slide-08-02'], - // ['/#/9', 'slide-09'], - ['/#/10', 'slide-10'], - ['/#/11', 'slide-11'], - ['/#/12', 'slide-12'], - // ['/#/13', 'slide-13'], - // ['/#/14', 'slide-14'], - // ['/#/15', 'slide-15'], - ['/#/16', 'slide-16-01'], - ['/#/16/2', 'slide-16-02'], - ['/#/16/3', 'slide-16-03'], - // ['/#/17', 'slide-17'], - ]; - - // Define resolutions: [width, height, label] - const resolutions = [ - // Mobile - [375, 667, 'iphone-se'], - [390, 844, 'iphone-12-13'], - [430, 932, 'iphone-14-15-16-17-pro-max'], - // Mobile Landscape - [667, 375, 'iphone-se-landscape'], - [844, 390, 'iphone-12-13-landscape'], - [932, 430, 'iphone-14-15-16-17-pro-max-landscape'], - // Tablet - [768, 1024, 'ipad-portrait'], - [1024, 768, 'ipad-landscape'], - // Desktop - [1280, 720, 'desktop-1280x720'], - [1366, 768, 'desktop-1366x768'], - [1440, 900, 'desktop-1440x900'], - [1920, 1080, 'desktop-1920x1080'], - [2560, 1440, 'desktop-2560x1440'], - ]; - - async function takeScreenshots(url, folder, waitTime = 0) { - const browser = await chromium.launch(); - const screenshots = []; - const fullUrl = `http://localhost:1313${url}`; - - if (waitTime > 0) { - // Load once, wait for animation, then resize for each resolution - console.log(`Loading ${url} at ${zoomLevel}x zoom and waiting ${waitTime}ms for animation...`); - const page = await browser.newPage(); - const [firstWidth, firstHeight, firstLabel] = resolutions[0]; - await page.setViewportSize({ width: firstWidth, height: firstHeight }); - await page.goto(fullUrl, { waitUntil: 'networkidle' }); - await page.waitForTimeout(500); - await page.evaluate((zoom) => { - document.documentElement.style.zoom = String(zoom); - }, zoomLevel); - await page.waitForTimeout(100); - await page.waitForTimeout(waitTime); - - // Now take screenshots at all resolutions by resizing - for (const [width, height, label] of resolutions) { - console.log(`Taking ${width}x${height} (${label}) for ${url} at ${zoomLevel}x zoom`); - await page.setViewportSize({ width, height }); - await page.evaluate((zoom) => { - document.documentElement.style.zoom = String(zoom); - }, zoomLevel); - // Small delay to let layout adjust after resize - await page.waitForTimeout(100); - - const filename = `${width}x${height}-${label}.png`; - const filepath = path.join(folder, filename); - await page.screenshot({ path: filepath, fullPage: false }); - screenshots.push({ filename, width, height, label }); - } - - await page.close(); - } else { - // Reload for each resolution - for (const [width, height, label] of resolutions) { - console.log(`Taking ${width}x${height} (${label}) for ${url} at ${zoomLevel}x zoom`); - const page = await browser.newPage(); - await page.setViewportSize({ width, height }); - await page.goto(fullUrl, { waitUntil: 'networkidle' }); - await page.waitForTimeout(500); - await page.evaluate((zoom) => { - document.documentElement.style.zoom = String(zoom); - }, zoomLevel); - await page.waitForTimeout(100); - - const filename = `${width}x${height}-${label}.png`; - const filepath = path.join(folder, filename); - await page.screenshot({ path: filepath, fullPage: false }); - await page.close(); - - screenshots.push({ filename, width, height, label }); - } - } - - await browser.close(); - return screenshots; - } - - function getFolderTitle(folderName) { - return folderName - .split('-') - .map(word => word.charAt(0).toUpperCase() + word.slice(1)) - .join(' '); - } - - async function generateReadme(folder, screenshots) { - const timestamp = new Date().toISOString().replace(/:/g, '-').split('.')[0] + 'Z'; - const readmePath = path.join(folder, 'README.md'); - - let content = `# ${getFolderTitle(folder)}\n\n`; - content += `Generated: ${new Date().toISOString()}\n\n`; - content += `| Resolution | Device | Screenshot |\n`; - content += `|------------|--------|------------|\n`; - - for (const { filename, width, height, label } of screenshots) { - content += `| ${width} × ${height} | ${label} |  |\n`; - } - - fs.writeFileSync(readmePath, content); - } - - (async () => { - try { - const allFolders = []; - console.log(`Using screenshot zoom level: ${zoomLevel}x`); - - for (const entry of urls) { - const [url, folderName, waitTime = 0] = entry; - fs.mkdirSync(folderName, { recursive: true }); - allFolders.push(folderName); - - const waitMsg = waitTime > 0 ? ` (wait ${waitTime}ms)` : ''; - console.log(`=== Capturing ${folderName} for ${url}${waitMsg} ===`); - const screenshots = await takeScreenshots(url, folderName, waitTime); - await generateReadme(folderName, screenshots); - console.log(`Captured ${screenshots.length} screenshots for ${folderName}`); - } - - console.log('All screenshots saved successfully'); - fs.writeFileSync('_screenshot_folders.json', JSON.stringify(allFolders)); - } catch (error) { - console.error('Error taking screenshots:', error); - process.exit(1); - } - })(); - EOF - - # Stop server - kill $SERVER_PID 2>/dev/null || true + ./scripts/capture-screenshots.sh - name: Create orphan branch and commit screenshots run: | git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" - FOLDERS=$(node -e "console.log(require('./_screenshot_folders.json').join(' '))") - rm _screenshot_folders.json - mv $FOLDERS /tmp/ + FOLDERS=$(bun -e "console.log(JSON.parse(require('fs').readFileSync('.screenshots/_screenshot_folders.json', 'utf8')).join(' '))") + rm .screenshots/_screenshot_folders.json + mv .screenshots/slide-* /tmp/ git checkout main || git checkout master || true git branch -D screenshots 2>/dev/null || true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ccc4619 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.screenshots/ +node_modules +bun.lock +package.json +*.cjs \ No newline at end of file diff --git a/README.md b/README.md index ef50717..784f4f9 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ Reveal.js runtime assets are vendored in-repo for offline use. - `index.html`: Reveal.js bootstrap, markdown loading, and custom slide behavior. - `custom.css`: presentation theme and layout styling. - `vendor/reveal.js/`: local Reveal.js CSS/JS/plugin assets used by `index.html`. +- `vendor/katex/`: slim local KaTeX runtime used for offline math rendering. +- `scripts/vendor-katex.sh`: idempotent vendoring script for the KaTeX runtime subset. +- `scripts/capture-screenshots.sh`: local multi-resolution screenshot capture for visual validation. ## Run In Dev @@ -20,17 +23,60 @@ bunx --bun serve . -p 1313 Then open the local URL printed by `serve` in your browser. -## Refresh Vendored Reveal Assets +## Capture Screenshots Locally + +To validate typography/layout changes across the same resolution set used in CI: ```bash -mkdir -p vendor/reveal.js/dist/theme vendor/reveal.js/plugin/markdown vendor/reveal.js/plugin/highlight -wget -q -O vendor/reveal.js/dist/reveal.css https://cdn.jsdelivr.net/npm/reveal.js@5/dist/reveal.css -wget -q -O vendor/reveal.js/dist/theme/black.css https://cdn.jsdelivr.net/npm/reveal.js@5/dist/theme/black.css -wget -q -O vendor/reveal.js/dist/reveal.js https://cdn.jsdelivr.net/npm/reveal.js@5/dist/reveal.js -wget -q -O vendor/reveal.js/plugin/markdown/markdown.js https://cdn.jsdelivr.net/npm/reveal.js@5/plugin/markdown/markdown.js -wget -q -O vendor/reveal.js/plugin/highlight/highlight.js https://cdn.jsdelivr.net/npm/reveal.js@5/plugin/highlight/highlight.js +SCREENSHOT_ZOOM_LEVEL=1 ./scripts/capture-screenshots.sh +``` + +This writes slide image folders plus `_screenshot_folders.json` into `.screenshots/` by default. +The script aligns with CI by ensuring the `playwright` package is installed locally before capture, then installing Chromium. +Override `SCREENSHOT_OUT_DIR` to capture elsewhere, and `SCREENSHOT_PORT` if `1313` is already in use. + +## Authoring Math + +Display math can be written using fenced `math` blocks in `present.md`: + +````md +```math +\int_0^\infty e^{-x^2} \, dx = \frac{\sqrt{\pi}}{2} ``` +```` + +`index.html` rewrites these fences to KaTeX display-math delimiters before Reveal parses the deck, so slide authoring stays markdown-native while rendering still uses Reveal's math plugin. + +Inline math also works with standard KaTeX delimiters such as `$x^2$`, `\(...\)`, and `\[...\]`. + +## Refresh Vendored Assets + +```bash +mkdir -p vendor/reveal.js/dist/theme vendor/reveal.js/plugin/markdown vendor/reveal.js/plugin/highlight vendor/reveal.js/plugin/math +curl -fsSL https://cdn.jsdelivr.net/npm/reveal.js@5.2.1/dist/reveal.css -o vendor/reveal.js/dist/reveal.css +curl -fsSL https://cdn.jsdelivr.net/npm/reveal.js@5.2.1/dist/theme/black.css -o vendor/reveal.js/dist/theme/black.css +curl -fsSL https://cdn.jsdelivr.net/npm/reveal.js@5.2.1/dist/reveal.js -o vendor/reveal.js/dist/reveal.js +curl -fsSL https://cdn.jsdelivr.net/npm/reveal.js@5.2.1/plugin/markdown/markdown.js -o vendor/reveal.js/plugin/markdown/markdown.js +curl -fsSL https://cdn.jsdelivr.net/npm/reveal.js@5.2.1/plugin/highlight/highlight.js -o vendor/reveal.js/plugin/highlight/highlight.js +curl -fsSL https://cdn.jsdelivr.net/npm/reveal.js@5.2.1/plugin/math/math.js -o vendor/reveal.js/plugin/math/math.js +./scripts/vendor-katex.sh +``` + +The KaTeX script vendors only the runtime files Reveal needs: + +- `dist/katex.min.js` +- `dist/katex.min.css` +- `dist/contrib/auto-render.min.js` +- `dist/fonts/*.woff2` +- `dist/fonts/*.woff` +- `LICENSE` + +Set `KATEX_VERSION` to override the pinned default when refreshing, for example: + +```bash +KATEX_VERSION=0.16.37 ./scripts/vendor-katex.sh +``` + +## Footer Text -# Footer Text -Line 294 of `index.html` can be edited to change the footer text from `present.md` to anything else. -It is there that the styling of the pagination is also handled. +Edit the `counter.textContent = \`${current} / ${total} | present.md\`;` line in `index.html` to change the footer text from `present.md` to something else. diff --git a/custom.css b/custom.css index a0ca74b..4faead9 100644 --- a/custom.css +++ b/custom.css @@ -3,7 +3,26 @@ --fg: #d8dee9; --muted: #8f98ab; --line: #5f6b84; - --slide-font-size: clamp(14px, 0.85vw + 0.65vh, 18px); + --slide-font-size: clamp(14px, calc(11px + 0.28vw + 0.22vh), 20px); + --content-heading-size: clamp(24px, calc(18px + 0.34vw + 0.24vh), 34px); + --content-body-size: clamp(20px, calc(16px + 0.24vw + 0.16vh), 28px); + --content-table-size: clamp(18px, calc(15px + 0.22vw + 0.14vh), 26px); + --content-table-only-size: clamp(21px, calc(16px + 0.3vw + 0.2vh), 30px); + --content-table-fit-scale: 1; + --slide-content-fit-scale: 1; + --table-border-width: 1px; + --content-code-size: clamp(16px, calc(13px + 0.2vw + 0.12vh), 22px); + --content-math-size: clamp(26px, calc(20px + 0.38vw + 0.28vh), 38px); + --standalone-table-slide-width: clamp(42rem, 62vw, 110rem); + --chrome-header-size: 13px; + --chrome-header-margin-y: 8px; + --chrome-header-margin-x: 8px; + --chrome-header-pad-y: 4px; + --chrome-header-pad-x: 7px; + --chrome-border-width: 1px; + --chrome-counter-size: 13px; + --chrome-counter-left: 14px; + --chrome-counter-bottom: 10px; --slide-pad-top-base: 5.2rem; --slide-pad-bottom-base: 3rem; --deck-header-offset: var(--slide-pad-top-base); @@ -13,6 +32,10 @@ --slide-pad-left: clamp(1rem, 3.4vw, 4rem); --slide-pad-right: clamp(0.75rem, 2.2vw, 1.25rem); --walkthrough-code-height: min(66vh, calc(100vh - 12.5rem)); + --content-pre-margin-top: 2px; + --content-pre-margin-bottom: 14px; + --math-display-margin-top: 4px; + --math-display-margin-bottom: 14px; } html, @@ -84,10 +107,17 @@ body { margin-top: 0 !important; } -.reveal .slides section > :not(table):not(figure):not(pre):not(section) { +.reveal .slides section > :not(table):not(figure):not(pre):not(section):not(ul):not(ol):not(dl) { margin-left: 0 !important; margin-right: 0 !important; - max-width: min(72ch, 100%) !important; + max-width: min(96ch, 100%) !important; + text-align: left !important; +} + +.reveal .slides section > :is(ul, ol, dl) { + margin-left: 0 !important; + margin-right: 0 !important; + max-width: 100% !important; text-align: left !important; } @@ -116,7 +146,7 @@ body { .reveal .slides section h5, .reveal .slides section h6 { font-family: "JetBrains Mono", "Fira Code", monospace; - font-size: 1em; + font-size: calc(var(--content-heading-size) * var(--slide-content-fit-scale)); font-weight: 500; letter-spacing: 0; line-height: 1.25; @@ -128,10 +158,23 @@ body { .reveal .slides section li, .reveal .slides section th, .reveal .slides section td { - font-size: 0.9em; + font-size: calc(var(--content-body-size) * var(--slide-content-fit-scale)); line-height: 1.34; } +.reveal .slides section table:not(.hljs-ln) th, +.reveal .slides section table:not(.hljs-ln) td { + font-size: calc(var(--content-table-size) * var(--content-table-fit-scale) * var(--slide-content-fit-scale)); + line-height: 1.22; +} + +.reveal .slides section.standalone-table-slide > table:not(.hljs-ln) th, +.reveal .slides section.standalone-table-slide > table:not(.hljs-ln) td, +.reveal .slides section.standalone-table-slide > figure > table:not(.hljs-ln) th, +.reveal .slides section.standalone-table-slide > figure > table:not(.hljs-ln) td { + font-size: calc(var(--content-table-only-size) * var(--slide-content-fit-scale)); +} + .reveal .slides section ul, .reveal .slides section ol, .reveal .slides section dl { @@ -140,6 +183,13 @@ body { padding-left: 0; } +.reveal .slides section li > ul, +.reveal .slides section li > ol, +.reveal .slides section li > dl { + margin: 0.15em 0 !important; + padding-left: 1.6em; +} + .reveal .slides section ul { list-style: none; } @@ -159,6 +209,7 @@ body { } .reveal .slides section li { + margin: 0.15em 0 !important; margin-left: 0 !important; padding-left: 0 !important; } @@ -184,7 +235,7 @@ body { .reveal .slides section table:not(.hljs-ln) { margin: 0.5em auto 0.8em auto !important; width: auto; - border: 1px solid rgba(95, 107, 132, 0.45); + border: calc(var(--table-border-width) * var(--content-table-fit-scale)) solid rgba(95, 107, 132, 0.45); border-collapse: collapse; } @@ -218,8 +269,8 @@ body { } /* Override Reveal's display:block on .present; use grid for reliable centering */ -.reveal .slides section.table-only-slide, -.reveal .slides section.table-only-slide.present { +.reveal .slides section.standalone-table-slide, +.reveal .slides section.standalone-table-slide.present { display: grid !important; place-items: center; place-content: center; @@ -231,27 +282,32 @@ body { overflow: visible; } -.reveal .slides section.table-only-slide > table:not(.hljs-ln), -.reveal .slides section.table-only-slide > figure { +.reveal .slides section.standalone-table-slide > table:not(.hljs-ln), +.reveal .slides section.standalone-table-slide > figure { margin: 0 !important; transform: none !important; - max-width: min(80ch, 100%); + width: min(100%, var(--standalone-table-slide-width)); + max-width: min(100%, var(--standalone-table-slide-width)); justify-self: center; align-self: center; } -.reveal .slides section.table-only-slide > figure > table:not(.hljs-ln) { +.reveal .slides section.standalone-table-slide > figure > table:not(.hljs-ln) { margin: 0 !important; + width: 100%; } .reveal .slides section table:not(.hljs-ln) th, .reveal .slides section table:not(.hljs-ln) td { - border: 1px solid rgba(95, 107, 132, 0.45); + border: calc(var(--table-border-width) * var(--content-table-fit-scale)) solid rgba(95, 107, 132, 0.45); padding: 0.18em 0.45em; + overflow-wrap: break-word; + word-break: normal; + hyphens: manual; } .reveal .slides section table:not(.hljs-ln) tbody tr:last-child td { - border-bottom: 1px solid rgba(95, 107, 132, 0.45) !important; + border-bottom: calc(var(--table-border-width) * var(--content-table-fit-scale)) solid rgba(95, 107, 132, 0.45) !important; } .reveal .slides section.code-walkthrough pre { @@ -272,14 +328,12 @@ body { scrollbar-gutter: stable both-edges; scrollbar-width: thin; scrollbar-color: rgba(143, 152, 171, 0.55) rgba(6, 8, 12, 0.35); - font-size: 0.98em; + font-size: var(--content-code-size); line-height: 1.34; } @media (max-width: 768px) { :root { - --slide-pad-top-base: 3.2rem; - --slide-pad-bottom-base: 2.5rem; --slide-pad-left: 1rem; --slide-pad-right: 1rem; --walkthrough-code-height: min(56vh, calc(100vh - 8.5rem)); @@ -287,8 +341,8 @@ body { .reveal .slides section > table:not(.hljs-ln), .reveal .slides section > figure, - .reveal .slides section.table-only-slide > table:not(.hljs-ln), - .reveal .slides section.table-only-slide > figure { + .reveal .slides section.standalone-table-slide > table:not(.hljs-ln), + .reveal .slides section.standalone-table-slide > figure { transform: none !important; } @@ -298,6 +352,13 @@ body { .reveal .slides section td { overflow-wrap: anywhere; } + + .reveal .slides section table:not(.hljs-ln) th, + .reveal .slides section table:not(.hljs-ln) td { + overflow-wrap: break-word; + word-break: normal; + padding: 0.12em 0.28em; + } } .reveal .slides section.code-walkthrough pre code::-webkit-scrollbar { @@ -347,7 +408,7 @@ body { .reveal table.hljs-ln td { padding: 0 !important; - font-size: 0.98em !important; + font-size: calc(var(--content-code-size) * var(--slide-content-fit-scale)) !important; line-height: 1.34 !important; } @@ -369,7 +430,10 @@ body { } .reveal pre { - margin: 0.15em 0 0.7em !important; + margin: + calc(var(--content-pre-margin-top) * var(--slide-content-fit-scale)) + 0 + calc(var(--content-pre-margin-bottom) * var(--slide-content-fit-scale)) !important; margin-left: 0 !important; margin-right: auto !important; display: block; @@ -380,26 +444,41 @@ body { box-shadow: none; } -.reveal pre.raw-fence::before { - content: "```" attr(data-lang); +.reveal pre:has(+ .katex-display), +.reveal pre:has(+ p .katex-display), +.reveal pre:has(+ p > .katex-display) { + margin-bottom: calc(4px * var(--slide-content-fit-scale)) !important; +} + +.reveal pre.raw-fence::before, +.reveal pre.raw-fence::after { display: block; - margin-bottom: 0.12em; color: var(--muted); - font-size: 0.98em; + font-family: inherit; + font-size: calc(var(--content-code-size) * var(--slide-content-fit-scale)); + font-weight: inherit; letter-spacing: 0.01em; + line-height: 1.34; +} + +.reveal pre.raw-fence::before { + content: "```" attr(data-lang); + margin-bottom: 0.24em; } .reveal pre.raw-fence::after { content: "```"; - display: block; - margin-top: 0.06em; - color: var(--muted); - font-size: 0.98em; - letter-spacing: 0.01em; + margin-top: 0.24em; +} + +.reveal pre.raw-fence:has(+ .katex-display)::after, +.reveal pre.raw-fence:has(+ p .katex-display)::after, +.reveal pre.raw-fence:has(+ p > .katex-display)::after { + margin-top: 0.08em; } .reveal pre code { - font-size: 0.98em; + font-size: calc(var(--content-code-size) * var(--slide-content-fit-scale)); line-height: 1.34; padding: 0; text-align: left; @@ -475,6 +554,45 @@ body { color: #c7a8ff; } +.reveal .katex { + color: var(--fg); +} + +.reveal .katex-display { + font-size: 1em; + margin: + calc(var(--math-display-margin-top) * var(--slide-content-fit-scale)) + 0 + calc(var(--math-display-margin-bottom) * var(--slide-content-fit-scale)) !important; + overflow-x: auto; + overflow-y: hidden; +} + +.reveal pre + .katex-display { + margin-top: calc(0px * var(--slide-content-fit-scale)) !important; +} + +.reveal pre + p:has(.katex-display), +.reveal pre + p:has(> .katex-display) { + margin-top: 0 !important; + margin-bottom: calc(2px * var(--slide-content-fit-scale)) !important; +} + +.reveal pre + p .katex-display, +.reveal pre + p > .katex-display { + margin-top: 0 !important; +} + +.reveal .katex-display > .katex { + font-size: calc(var(--content-math-size) * var(--slide-content-fit-scale)) !important; + text-align: left; +} + +.reveal .katex-display > .base { + margin-left: 0; + margin-right: auto; +} + #deck-header { position: fixed; top: 0; @@ -486,7 +604,7 @@ body { padding: 0; color: var(--fg); font-family: "JetBrains Mono", "Fira Code", "IBM Plex Mono", monospace; - font-size: clamp(0.72rem, 0.6rem + 0.35vw, 0.9rem); + font-size: var(--chrome-header-size); font-weight: 600; letter-spacing: 0.02em; line-height: 1.2; @@ -496,11 +614,11 @@ body { #deck-header-text { display: block; - margin: clamp(0.35rem, 0.3rem + 0.25vw, 0.55rem) clamp(0.35rem, 0.3rem + 0.25vw, 0.55rem) 0; - padding: clamp(0.24rem, 0.2rem + 0.15vw, 0.34rem) clamp(0.42rem, 0.35rem + 0.2vw, 0.58rem); - border: 1px solid var(--line); + margin: var(--chrome-header-margin-y) var(--chrome-header-margin-x) 0; + padding: var(--chrome-header-pad-y) var(--chrome-header-pad-x); + border: var(--chrome-border-width) solid var(--line); background: rgba(12, 15, 20, 0.92); - box-shadow: 0 0 0 1px rgba(95, 107, 132, 0.2) inset; + box-shadow: 0 0 0 var(--chrome-border-width) rgba(95, 107, 132, 0.2) inset; box-sizing: border-box; overflow: hidden; overflow-wrap: anywhere; @@ -509,14 +627,14 @@ body { #deck-counter { position: fixed; - left: clamp(0.75rem, 0.45rem + 0.8vw, 1.1rem); - bottom: clamp(0.55rem, 0.35rem + 0.8vw, 0.8rem); + left: var(--chrome-counter-left); + bottom: var(--chrome-counter-bottom); z-index: 40; color: var(--muted); font-family: "JetBrains Mono", "Fira Code", monospace; - font-size: clamp(0.76rem, 0.68rem + 0.25vw, 0.9rem); + font-size: var(--chrome-counter-size); letter-spacing: 0.02em; - max-width: calc(100vw - 1.5rem); + max-width: calc(100vw - (var(--chrome-counter-left) * 2)); overflow-wrap: anywhere; pointer-events: none; } diff --git a/index.html b/index.html index 70db392..18b3486 100644 --- a/index.html +++ b/index.html @@ -17,7 +17,8 @@