commit 12123ad7560b85e41525dc40c28a2431fdcb9777 parent bb8d187525d3b74bc2d672bd36ac9def7dc058ab Author: Michael Neuper <michael@michaelneuper.com> Date: Mon, 12 Oct 2026 15:35:33 +0200 convert to astro The page is src/pages/index.astro, the scripts and styles moved to src/scripts and src/styles for Astro to bundle, and fonts, favicon, robots.txt and notes-to-self.txt moved to public/. Claude-Session: https://claude.ai/code/session_011d9ErWYG4cS8UDXfPRtwTJ Diffstat:
36 files changed, 6834 insertions(+), 3037 deletions(-)
diff --git a/.gitignore b/.gitignore @@ -0,0 +1,10 @@ +# build output +dist/ +# generated types +.astro/ +# dependencies +node_modules/ +# logs +npm-debug.log* +# macOS +.DS_Store diff --git a/astro.config.mjs b/astro.config.mjs @@ -0,0 +1,10 @@ +// @ts-check +import { defineConfig } from "astro/config"; + +export default defineConfig({ + // The default ("jsx") drops line breaks between text and inline elements, which + // glues words to links. true only removes whitespace that doesn't render. + compressHTML: true, + // The toolbar would sit on top of the modeline and echo area. + devToolbar: { enabled: false }, +}); diff --git a/css/style.css b/css/style.css @@ -1,2443 +0,0 @@ -/* ───────────────────────────── fonts ───────────────────────────── */ - -@font-face { - font-family: "JetBrains Mono"; - src: url("../fonts/jetbrains-mono-regular.woff2") format("woff2"); - font-weight: 400; - font-display: swap; -} - -@font-face { - font-family: "JetBrains Mono"; - src: url("../fonts/jetbrains-mono-semibold.woff2") format("woff2"); - font-weight: 600; - font-display: swap; -} - -/* Computer Modern, via KaTeX's build of it: the same family as Latin Modern */ -@font-face { - font-family: "Computer Modern"; - src: url("../fonts/cm-regular.woff2") format("woff2"); - font-weight: 400; - font-style: normal; - font-display: swap; -} - -@font-face { - font-family: "Computer Modern"; - src: url("../fonts/cm-italic.woff2") format("woff2"); - font-weight: 400; - font-style: italic; - font-display: swap; -} - -/* ───────────────────────────── themes ───────────────────────────── - Real Emacs themes. Each sets a background, a modeline background, - a foreground and seven accents; everything else is mixed from those. - Keep the names in sync with js/themes.js and the script in index.html. */ - -:root { - color-scheme: dark; - --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; - --serif: "Computer Modern", "Latin Modern Roman", "CMU Serif", Georgia, serif; - - --gutter: clamp(16px, 4.5vw, 56px); - --top-h: 44px; - --frame-h: 46px; - --col: 1088px; - - --bg: #282828; - --bg-alt: #3c3836; - --fg: #ebdbb2; - --red: #fb4934; - --orange: #fe8019; - --yellow: #fabd2f; - --green: #b8bb26; - --cyan: #8ec07c; - --blue: #83a598; - --magenta: #d3869b; - --glow: 1; - - --dim: color-mix(in srgb, var(--fg) 64%, var(--bg)); - --faint: color-mix(in srgb, var(--fg) 34%, var(--bg)); - --rule: color-mix(in srgb, var(--fg) 15%, var(--bg)); - --hl: color-mix(in srgb, var(--fg) 10%, var(--bg)); - --wash: color-mix(in srgb, var(--fg) 5%, transparent); - --led-off: color-mix(in srgb, var(--fg) 13%, var(--bg)); - --violet: color-mix(in oklch, var(--blue) 50%, var(--magenta)); - - --c-hw: var(--yellow); - --c-sw: var(--blue); - --c-math: var(--magenta); - --c-sec: var(--red); -} - -:root[data-theme="doom-gruvbox-light"] { - color-scheme: light; - --bg: #fbf1c7; --bg-alt: #ebdbb2; --fg: #3c3836; - --red: #9d0006; --orange: #af3a03; --yellow: #b57614; --green: #79740e; - --cyan: #427b58; --blue: #076678; --magenta: #8f3f71; - --glow: 0; -} - -:root[data-theme="doom-one"] { - --bg: #282c34; --bg-alt: #21242b; --fg: #bbc2cf; - --red: #ff6c6b; --orange: #da8548; --yellow: #ecbe7b; --green: #98be65; - --cyan: #46d9ff; --blue: #51afef; --magenta: #c678dd; -} - -:root[data-theme="atom-one-dark"] { - --bg: #282c34; --bg-alt: #21252b; --fg: #abb2bf; - --red: #e06c75; --orange: #d19a66; --yellow: #e5c07b; --green: #98c379; - --cyan: #56b6c2; --blue: #61afef; --magenta: #c678dd; -} - -:root[data-theme="modus-vivendi"] { - --bg: #000000; --bg-alt: #1e1e1e; --fg: #ffffff; - --red: #ff5f59; --orange: #fec43f; --yellow: #d0bc00; --green: #44bc44; - --cyan: #00d3d0; --blue: #2fafff; --magenta: #feacd0; -} - -:root[data-theme="modus-operandi"] { - color-scheme: light; - --bg: #ffffff; --bg-alt: #f2f2f2; --fg: #000000; - --red: #a60000; --orange: #884900; --yellow: #6f5500; --green: #006800; - --cyan: #005e8b; --blue: #0031a9; --magenta: #721045; - --glow: 0; -} - -:root[data-theme="doom-dracula"] { - --bg: #282a36; --bg-alt: #1e2029; --fg: #f8f8f2; - --red: #ff5555; --orange: #ffb86c; --yellow: #f1fa8c; --green: #50fa7b; - --cyan: #8be9fd; --blue: #61bfff; --magenta: #ff79c6; -} - -:root[data-theme="doom-nord"] { - --bg: #2e3440; --bg-alt: #3b4252; --fg: #eceff4; - --red: #bf616a; --orange: #d08770; --yellow: #ebcb8b; --green: #a3be8c; - --cyan: #88c0d0; --blue: #81a1c1; --magenta: #b48ead; -} - -:root[data-theme="catppuccin"] { - --bg: #1e1e2e; --bg-alt: #181825; --fg: #cdd6f4; - --red: #f38ba8; --orange: #fab387; --yellow: #f9e2af; --green: #a6e3a1; - --cyan: #94e2d5; --blue: #89b4fa; --magenta: #cba6f7; -} - -:root[data-theme="doom-tokyo-night"] { - --bg: #1a1b26; --bg-alt: #16161e; --fg: #c0caf5; - --red: #f7768e; --orange: #ff9e64; --yellow: #e0af68; --green: #9ece6a; - --cyan: #7dcfff; --blue: #7aa2f7; --magenta: #bb9af7; -} - -:root[data-theme="doom-solarized-light"] { - color-scheme: light; - --bg: #fdf6e3; --bg-alt: #eee8d5; --fg: #556b72; - --red: #dc322f; --orange: #cb4b16; --yellow: #b58900; --green: #859900; - --cyan: #2aa198; --blue: #268bd2; --magenta: #d33682; - --glow: 0; -} - -[data-cat="hw"] { --c: var(--c-hw); } -[data-cat="sw"] { --c: var(--c-sw); } -[data-cat="math"] { --c: var(--c-math); } -[data-cat="sec"] { --c: var(--c-sec); } - -/* ───────────────────────────── base ───────────────────────────── */ - -*, -*::before, -*::after { - box-sizing: border-box; -} - -html { - background: var(--bg); - color: var(--fg); - scroll-behavior: smooth; - scroll-snap-type: y proximity; - scroll-padding-top: calc(var(--top-h) + 24px); - -webkit-text-size-adjust: 100%; - text-size-adjust: 100%; -} - -body { - margin: 0; - font: 400 13px/1.6 var(--mono); - font-variant-ligatures: none; - -webkit-font-smoothing: antialiased; - transition: background-color 200ms ease, color 200ms ease; -} - -::selection { - background: color-mix(in srgb, var(--blue) 35%, var(--bg)); - color: var(--fg); -} - -a { - color: inherit; - text-decoration-line: underline; - text-decoration-thickness: 1px; - text-decoration-color: var(--faint); - text-underline-offset: 0.2em; -} - -a:hover { - text-decoration-color: currentColor; -} - -button, -input, -output, -select { - font: inherit; - color: inherit; -} - -button { - cursor: pointer; -} - -:focus-visible { - outline: 1px solid var(--fg); - outline-offset: 2px; -} - -kbd { - font: inherit; - font-size: 0.95em; - padding: 0 0.45ch; - border: 1px solid var(--faint); - border-radius: 3px; -} - -code { - font-family: var(--mono); - font-size: 0.95em; -} - -.dim { - color: var(--dim); -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - overflow: hidden; - clip-path: inset(50%); - white-space: nowrap; -} - -.skip { - position: absolute; - left: 8px; - top: -100px; - z-index: 50; - padding: 6px 12px; - background: var(--fg); - color: var(--bg); -} - -.skip:focus { - top: 8px; -} - -.btn { - display: inline-flex; - align-items: center; - min-height: 30px; - padding: 0 14px; - border: 1px solid var(--faint); - border-radius: 0; - background: none; - font-size: 12px; - line-height: 1; - white-space: nowrap; -} - -.btn:hover { - border-color: var(--fg); -} - -.btn[aria-pressed="true"] { - border-color: var(--fg); - background: var(--fg); - color: var(--bg); -} - -/* ───────────────────────────── top line ───────────────────────────── */ - -.top { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 20; - display: flex; - align-items: center; - gap: 3ch; - height: var(--top-h); - padding: 0 var(--gutter); - font-size: 12px; - border-bottom: 1px solid transparent; - transition: background-color 200ms ease, border-color 200ms ease; -} - -.is-scrolled .top { - background: color-mix(in srgb, var(--bg) 90%, transparent); - border-bottom-color: var(--rule); - -webkit-backdrop-filter: blur(10px); - backdrop-filter: blur(10px); -} - -.brand { - display: inline-flex; - align-items: center; - gap: 1.5ch; - margin-right: auto; - text-decoration: none; -} - -.logo { - width: 22px; - height: 11px; - overflow: visible; - fill: none; - stroke: currentColor; - stroke-width: 1.6; -} - -.nav { - display: flex; - gap: 2.5ch; -} - -.nav a { - color: var(--dim); - text-decoration: none; -} - -.nav a:hover, -.nav a[aria-current="true"] { - color: var(--fg); -} - -.nav a[aria-current="true"] { - text-decoration: underline; - text-decoration-color: var(--fg); - text-underline-offset: 6px; -} - -.theme-key, -.menu-key { - padding: 8px 0; - border: 0; - background: none; - color: var(--dim); - font-size: 12px; -} - -.theme-key:hover, -.menu-key:hover { - color: var(--fg); -} - -.menu-key { - display: none; -} - -/* ───────────────────────────── hero: the computer ───────────────────────────── */ - -.hero { - display: grid; - grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); - gap: 32px clamp(32px, 4vw, 64px); - align-items: center; - min-height: 100vh; - min-height: 100svh; - padding: calc(var(--top-h) + 28px) var(--gutter) calc(var(--frame-h) + 32px); - max-width: 1440px; - margin: 0 auto; -} - -.hero-name { - margin: 0 0 20px -0.04em; - font: 400 clamp(46px, 6.4vw, 96px)/0.94 var(--serif); - letter-spacing: -0.015em; -} - -/* On load the name decodes itself (js/decode.js): each letter starts as a byte - with a few bits flipped and changes one bit at a time until it is right. */ - -.boot .hero-name { - visibility: hidden; - animation: boot-failsafe 0s 2.5s forwards; -} - -@keyframes boot-failsafe { - to { visibility: visible; } -} - -/* each letter sits in a box as wide as the final letter, and whatever - character it shows is centred in it */ -.hero-name.is-cells .bc { - display: inline-block; - text-align: center; -} - -.hero-name.is-cells .bc-ch { - display: inline-block; - margin-inline: -1em; - white-space: pre; -} - -.bc-word { - white-space: nowrap; -} - -/* a wrong byte shows as a raw character in the mono face */ -.bc.is-wrong { - color: var(--dim); -} - -.bc.is-wrong .bc-ch { - font-family: var(--mono); - font-size: 0.78em; - letter-spacing: 0; -} - -.hero-lede { - max-width: 44ch; - margin: 0 0 20px; - font-size: 14px; - line-height: 1.6; -} - -.legend { - display: flex; - flex-wrap: wrap; - gap: 4px 2.5ch; - margin: 0; - padding: 0; - list-style: none; - font-size: 12px; - color: var(--dim); -} - -.legend li::before, -.features li::before { - content: ""; - display: inline-block; - width: 7px; - height: 7px; - margin-right: 1ch; - background: var(--c, var(--fg)); - vertical-align: 0.06em; -} - -/* landing: the MN-2026 pinout */ - -.hero-chip { - justify-self: center; - width: min(100%, 460px); -} - -.hero-chip .chip { - grid-template-columns: minmax(0, 1fr) 128px minmax(0, 1fr); - font-size: 13px; -} - -.hero-chip .pin { - height: 34px; -} - -.hero-chip .pin .leg { - height: 9px; -} - -.hero-chip .pin-readout { - min-height: 6.5em; -} - -/* the 8-bit computer, as the project's demo */ - -.demo-wide { - margin-top: 40px; - padding-top: 28px; - border-top: 1px solid var(--rule); -} - -.sim-bar { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 10px 10px; - margin-top: 16px; - font-size: 12px; -} - -.sim-field { - display: inline-flex; - align-items: center; - gap: 1.2ch; - margin-left: 1.5ch; - color: var(--dim); -} - -.sim-field output { - min-width: 7ch; - color: var(--fg); - font-variant-numeric: tabular-nums; -} - -select { - min-height: 30px; - padding: 0 28px 0 10px; - border: 1px solid var(--faint); - border-radius: 0; - background: var(--bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23888'/%3E%3C/svg%3E") no-repeat right 10px center; - color: var(--fg); - font-size: 12px; - -webkit-appearance: none; - appearance: none; -} - -input[type="range"] { - width: 120px; - height: 22px; - margin: 0; - background: transparent; - -webkit-appearance: none; - appearance: none; -} - -input[type="range"]::-webkit-slider-runnable-track { - height: 1px; - background: var(--faint); -} - -input[type="range"]::-moz-range-track { - height: 1px; - background: var(--faint); -} - -input[type="range"]::-webkit-slider-thumb { - width: 9px; - height: 18px; - margin-top: -9px; - border: 0; - border-radius: 0; - background: var(--fg); - -webkit-appearance: none; - appearance: none; -} - -input[type="range"]::-moz-range-thumb { - width: 9px; - height: 18px; - border: 0; - border-radius: 0; - background: var(--fg); -} - -.sim-note { - max-width: 78ch; - margin: 12px 0 0; - font-size: 12px; - line-height: 1.6; - color: var(--dim); -} - -/* board: Ben Eater's layout, two columns of modules either side of the bus */ - -.board { - --led: 10px; - display: grid; - grid-template-columns: minmax(0, 1fr) 64px minmax(0, 1fr); - grid-template-areas: - "left bus right" - "ctrl ctrl ctrl"; - gap: 10px; - font-size: 11.5px; - font-variant-numeric: tabular-nums; -} - -.col { - display: flex; - flex-direction: column; - gap: 10px; -} - -.col-l { grid-area: left; } -.col-r { grid-area: right; } - -.mod { - padding: 7px 10px 9px; - border: 1px solid var(--rule); - background: color-mix(in srgb, var(--bg) 92%, var(--fg)); -} - -.mod.is-out { - border-color: var(--red); -} - -.mod.is-in { - border-color: var(--green); -} - -.mod-head { - display: flex; - align-items: baseline; - gap: 1ch; - margin-bottom: 6px; - color: var(--dim); - white-space: nowrap; -} - -.mod-name { - margin-right: auto; - overflow: hidden; - text-overflow: ellipsis; -} - -.sig { - padding: 0 0.4ch; - border-radius: 2px; - color: var(--faint); - font-size: 10.5px; -} - -.sig.on { - background: var(--blue); - color: var(--bg); -} - -.mod-body { - display: flex; - align-items: center; - justify-content: space-between; - gap: 1ch; -} - -.mod-val { - color: var(--fg); - white-space: nowrap; -} - -.leds { - display: flex; - gap: calc(var(--led) * 0.45); -} - -.led { - display: block; - flex: none; - width: var(--led); - height: var(--led); - padding: 0; - border: 0; - border-radius: 50%; - background: var(--led-off); - --lc: var(--red); -} - -.led.on { - background: var(--lc); - box-shadow: 0 0 calc(var(--glow) * 7px) calc(var(--glow) * 1px) color-mix(in srgb, var(--lc) 70%, transparent); -} - -.led.g { --lc: var(--green); } -.led.y { --lc: var(--yellow); } -.led.b { --lc: var(--blue); } - -.leds .gap { - width: calc(var(--led) * 0.4); -} - -/* RAM: the whole 16-byte memory as a matrix you can edit */ - -.ram-rows { - display: grid; - gap: 1px; -} - -.ram-row { - --led: 8px; - display: grid; - grid-template-columns: 1.5ch 2ch auto minmax(0, 1fr); - align-items: center; - gap: 0.8ch; - padding: 1px 4px; - margin: 0 -4px; - line-height: 14px; -} - -.ram-row.is-mar { - background: var(--hl); -} - -.ram-row .pc { - color: var(--green); -} - -.ram-row .addr { - color: var(--dim); -} - -.ram-row .dis { - overflow: hidden; - color: var(--dim); - white-space: nowrap; - text-overflow: ellipsis; -} - -.ram-row.is-mar .dis { - color: var(--fg); -} - -.ram-row .led { - cursor: pointer; -} - -.ram-row .led:hover { - outline: 1px solid var(--faint); - outline-offset: 1px; -} - -/* the bus: eight lanes down the middle */ - -.bus { - grid-area: bus; - display: flex; - flex-direction: column; - align-items: center; - padding: 7px 0 9px; - border: 1px solid var(--rule); -} - -.bus .mod-head { - margin-bottom: 4px; -} - -.bus-val { - margin-bottom: 8px; -} - -.lanes { - display: flex; - flex: 1; - gap: 4px; -} - -.lane { - width: 2px; - background: var(--led-off); -} - -.lane.on { - background: var(--red); - box-shadow: 0 0 calc(var(--glow) * 6px) color-mix(in srgb, var(--red) 70%, transparent); -} - -/* output: a 7-segment display */ - -.seg7 { - display: flex; - gap: 6px; -} - -.seg7 svg { - width: 22px; - height: 38px; - overflow: visible; -} - -.seg7 path { - fill: var(--led-off); -} - -.seg7 path.on { - fill: var(--red); - filter: drop-shadow(0 0 calc(var(--glow) * 3px) color-mix(in srgb, var(--red) 80%, transparent)); -} - -.mod-out .mod-body { - cursor: pointer; -} - -/* control word */ - -.ctrl { - grid-area: ctrl; -} - -.ctrl-row { - display: flex; - flex-wrap: wrap; - align-items: flex-end; - gap: 8px 18px; -} - -.cw { - display: flex; - flex-wrap: wrap; - gap: 4px; -} - -.cw-bit { - display: flex; - flex-direction: column; - align-items: center; - gap: 3px; - width: 3.4ch; - color: var(--faint); - font-size: 10px; -} - -.cw-bit.on { - color: var(--fg); -} - -.ustep { - margin-top: 8px; - color: var(--dim); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.ustep b { - color: var(--fg); - font-weight: 600; -} - -/* ───────────────────────────── sections ───────────────────────────── */ - -.sec { - max-width: var(--col); - margin: 0 auto; - padding: 136px var(--gutter) 0; -} - -.hero, -.sec > .winbar { - scroll-snap-align: start; -} - -.winbar { - display: flex; - align-items: center; - gap: 1.5ch; - margin: 0 0 56px; - font-size: 12px; - line-height: 1; - color: var(--dim); -} - -.winbar .file { - color: var(--fg); -} - -.winbar .rule { - flex: 1; - height: 1px; - background: var(--rule); -} - -.h2 { - max-width: 17em; - margin: 0 0 20px; - font: 400 clamp(36px, 5.4vw, 62px)/1.04 var(--serif); - letter-spacing: -0.01em; -} - -.lede, -.prose { - max-width: 34em; - margin: 0 0 48px; - font: 400 19px/1.55 var(--serif); -} - -.prose { - margin-bottom: 0; -} - -.lede kbd { - font: 400 13px/1 var(--mono); - vertical-align: 0.15em; -} - -.sub-h { - margin: 72px 0 8px; - font: 400 28px/1.15 var(--serif); -} - -.sub-p { - max-width: 34em; - margin: 0 0 28px; - font: 400 17px/1.55 var(--serif); -} - -/* ───────────────────────────── datasheet ───────────────────────────── */ - -.ds-head { - display: grid; - grid-template-columns: 14ch minmax(0, 1fr); - gap: 8px 2ch; - align-items: baseline; - padding-top: 16px; - border-top: 2px solid var(--fg); -} - -.ds-part { - margin: 0; - font-weight: 600; - font-size: 15px; -} - -.ds-title { - max-width: 19em; - margin: 0; - font: 400 clamp(28px, 3.8vw, 44px)/1.1 var(--serif); -} - -.ds-grid { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(0, 400px); - gap: 72px; - align-items: start; -} - -.ds-desc { - margin: 40px 0 0; -} - -.ds-h { - margin: 48px 0 16px; - font-size: 12px; - font-weight: 600; - line-height: 1.4; -} - -.features { - margin: 0; - padding: 0; - list-style: none; -} - -.features li { - max-width: 62ch; - margin-bottom: 8px; - padding-left: 3ch; - text-indent: -3ch; -} - -.features li::before { - margin-right: 2ch; - text-indent: 0; -} - -.pinout { - margin: 0; -} - -.chip { - display: grid; - grid-template-columns: minmax(0, 1fr) 104px minmax(0, 1fr); - font-size: 12px; -} - -.chip-side { - display: flex; - flex-direction: column; - padding: 10px 0; -} - -.chip-body { - position: relative; - border: 1px solid var(--fg); - border-radius: 2px; -} - -.chip-body::before { - content: ""; - position: absolute; - top: -1px; - left: 50%; - width: 20px; - height: 10px; - border: 1px solid var(--fg); - border-top: 0; - border-radius: 0 0 10px 10px; - background: var(--bg); - transform: translateX(-50%); -} - -.chip-body span { - position: absolute; - inset: 0; - display: flex; - align-items: center; - justify-content: center; - color: var(--dim); - writing-mode: vertical-rl; - letter-spacing: 0.2em; -} - -.pin { - display: grid; - align-items: center; - height: 28px; - padding: 0; - border: 0; - background: none; - color: var(--dim); - text-align: left; -} - -.chip-side.left .pin { - grid-template-columns: 1fr 3ch 16px; - text-align: right; -} - -.chip-side.right .pin { - grid-template-columns: 16px 3ch 1fr; -} - -.pin .num { - text-align: center; - font-size: 11px; -} - -.pin .leg { - height: 8px; - border: 1px solid var(--faint); -} - -.chip-side.left .leg { - border-right: 0; -} - -.chip-side.right .leg { - border-left: 0; -} - -.pin .name { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.pin:hover, -.pin.is-active { - color: var(--fg); -} - -.pin.is-active .name { - color: var(--c, var(--fg)); - font-weight: 600; -} - -.pin.is-active .leg { - border-color: var(--c, var(--fg)); - background: var(--c, var(--fg)); -} - -.pin-readout { - min-height: 7.5em; - margin-top: 20px; - padding-top: 12px; - border-top: 1px solid var(--rule); - font-size: 12px; -} - -.pin-readout p { - margin: 0; -} - -.pin-readout .pr-head { - display: flex; - gap: 2ch; - margin-bottom: 6px; -} - -.pin-readout .pr-name { - color: var(--c, var(--fg)); - font-weight: 600; -} - -.pinout figcaption { - margin-top: 8px; - font-size: 12px; - color: var(--dim); -} - -.pin-list { - margin: 16px 0 0; - padding-left: 3ch; - font-size: 12px; -} - -.pinout.is-built .pin-list { - display: none; -} - -.pin-list li::before { - content: attr(data-name) " (" attr(data-type) ") "; - font-weight: 600; -} - -.ds-note { - margin: -8px 0 14px; - font-size: 12px; - color: var(--dim); -} - -.table-scroll { - overflow-x: auto; -} - -.ds-table { - width: 100%; - min-width: 560px; - border-collapse: collapse; - font-size: 12.5px; - font-variant-numeric: tabular-nums; -} - -.ds-table th, -.ds-table td { - padding: 8px 1.5ch 8px 0; - border-bottom: 1px solid var(--rule); - text-align: left; - vertical-align: baseline; -} - -.ds-table thead th { - border-top: 1px solid var(--fg); - border-bottom-color: var(--fg); - font-weight: 600; -} - -.ds-table tbody th { - font-weight: 400; -} - -.ds-table td:nth-child(2) { - color: var(--dim); -} - -.ds-table .num { - text-align: right; - padding-right: 3ch; -} - -/* experience as git log --graph --color */ - -.gitlog-cmd { - margin-bottom: 12px; - font-weight: 400; - color: var(--fg); - line-height: 1.5; - white-space: pre-wrap; - overflow-wrap: anywhere; -} - -.gitlog-cmd .prompt { - color: var(--green); -} - -.gitlog { - padding: 16px 18px; - overflow-x: auto; - border: 1px solid var(--rule); - font-size: 12px; - line-height: 1.7; - color: var(--fg); -} - -.gl-line { - width: max-content; - white-space: pre; -} - -/* one colour per branch */ -.gitlog .lm { color: var(--magenta); } /* main */ -.gitlog .lu { color: var(--green); } /* undergrad */ -.gitlog .lt { color: var(--yellow); } /* teaching-assistant */ -.gitlog .lb { color: var(--red); } /* bbd-software */ -.gitlog .li { color: var(--blue); } /* mwr-internship */ - -.gl-tip { - color: var(--fg); - font-weight: 600; -} - -.gl-refs { - color: var(--yellow); -} - -.gl-head { - color: var(--cyan); - font-weight: 600; -} - -.gl-branch { - color: var(--green); - font-weight: 600; -} - -.gl-author { - color: var(--blue); -} - -.gl-subj { - padding: 0; - border: 0; - background: none; - color: inherit; - font: inherit; - white-space: pre; - text-decoration: underline dotted; - text-decoration-color: var(--faint); - text-underline-offset: 0.25em; -} - -.gl-subj:hover, -.gl-subj[aria-expanded="true"] { - text-decoration-style: solid; - text-decoration-color: currentColor; -} - -.gl-body, -.gl-desc { - color: var(--dim); -} - -/* before the script runs (or without it), descriptions show under their commit */ -.gl-desc { - display: block; - padding-left: 4ch; -} - -.gitlog-hint { - margin: 8px 0 0; - font-size: 12px; -} - -/* ───────────────────────────── memory map ───────────────────────────── */ - -.mm { - --mm-cols: 8ch 8ch minmax(0, 1fr) 8ch; -} - -.mm-bar { - display: flex; - height: 36px; - margin-bottom: 32px; - border: 1px solid var(--rule); -} - -.mm-seg { - min-width: 3px; - padding: 0 6px; - overflow: hidden; - border-right: 1px solid var(--bg); - background: color-mix(in srgb, var(--c) 20%, transparent); - box-shadow: inset 0 2px 0 var(--c); - font-size: 11px; - line-height: 34px; - white-space: nowrap; - cursor: pointer; - transition: background-color 120ms ease; -} - -.mm-seg:last-child { - border-right: 0; -} - -.mm-seg:hover { - background: color-mix(in srgb, var(--c) 34%, transparent); -} - -.mm-seg.is-active { - background: var(--c); - color: var(--bg); -} - -.mm-cols { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); - gap: 48px; - align-items: start; -} - -.mm-head { - display: grid; - grid-template-columns: var(--mm-cols); - gap: 1.5ch; - margin: 0; - padding: 0 0 8px 12px; - border-bottom: 1px solid var(--rule); - font-size: 12px; - color: var(--dim); -} - -.mm-list { - margin: 0; - padding: 0; - list-style: none; -} - -.proj-name { - margin: 0; - font: inherit; -} - -.proj-row { - display: grid; - grid-template-columns: var(--mm-cols); - gap: 1.5ch; - align-items: baseline; - width: 100%; - padding: 11px 0 11px 12px; - border: 0; - border-bottom: 1px solid var(--rule); - background: none; - text-align: left; - font-size: 13px; - font-variant-numeric: tabular-nums; -} - -.proj-row:hover { - background: var(--wash); -} - -.proj-row .o, -.proj-row .l, -.proj-row .y { - font-size: 12px; - color: var(--dim); -} - -.proj-row .n { - font-weight: 600; -} - -.proj-row .n::before { - content: ""; - display: inline-block; - width: 7px; - height: 7px; - margin-right: 1.2ch; - background: var(--c); - vertical-align: 0.06em; -} - -.proj-row .s { - display: block; - margin-top: 2px; - font-weight: 400; - color: var(--dim); -} - -.proj-row[aria-pressed="true"] { - background: var(--wash); - box-shadow: inset 2px 0 0 var(--c); -} - -.proj-row[aria-pressed="true"] .o, -.proj-row[aria-pressed="true"] .l { - color: var(--c); -} - -.mm.is-built .proj-sum, -.mm.is-built .proj > .proj-body { - display: none; -} - -.mm-detail { - min-height: 320px; - padding-left: 32px; - border-left: 1px solid var(--rule); -} - -.mm-detail:empty { - display: none; -} - -.hex { - margin: 0 0 22px; - overflow-x: auto; - font-size: 11.5px; - line-height: 1.55; - color: var(--dim); - white-space: pre; -} - -.hex .a { - color: var(--fg); -} - -.hex .addr { - color: var(--c); -} - -.mm-detail h3 { - margin: 0 0 14px; - font: 400 32px/1.1 var(--serif); -} - -.mm-detail .proj-body p { - margin: 0 0 14px; - font: 400 17px/1.55 var(--serif); -} - -.mm-detail .proj-body .proj-stack, -.mm-detail .proj-body .proj-links { - font: 400 12px/1.6 var(--mono); -} - -.proj-stack { - color: var(--dim); -} - -.proj-links a { - margin-right: 2ch; -} - -/* project demos */ - -.demo { - margin-top: 22px; - padding-top: 18px; - border-top: 1px solid var(--rule); - font-size: 12px; -} - -.demo-bar { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 8px; - margin-bottom: 12px; -} - -.demo-bar .dim { - margin-left: auto; -} - -.demo canvas { - display: block; - width: 100%; -} - -.demo pre { - margin: 0; - font-size: 12px; - line-height: 1.2; - user-select: none; - -webkit-user-select: none; -} - -.demo .cap { - margin: 10px 0 0; - color: var(--dim); -} - -.bc-input { - display: flex; - align-items: center; - gap: 1ch; - margin-bottom: 12px; -} - -.bc-input input { - flex: 1; - min-width: 0; - min-height: 30px; - padding: 0 10px; - border: 1px solid var(--faint); - border-radius: 0; - background: none; - font-size: 13px; -} - -.bc-input input:focus { - border-color: var(--fg); - outline: none; -} - -.bc-cols { - display: grid; - grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); - gap: 16px; -} - -.bc-code { - margin: 0; - padding: 0; - list-style: none; - font-variant-numeric: tabular-nums; -} - -.bc-code li { - display: grid; - grid-template-columns: 4ch 1fr; - gap: 1ch; - padding: 1px 6px; -} - -.bc-code li.is-pc { - background: var(--hl); -} - -.bc-code .off { - color: var(--dim); - text-align: right; -} - -.bc-code .op { - color: var(--blue); -} - -.bc-stack { - display: flex; - flex-direction: column-reverse; - justify-content: flex-start; - gap: 2px; - min-height: 120px; - padding: 6px; - border: 1px solid var(--rule); - border-top: 0; -} - -.bc-stack span { - padding: 2px 8px; - border: 1px solid var(--faint); - text-align: right; -} - -.bc-stack span:last-child { - border-color: var(--fg); -} - -.bc-err { - color: var(--red); - white-space: pre; -} - -/* othello */ - -.oth { - display: grid; - grid-template-columns: repeat(8, minmax(0, 1fr)); - gap: 2px; - width: min(100%, 336px); - aspect-ratio: 1; - padding: 2px; - background: color-mix(in srgb, var(--fg) 25%, var(--bg)); -} - -.oth-cell { - position: relative; - padding: 0; - border: 0; - border-radius: 0; - background: color-mix(in srgb, var(--green) 28%, var(--bg)); - cursor: default; -} - -.oth-cell.legal { - cursor: pointer; -} - -.oth-cell.legal::after { - content: ""; - position: absolute; - inset: 40%; - border-radius: 50%; - background: var(--fg); - opacity: 0.4; -} - -.oth-cell.last { - box-shadow: inset 0 0 0 2px var(--yellow); -} - -.oth-cell .disc { - position: absolute; - inset: 12%; - border-radius: 50%; -} - -.oth-cell .disc.b { - background: #1b1b1b; - box-shadow: 0 0 0 1px rgb(0 0 0 / 0.35); -} - -.oth-cell .disc.w { - background: #f1efe8; - box-shadow: 0 0 0 1px rgb(0 0 0 / 0.15); -} - -.oth-cell .heat { - position: absolute; - inset: 0; - z-index: 1; - display: flex; - align-items: center; - justify-content: center; - background: color-mix(in srgb, var(--blue) var(--hp, 0%), transparent); - color: var(--fg); - font-size: 10px; -} - -.oth-cell .heat:empty { - background: none; -} - -/* rbudp */ - -.rb-canvas { - height: 200px; -} - -.rb-log { - max-height: 9.8em; - margin: 10px 0 0; - padding: 8px 10px; - overflow-y: auto; - border: 1px solid var(--rule); - list-style: none; - font-size: 11.5px; - line-height: 1.6; -} - -.rb-log li { - display: grid; - grid-template-columns: 8ch 5ch minmax(0, 1fr); - gap: 1ch; -} - -.rb-proto { - color: var(--cyan); -} - -.sched-legend { - display: flex; - flex-wrap: wrap; - gap: 4px 12px; - margin-top: 8px; - color: var(--dim); -} - -/* ───────────────────────────── posts: an Org buffer ───────────────────────────── */ - -.org { - max-width: 880px; - font-size: 13px; - line-height: 1.75; -} - -.org-kw { - margin: 0; - font: inherit; - color: var(--dim); -} - -.org-kw .v { - color: var(--fg); -} - -.org-title { - color: var(--fg); - font-weight: 600; -} - -.org-p { - max-width: 76ch; - margin: 20px 0 0; - font-size: 13px; - line-height: 1.75; -} - -.org > .org-tree { - margin-top: 20px; -} - -.org-tree { - margin: 0; - padding: 0; - list-style: none; -} - -.org-h { - display: flex; - align-items: baseline; - gap: 1ch; -} - -.org-h:focus-visible { - outline: none; - background: var(--hl); -} - -.org-stars { - flex: none; - padding: 0; - border: 0; - background: none; - color: inherit; - font: inherit; -} - -.org-h1 > .org-h { - color: var(--blue); - font-weight: 600; -} - -.org-h2 > .org-h { - color: var(--magenta); -} - -.org-h2 a { - min-width: 0; - color: inherit; - text-decoration: none; -} - -.org-h2 a:hover { - text-decoration: underline; - text-decoration-thickness: 1px; -} - -.org-h .count, -.org-ellipsis { - color: var(--dim); - font-weight: 400; -} - -.org-tags { - flex: none; - margin-left: auto; - padding-left: 2ch; - color: var(--dim); - white-space: nowrap; -} - -.org-tags .t { - color: var(--tag, var(--dim)); -} - -.org-drawer { - margin: 0 0 6px 3ch; - overflow-x: auto; - color: var(--dim); - font-size: 12px; - line-height: 1.6; - white-space: pre; -} - -.org-drawer .k { - color: var(--faint); -} - -.org-drawer .ts { - color: var(--cyan); -} - -.org-drawer a { - color: var(--fg); -} - -/* ───────────────────────────── contact ───────────────────────────── */ - -.contact { - display: flex; - flex-wrap: wrap; - align-items: baseline; - gap: 16px 32px; - margin-bottom: 8px; -} - -.mail { - font: 400 clamp(26px, 4.4vw, 52px)/1.1 var(--serif); - overflow-wrap: anywhere; -} - -.mail .at { - font: 400 0.42em/1 var(--mono); - color: var(--dim); - vertical-align: 0.35em; - white-space: pre; -} - -.linkish { - padding: 0; - border: 0; - background: none; - color: inherit; - font: inherit; - text-decoration: underline; - text-decoration-thickness: 1px; - text-decoration-color: var(--faint); - text-underline-offset: 0.2em; -} - -.linkish:hover { - text-decoration-color: currentColor; -} - -.contact-grid { - display: grid; - grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); - gap: 0 56px; -} - -.gpg-fp { - display: flex; - flex-wrap: wrap; - gap: 4px 2ch; - margin: 0 0 12px; -} - -.gpg-fp code { - letter-spacing: 0.02em; -} - -.gpg-cmd { - display: flex; - align-items: stretch; - gap: 8px; -} - -.gpg-cmd pre { - flex: 1; - min-width: 0; - margin: 0; - padding: 7px 12px; - overflow-x: auto; - border: 1px solid var(--rule); - background: var(--wash); - font-size: 12px; -} - -.elsewhere { - display: flex; - flex-wrap: wrap; - gap: 8px 3ch; - margin: 0; - padding: 0; - list-style: none; -} - -.ctf { - max-width: 70ch; - margin-top: 16px; -} - -.ctf p { - margin: 0 0 12px; -} - -.ctf-row { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 12px 2ch; -} - -.ctf-progress { - color: var(--dim); -} - -.ctf-progress.done { - color: var(--green); -} - -.foot { - max-width: var(--col); - margin: 0 auto; - padding: 160px var(--gutter) calc(var(--frame-h) + 48px); - font-size: 12px; -} - -.foot p { - margin: 0 0 4px; -} - -/* ───────────────────────────── modeline, minibuffer, which-key ───────────────────────────── */ - -.frame-bottom { - position: fixed; - left: 0; - right: 0; - bottom: 0; - z-index: 30; - padding-bottom: env(safe-area-inset-bottom, 0px); - background: var(--bg); - font-size: 12px; - white-space: nowrap; -} - -.modeline { - display: flex; - align-items: stretch; - height: 24px; - line-height: 24px; - background: var(--bg-alt); - color: var(--fg); -} - -/* doom-modeline's bar */ -.modeline::before { - content: ""; - flex: none; - width: 4px; - background: var(--blue); -} - -.modeline > span { - padding: 0 1ch; -} - -.ml-evil { - color: var(--green); - font-weight: 600; -} - -.modeline[data-evil="I"] .ml-evil { color: var(--yellow); } -.modeline[data-evil="V"] .ml-evil { color: var(--magenta); } -.modeline[data-evil="E"] .ml-evil { color: var(--cyan); } - -.ml-buf { - font-weight: 600; -} - -.ml-pos, -.ml-pct, -.ml-enc, -.ml-time { - color: var(--dim); -} - -.ml-spacer { - flex: 1; - padding: 0 !important; -} - -.ml-flags { - color: var(--green); -} - -.ml-mode { - color: var(--blue); - font-weight: 600; -} - -.ml-vc { - color: var(--green); -} - -.echo { - height: 22px; - padding: 0 1ch; - overflow: hidden; - line-height: 22px; - color: var(--dim); - text-overflow: ellipsis; -} - -.echo.is-error { - color: var(--red); -} - -.echo.is-ok { - color: var(--green); -} - -.mini:not([hidden]) ~ .echo { - display: none; -} - -.mini-prompt { - margin: 0; -} - -.mini-prompt label { - display: flex; - height: 22px; - padding: 0 1ch; - line-height: 22px; -} - -.mini-count { - min-width: 6ch; - color: var(--dim); -} - -.mini-ps { - color: var(--blue); - white-space: pre; -} - -.mini-prompt input { - flex: 1; - min-width: 0; - padding: 0; - border: 0; - outline: 0; - background: none; - color: var(--fg); - caret-color: var(--fg); - font-size: 12px; - line-height: 22px; -} - -.mini-list { - max-height: calc(10 * 21px); - margin: 0; - padding: 0; - overflow-y: auto; - list-style: none; -} - -.mini-list:empty { - display: none; -} - -.mini-list li { - display: flex; - gap: 2ch; - height: 21px; - padding: 0 1ch; - line-height: 21px; - cursor: pointer; -} - -.mini-list li[aria-selected="true"] { - background: var(--hl); -} - -.mini-list .cand { - flex: none; - min-width: 24ch; - color: var(--fg); -} - -.mini-list .cand mark { - background: none; - color: var(--magenta); - font-weight: 600; -} - -.mini-list .ann { - flex: 1; - min-width: 0; - overflow: hidden; - color: var(--dim); - text-overflow: ellipsis; -} - -.mini-list .key { - flex: none; - color: var(--blue); -} - -.which-key { - position: fixed; - left: 0; - right: 0; - bottom: var(--frame-h); - z-index: 29; - display: grid; - grid-template-columns: repeat(auto-fill, minmax(26ch, 1fr)); - gap: 2px 2ch; - padding: 10px 2ch 12px; - border-top: 1px solid var(--rule); - background: var(--bg-alt); - font-size: 12px; -} - -.which-key[hidden] { - display: none; -} - -.wk-title { - grid-column: 1 / -1; - margin-bottom: 4px; - color: var(--dim); -} - -.wk-item { - display: flex; - gap: 1ch; - white-space: nowrap; -} - -.wk-key { - min-width: 3ch; - color: var(--magenta); - font-weight: 600; -} - -.wk-arrow { - color: var(--faint); -} - -.wk-desc { - color: var(--fg); -} - -.wk-desc.group { - color: var(--blue); -} - -/* ───────────────────────────── M-x coffee-refill ───────────────────────────── */ - -.coffee { - position: fixed; - right: 2ch; - bottom: calc(var(--frame-h) + 12px); - z-index: 28; - display: flex; - gap: 3ch; - width: min(620px, calc(100% - 4ch)); - padding: 16px 20px 18px; - border: 1px solid var(--faint); - background: var(--bg); - box-shadow: 0 12px 40px rgb(0 0 0 / 0.35); - font-size: 12px; -} - -.coffee[hidden] { - display: none; -} - -.mug { - flex: none; - margin: 0; - font-size: 12px; - line-height: 1.25; - color: var(--fg); -} - -.mug .steam { - color: var(--dim); -} - -.mug .brew { - color: var(--orange); -} - -.mug .crema { - color: var(--yellow); -} - -.coffee-info { - flex: 1; - min-width: 0; -} - -.coffee-info .winbar { - margin: 0 28px 14px 0; -} - -.coffee-info p { - margin: 0 0 10px; -} - -.vcc { - display: flex; - gap: 1.5ch; - font-variant-numeric: tabular-nums; -} - -.vbar { - color: var(--green); - letter-spacing: -0.05em; -} - -.coffee.is-over .vbar, -.coffee.is-over .volts { - color: var(--red); -} - -.coffee-msg { - min-height: 3.2em; -} - -.coffee-links { - display: flex; - flex-wrap: wrap; - gap: 4px 2ch; -} - -.coffee-close { - position: absolute; - top: 6px; - right: 8px; - padding: 2px 6px; - border: 0; - background: none; - color: var(--dim); - font-size: 16px; - line-height: 1; -} - -.coffee-close:hover { - color: var(--fg); -} - -/* ───────────────────────────── help ───────────────────────────── */ - -.help { - width: min(780px, calc(100% - 32px)); - max-height: calc(100% - 64px); - padding: 24px 28px; - border: 1px solid var(--faint); - background: var(--bg); - color: var(--fg); - font-size: 12.5px; -} - -.help::backdrop { - background: rgb(0 0 0 / 0.5); -} - -.help .winbar { - margin-bottom: 28px; -} - -.help-cols { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 40px; -} - -.help h3 { - margin: 0 0 12px; - font-size: 12px; - font-weight: 600; -} - -.help dl { - margin: 0; -} - -.help dl div { - display: grid; - grid-template-columns: 13ch 1fr; - gap: 2ch; - padding: 3px 0; -} - -.help dt { - color: var(--fg); -} - -.help dd { - margin: 0; - color: var(--dim); -} - -.help form { - margin-top: 28px; -} - -/* ───────────────────────────── responsive ───────────────────────────── */ - -@media (max-width: 1100px) { - .hero { - grid-template-columns: minmax(0, 1fr); - align-items: start; - } - - .hero-id { - max-width: 640px; - } -} - -@media (max-width: 920px) { - .nav { - display: none; - } - - .nav.is-open { - position: absolute; - top: calc(var(--top-h) - 4px); - right: var(--gutter); - display: flex; - flex-direction: column; - gap: 10px; - min-width: 18ch; - padding: 14px 18px; - border: 1px solid var(--faint); - background: var(--bg); - } - - .menu-key { - display: block; - } - - .ds-grid, - .mm-cols, - .contact-grid { - grid-template-columns: minmax(0, 1fr); - } - - .ds-grid { - gap: 0; - } - - .pinout { - max-width: 420px; - } - - .mm-detail { - min-height: 0; - margin: 4px 0 8px; - padding: 20px 0 20px 12px; - border-left: 0; - border-bottom: 1px solid var(--rule); - } - - .ml-enc, - .ml-vc, - .ml-time, - .ml-pos { - display: none; - } -} - -@media (max-width: 640px) { - .board { - --led: 8px; - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - grid-template-areas: - "bus bus" - "left right" - "ctrl ctrl"; - font-size: 10.5px; - } - - .bus { - flex-direction: row; - gap: 1.5ch; - padding: 6px 10px; - } - - .bus .mod-head, - .bus-val { - margin: 0; - } - - .lanes { - flex-direction: column; - justify-content: center; - height: 26px; - gap: 1px; - } - - .lane { - width: auto; - height: 2px; - } - - .mod { - padding: 6px 8px 8px; - } - - .ram-row { - --led: 6px; - grid-template-columns: 1.5ch 2ch auto; - } - - .ram-row .dis { - display: none; - } - - .seg7 svg { - width: 16px; - height: 28px; - } - - .sim-field { - margin-left: 0; - } - - .sec { - padding-top: 104px; - } - - .winbar { - margin-bottom: 40px; - } - - .lede, - .prose { - font-size: 17px; - } - - .ds-head { - grid-template-columns: minmax(0, 1fr); - } - - .mm { - --mm-cols: 7ch 6ch minmax(0, 1fr); - } - - .mm-head span:last-child, - .proj-row .y { - display: none; - } - - .bc-cols { - grid-template-columns: minmax(0, 1fr); - } - - .gitlog { - padding: 12px; - font-size: 11.5px; - } - - .gitlog-cmd { - font-size: 11.5px; - } - - .org-tags { - display: none; - } - - .help-cols { - grid-template-columns: minmax(0, 1fr); - gap: 24px; - } - - .ml-pct { - display: none; - } - - .coffee { - right: 0; - left: 0; - width: auto; - margin: 0 8px; - flex-direction: column; - gap: 8px; - } -} - -@media (prefers-reduced-motion: reduce) { - html { - scroll-behavior: auto; - } - - *, - *::before, - *::after { - transition: none !important; - } -} diff --git a/index.html b/index.html @@ -1,349 +0,0 @@ -<!doctype html> -<html lang="en" data-theme="doom-gruvbox"> -<head> -<meta charset="utf-8"> -<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> -<title>Michael Neuper</title> -<meta name="description" content="Computer science student at Stellenbosch University. Low-level software, electronics, a little security, and a lot of Emacs."> -<link rel="icon" href="favicon.svg" type="image/svg+xml"> -<link rel="preload" href="fonts/jetbrains-mono-regular.woff2" as="font" type="font/woff2" crossorigin> -<link rel="preload" href="fonts/cm-regular.woff2" as="font" type="font/woff2" crossorigin> -<link rel="stylesheet" href="css/style.css"> -<script> - // Pick the theme before first paint so there is no flash. Keep this list in sync with js/themes.js. - try { - var t = localStorage.getItem("theme"); - var known = /^(doom-gruvbox|doom-gruvbox-light|doom-one|atom-one-dark|modus-vivendi|modus-operandi|doom-dracula|doom-nord|catppuccin|doom-tokyo-night|doom-solarized-light)$/; - if (!known.test(t || "")) t = matchMedia("(prefers-color-scheme: light)").matches ? "doom-gruvbox-light" : ""; - if (t) document.documentElement.dataset.theme = t; - } catch (e) {} - // Hide the name until js/decode.js has cut it into bands, so it never flashes whole first. - // CSS shows it anyway after a moment in case the script never runs. - try { - if (!matchMedia("(prefers-reduced-motion: reduce)").matches && (!location.hash || location.hash === "#top")) { - document.documentElement.classList.add("boot"); - } - } catch (e) {} -</script> -<script type="module" src="js/main.js"></script> -</head> -<!-- Reading the source? Good instinct. flag{view_source_is_recon} --> -<body> -<a class="skip" href="#about">Skip to content</a> - -<header class="top"> - <a class="brand" href="#top" aria-label="Michael Neuper, back to top"> - <svg class="logo" viewBox="0 0 32 16" aria-hidden="true"><path d="M1 14H3V2H9V14H11V2H17V14H20V2H26V14H31"/></svg> - <span>michael neuper</span> - </a> - <nav class="nav" id="nav" aria-label="Sections"> - <a href="#top">pinout</a> - <a href="#about">about</a> - <a href="#projects">projects</a> - <a href="#posts">posts</a> - <a href="#contact">contact</a> - </nav> - <button class="theme-key" type="button" title="SPC h t">load-theme</button> - <button class="menu-key" type="button" aria-expanded="false" aria-controls="nav">menu</button> -</header> - -<main> - - <!-- ─────────────────────────── landing ─────────────────────────── --> - <section class="hero" id="top" data-file="mn-2026.kicad_sym" data-mode="Lisp Data" aria-labelledby="hero-name"> - <div class="hero-id"> - <h1 class="hero-name" id="hero-name">Michael Neuper</h1> - <p class="hero-lede">Computer science student at Stellenbosch University. I like low-level software, electronics and the maths underneath both, and I do almost all of it in Emacs.</p> - <ul class="legend" aria-label="Colour key used across the site"> - <li data-cat="hw">hardware</li> - <li data-cat="sw">software</li> - <li data-cat="math">maths</li> - <li data-cat="sec">security</li> - </ul> - </div> - - <div class="hero-chip"> - <figure class="pinout"> - <div class="chip-wrap"><!-- built from the list below --></div> - <div class="pin-readout" aria-live="polite"><p class="dim">Point at a pin to read its function.</p></div> - <figcaption>Figure 1. MN-2026, DIP-16 package, top view.</figcaption> - <!-- Edit the pins here. data-cat: hw, sw, math or sec. "M-x some-command" in a description becomes a button. --> - <ol class="pin-list"> - <li data-name="VCC" data-type="power">Supply input: coffee. Top it up with M-x coffee-refill.</li> - <li data-name="C" data-type="I/O" data-cat="sw">Most of what I write, from a compiler to terminal toys like a spinning cube and the Game of Life.</li> - <li data-name="ASM" data-type="I/O" data-cat="sw">Assembly, starting with the 8-bit computer’s eleven instructions.</li> - <li data-name="JVM" data-type="output" data-cat="sw">The target of my compiler, so I read javap output for fun.</li> - <li data-name="LINUX" data-type="I/O" data-cat="sw">Daily driver. Dotfiles on GitHub, and posts on packaging formats and turning a window manager into a desktop.</li> - <li data-name="TTL" data-type="I/O" data-cat="hw">74-series logic. The 8-bit computer is dozens of these chips on breadboards.</li> - <li data-name="SEC" data-type="input" data-cat="sec">Security: a consulting internship, a web application assessment, and the habit of asking how things break.</li> - <li data-name="GND" data-type="power">Return path. Sleep, when the config is finished (it is never finished).</li> - <li data-name="RST" data-type="input">Active low. Asserted by a walk without a laptop.</li> - <li data-name="TA" data-type="output" data-cat="hw">Teaching assistant for introductory computer science and computer architecture.</li> - <li data-name="TEX" data-type="output" data-cat="math">Notes, templates and maths typeset in LaTeX, usually from Emacs.</li> - <li data-name="ORG" data-type="I/O" data-cat="sw">Org mode and org-roam for notes, literate configs, and replacing Jupyter.</li> - <li data-name="EMACS" data-type="I/O" data-cat="sw">Doom Emacs, with a literate config of over a thousand lines. Location: ~/.config/emacs/.</li> - <li data-name="MATH" data-type="input" data-cat="math">Project Euler, discrete maths, and modelling things in Python.</li> - <li data-name="CAN" data-type="I/O">CAN bus, the network inside every car. Cars are my one interest that isn’t a computer, mostly.</li> - <li data-name="NC" data-type="no connect">Reserved for the next obsession.</li> - </ol> - </figure> - </div> - </section> - - <!-- ───────────────────────────── datasheet ───────────────────────────── --> - <section class="sec" id="about" data-file="whoami.pdf" data-mode="PDFView"> - <p class="winbar"><span class="file">whoami.pdf</span><span class="rule" aria-hidden="true"></span><span class="meta">revised June 2026</span></p> - - <header class="ds-head"> - <p class="ds-part">MN-2026</p> - <h2 class="ds-title">About</h2> - </header> - - <p class="prose ds-desc">I study computer science at Stellenbosch University and have been a teaching assistant for introductory computer science and computer architecture. I like understanding things all the way down, from a line of C to the gates that run it, and I’m happiest when that ends in something I built: a scheduler, a compiler, or a computer on breadboards. Away from that I’m a linguistics nerd and a free-software advocate.</p> - - <!-- Experience, as the one-line git log that would print it: "<date> - (refs) <subject> <author>". - data-lanes colours each graph character by branch: m main, u undergrad, t teaching-assistant, - b bbd-software, i mwr-internship (the colours are set in css/style.css). data-cont is the graph that continues below a commit, and a - .gl-desc becomes its expandable description. data-branch colours the date; data-tip makes the - * bold for a branch that's still going; data-today swaps in the current month when the page loads. - Without JavaScript this shows as plain text. --> - <h3 class="ds-h gitlog-cmd"><span class="prompt" aria-hidden="true">$ </span>git log --graph --all --color \ - --date=format:'%Y-%m' \ - --format='%ad -%C(auto)%d%C(reset) %s %C(blue)<%an>%C(reset)'</h3> - <div class="gitlog" aria-label="Experience, newest first"> -<div class="gl-line" data-lanes=" b u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="m" data-tip data-today>* | | | 2026-10 - (HEAD -> main)</div> -<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="b" data-tip>| * | | 2026-06 - (bbd-software) Vac Week 2026 <BBD Software><div class="gl-desc">Built an online foosball game: players steer the rods by -tilting their phones, using the gyroscope. Designed and -presented as a full-stack web app with a small team.</div></div> -<div class="gl-line" data-lanes="m b u " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="t" data-tip>| | | * 2026-06 - (teaching-assistant) Teach computer architecture as a TA <Stellenbosch University></div> -<div class="gl-line" data-lanes="m b u t">| | | |</div> -<div class="gl-line" data-lanes="m b u " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="t">| | | * 2026-02 - Teach introductory computer science as a TA <Stellenbosch University></div> -<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="b">| * | | 2025-06 - Vac Week 2025 <BBD Software><div class="gl-desc">Built an online laser tag game: computer vision finds players -in the camera feed and tags them. Designed and presented as a -full-stack web app with a small team.</div></div> -<div class="gl-line" data-lanes="m b u t">| | | |</div> -<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="b">| * | | 2025-01 - Join BBD Software as a bursar <BBD Software><div class="gl-desc">Part of the Bursary & Beyond Programme, which includes the -yearly Vac Weeks.</div></div> -<div class="gl-line" data-lanes="mb u t">|/ | |</div> -<div class="gl-line" data-lanes="m u t">| | |</div> -<div class="gl-line" data-lanes="mi u t">|\ | |</div> -<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m i u t " data-branch="i">| * | | 2024-12 - (mwr-internship) Complete a cybersecurity consultant internship <MWR CyberSec><div class="gl-desc">- Completed cybersecurity training with labs on TryHackMe. -- Assessed a web application end to end, documenting each - vulnerability with its risk and how to fix it. -- Wrote a professional report and presented it, client-style, - to a panel of industry professionals.</div></div> -<div class="gl-line" data-lanes="mi u t">|/ | |</div> -<div class="gl-line" data-lanes="m ut">| |/</div> -<div class="gl-line" data-lanes="m " data-cont="| | " data-cont-lanes="m u " data-branch="u" data-tip>| * 2024-01 - (undergrad) Start an undergraduate degree in computer science <Stellenbosch University></div> -<div class="gl-line" data-lanes="m u">| /</div> -<div class="gl-line" data-lanes="mu">|/</div> -<div class="gl-line" data-lanes=" " data-cont=" " data-cont-lanes=" " data-branch="m">* 2005-06 - Initial commit <Michael Neuper></div> - </div> - <p class="gitlog-hint dim">Click an underlined commit message to read the rest of it.</p> - - </section> - - <!-- ──────────────────────────── memory map ──────────────────────────── --> - <section class="sec" id="projects" data-file="memory.map" data-mode="Fundamental"> - <p class="winbar"><span class="file">memory.map</span><span class="rule" aria-hidden="true"></span><span class="meta" data-mm="meta"></span></p> - <h2 class="h2">Projects</h2> - <p class="lede">Laid out like a linker map: each project is a region in memory holding its one-line summary, and the hexdump shows exactly those bytes. Select one to read about it and try it out.</p> - - <div class="mm"> - <div class="mm-bar" aria-hidden="true"></div> - <div class="mm-cols"> - <div class="mm-table"> - <p class="mm-head" aria-hidden="true"><span>origin</span><span>length</span><span>name</span><span>source</span></p> - <!-- Edit projects here. data-cat: hw, sw, math or sec. data-src: shown in the source column. - data-demo: computer, scheduler, bytecode, othello or rbudp (optional); data-wide gives the - demo the full width under the list. --> - <ol class="mm-list"> - <li class="proj" data-cat="hw" data-src="built" data-demo="computer" data-wide> - <h3 class="proj-name">8-bit-computer</h3> - <p class="proj-sum">Ben Eater's 8-bit breadboard computer, built chip by chip.</p> - <div class="proj-body"> - <p>My most recent finished project: a programmable computer on breadboards, built from 74-series logic chips following Ben Eater’s video series. It has 16 bytes of RAM, an 8-bit bus, and microcode in EEPROMs that drives sixteen control lines.</p> - <p>The simulation below runs the same instruction set and microcode, so you can step through a program one control word at a time.</p> - <p class="proj-stack">74HC logic, EEPROMs, breadboards, a lot of jumper wire</p> - <p class="proj-links"><a href="https://eater.net/8bit">Ben Eater’s series</a></p> - </div> - </li> - <li class="proj" data-cat="sw" data-src="private" data-demo="scheduler"> - <h3 class="proj-name">os-scheduler</h3> - <p class="proj-sum">A multicore operating system scheduler, for a concurrency course.</p> - <div class="proj-body"> - <p>The part of an operating system that decides which process runs on which core, and for how long. I wrote it for a concurrency course, so the source stays private, but the idea fits in a small simulation: processes arrive, wait in a shared ready queue, and get dispatched to cores under first come, first served, round robin or preemptive priority scheduling.</p> - <p class="proj-links dim">Source private (concurrency coursework)</p> - </div> - </li> - <li class="proj" data-cat="sw" data-src="private" data-demo="othello"> - <h3 class="proj-name">othello-mcts</h3> - <p class="proj-sum">An Othello player in C that runs Monte Carlo tree search across MPI processes.</p> - <div class="proj-body"> - <p>The player picks a move by running thousands of random games from the current position and keeping the move that was explored most, using UCT to balance trying new moves against improving promising ones. Each move gets one second.</p> - <p>The project was for a concurrency course, so the next step was to parallelise it with MPI, which I did in three ways: independent search trees combined at the end with <code>MPI_Allreduce</code>, trees that share their statistics every so often, and the same sharing done asynchronously with non-blocking sends. In ten-game matches on four processes, each version beat the one before it, except the asynchronous version, which won half its games against the synchronous one.</p> - <p>You can play a serial version, rewritten in JavaScript for this page, below. While it thinks, each legal move is shaded by how often the search tried it.</p> - <p class="proj-stack">C, MPI, Docker</p> - <p class="proj-links dim">Source private (concurrency coursework)</p> - </div> - </li> - <li class="proj" data-cat="sw" data-src="private" data-demo="bytecode"> - <h3 class="proj-name">jvm-compiler</h3> - <p class="proj-sum">A compiler in C for a custom language that targets the JVM.</p> - <div class="proj-body"> - <p>I wrote it in C for a computer architecture course. It reads a small custom programming language and produces bytecode the Java virtual machine can run. The source stays private, but the last stage is easy to show: the JVM is a stack machine, so an expression compiles to instructions that push and pop an operand stack. Type one below to see the bytecode and run it.</p> - <p class="proj-stack">C, JVM bytecode</p> - <p class="proj-links dim">Source private (computer architecture coursework)</p> - </div> - </li> - <li class="proj" data-cat="sw" data-src="private" data-demo="rbudp"> - <h3 class="proj-name">chat-voip-p2p</h3> - <p class="proj-sum">Four networking projects in Java: chat, fast UDP file transfer, voice calls and P2P sharing.</p> - <div class="proj-body"> - <p>A series of networking projects built with my group for a university course:</p> - <ul> - <li>A chat server that handles many clients at once, with a JavaFX client, load-tested with dozens of simultaneous users.</li> - <li>File transfer over Reliable Blast UDP, measured against TCP across packet sizes, loss rates and file sizes from 1 to 100 MB.</li> - <li>The chat extended with voice calls and group calls streamed over UDP, plus voice notes.</li> - <li>Peer-to-peer file sharing: a server brokers searches, then peers send files to each other directly over TCP, encrypted with AES-GCM keys exchanged using RSA, with pause and resume. We tested it across four machines over Tailscale.</li> - </ul> - <p>Below is the RBUDP transfer in miniature: blast every packet over UDP, ask over TCP which ones arrived, and resend the gaps.</p> - <p class="proj-stack">Java, JavaFX, TCP and UDP sockets, Java Sound, RSA, AES-GCM</p> - <p class="proj-links dim">Source private (coursework, group project)</p> - </div> - </li> - </ol> - </div> - <article class="mm-detail" aria-live="polite"></article> - </div> - </div> - </section> - - <!-- ────────────────────────────── posts ────────────────────────────── --> - <section class="sec" id="posts" data-file="posts.org" data-mode="Org"> - <p class="winbar"><span class="file">posts.org</span><span class="rule" aria-hidden="true"></span><span class="meta" data-org="meta"></span></p> - <p class="org-p">From my blog at michaelneuper.com, shown the way I read them. <kbd>TAB</kbd> on a heading folds it, <kbd>S-TAB</kbd> cycles the whole buffer, and clicking a heading’s stars does the same.</p> - - <!-- Edit posts here. data-tags are space separated; each tag gets its own colour (see TAG_COLORS in js/org.js). --> - <ol class="posts"> - <li data-date="2024-11-22" data-tags="emacs org" data-cat="sw"><a href="https://michaelneuper.com/posts/how-i-use-org-roam-to-takes-notes-for-cs/">How I Use Org-Roam to Take Notes for CS</a></li> - <li data-date="2023-11-15" data-tags="emacs latex" data-cat="math"><a href="https://michaelneuper.com/posts/efficient-latex-editing-with-emacs/">Efficient LaTeX Editing With Emacs</a></li> - <li data-date="2023-11-12" data-tags="python maths" data-cat="math"><a href="https://michaelneuper.com/posts/modelling-population-growth-in-python/">Modelling Population Growth in Python</a></li> - <li data-date="2023-02-27" data-tags="emacs org" data-cat="sw"><a href="https://michaelneuper.com/posts/replace-jupyter-notebook-with-emacs-org-mode/">Replace Jupyter Notebook With Emacs Org Mode</a></li> - <li data-date="2023-01-09" data-tags="linux" data-cat="sw"><a href="https://michaelneuper.com/posts/what-linux-packaging-format-to-use/">Which Linux Packaging Format Should You Use?</a></li> - <li data-date="2022-12-16" data-tags="linux security" data-cat="sec"><a href="https://michaelneuper.com/posts/enable-monitor-mode-on-tp-link/">Enable Monitor Mode on TP-Link TL-WN722N</a></li> - <li data-date="2022-12-14" data-tags="security c" data-cat="sec"><a href="https://michaelneuper.com/posts/buffer-overflow/">Buffer Overflows: Keep Your Code Safe</a></li> - <li data-date="2022-12-11" data-tags="linux" data-cat="sw"><a href="https://michaelneuper.com/posts/turning-a-window-manager-into-a-desktop-environment/">A Guide to Building Your Own Desktop Environment</a></li> - <li data-date="2022-12-03" data-tags="web" data-cat="sw"><a href="https://michaelneuper.com/posts/how-to-create-your-own-website/">How to Create Your Own Static Website</a></li> - </ol> - </section> - - <!-- ───────────────────────────── contact ───────────────────────────── --> - <section class="sec" id="contact" data-file="*unsent mail*" data-mode="Message"> - <p class="winbar"><span class="file">*unsent mail*</span><span class="rule" aria-hidden="true"></span><span class="meta">draft</span></p> - <h2 class="h2">Say hello</h2> - <p class="lede">Email works best. For anything private, encrypt it with my GPG key below.</p> - - <div class="contact"> - <!-- The address is only ever put together in JavaScript, so scrapers reading this HTML don't see it. - The link and the copy button read data-user and data-host. --> - <a class="mail" href="#contact" data-user="michael" data-host="michaelneuper.com">michael<span class="at"> <at> </span>michaelneuper.com</a> - <button type="button" class="btn" data-email="copy">copy address</button> - </div> - - <div class="contact-grid"> - <div class="gpg"> - <h3 class="ds-h">Encrypt it</h3> - <p class="gpg-fp"><span class="dim">fingerprint</span><code>4E7B F800 0D86 182D F484 5C37 508B CF84 373C 8930</code></p> - <div class="gpg-cmd"> - <pre><code>curl -sL https://michaelneuper.com/michaelneuper.gpg | gpg --import</code></pre> - <button type="button" class="btn" data-copy=".gpg-cmd code">copy</button> - </div> - </div> - <div> - <h3 class="ds-h">Elsewhere</h3> - <ul class="elsewhere"> - <li><a href="https://github.com/michaelneuper">GitHub</a></li> - <li><a href="https://www.linkedin.com/in/michaelneuper/">LinkedIn</a></li> - <li><a href="https://michaelneuper.com">michaelneuper.com</a></li> - <li><a href="https://buymeacoffee.com/michaelneuper" target="_blank" rel="noopener">Buy me a coffee</a></li> - </ul> - </div> - </div> - - <div class="ctf"> - <h3 class="ds-h">Capture the flag</h3> - <p>Three flags are hidden on this site, the kind you would find in a beginner CTF. They look like <code>flag{…}</code>. Found one? Run <kbd>M-x</kbd> <code>submit-flag</code>, or use the button.</p> - <p class="ctf-row"><button type="button" class="btn" data-ctf="submit">submit a flag</button><span class="ctf-progress" aria-live="polite">0 of 3 found</span></p> - </div> - </section> - - <footer class="foot"> - <p>Made with HTML, CSS, JavaScript and Emacs, without a framework, a build step or cookies.</p> - <p class="dim">Press <kbd>SPC</kbd> for commands or <kbd>M-x</kbd> to run one by name.</p> - </footer> -</main> - -<!-- ───────────────────────── coffee, modeline and minibuffer ───────────────────────── --> -<div class="coffee" hidden role="dialog" aria-label="Coffee refill"> - <pre class="mug" aria-hidden="true"></pre> - <div class="coffee-info"> - <p class="winbar"><span class="file">*coffee*</span><span class="rule" aria-hidden="true"></span><span class="meta">q to close</span></p> - <p class="vcc"><span class="dim">VCC</span><span class="vbar" aria-hidden="true"></span><span class="volts">2.6 V</span></p> - <p class="coffee-msg" aria-live="polite">brewing…</p> - <p class="coffee-links"><a href="https://buymeacoffee.com/michaelneuper" target="_blank" rel="noopener">That one was simulated. Buy me an actual coffee</a></p> - </div> - <button type="button" class="coffee-close" aria-label="Close">×</button> -</div> -<div class="which-key" hidden aria-live="polite"></div> -<div class="frame-bottom"> - <div class="modeline"> - <span class="ml-evil" title="evil state"><N></span> - <span class="ml-buf">sap-1.asm</span> - <span class="ml-pos" aria-hidden="true">1:0</span> - <span class="ml-pct" aria-hidden="true">Top</span> - <span class="ml-spacer"></span> - <span class="ml-misc" aria-live="polite"></span> - <span class="ml-flags" aria-hidden="true"></span> - <span class="ml-mode">Asm</span> - <span class="ml-enc" aria-hidden="true">LF UTF-8</span> - <span class="ml-vc" aria-hidden="true">master</span> - <span class="ml-time" aria-hidden="true"></span> - </div> - <div class="mini" hidden> - <form class="mini-prompt" autocomplete="off"> - <label><span class="mini-count"></span><span class="mini-ps"></span><input type="text" spellcheck="false" autocapitalize="off" role="combobox" aria-expanded="true" aria-controls="mini-list" aria-autocomplete="list"></label> - </form> - <ul class="mini-list" id="mini-list" role="listbox"></ul> - </div> - <div class="echo" role="status"></div> -</div> - -<dialog class="help" aria-labelledby="help-title"> - <p class="winbar"><span class="file" id="help-title">*Help*</span><span class="rule" aria-hidden="true"></span><span class="meta">q or esc to close</span></p> - <div class="help-cols"> - <div> - <h3>Keys</h3> - <dl> - <div><dt><kbd>SPC</kbd></dt><dd>leader key: shows every command</dd></div> - <div><dt><kbd>M-x</kbd></dt><dd>run a command by name (Alt+x or Option+x)</dd></div> - <div><dt><kbd>SPC h t</kbd></dt><dd>load a theme, with live preview</dd></div> - <div><dt><kbd>:</kbd></dt><dd>evil ex commands, like <code>:q</code></dd></div> - <div><dt><kbd>C-g</kbd></dt><dd>cancel (so does <kbd>esc</kbd>)</dd></div> - </dl> - </div> - <div> - <h3>On this page</h3> - <dl> - <div><dt><kbd>c</kbd> <kbd>n</kbd> <kbd>r</kbd></dt><dd>computer: run or pause, step, reset</dd></div> - <div><dt><kbd>TAB</kbd></dt><dd>fold the Org heading under focus</dd></div> - <div><dt><kbd>S-TAB</kbd></dt><dd>cycle the whole Org buffer</dd></div> - <div><dt><code>coffee-refill</code></dt><dd>top up VCC and overclock the computer</dd></div> - <div><dt><code>submit-flag</code></dt><dd>check a CTF flag</dd></div> - </dl> - </div> - </div> - <form method="dialog"><button class="btn" type="submit">close</button></form> -</dialog> -</body> -</html> diff --git a/js/gitlog.js b/js/gitlog.js @@ -1,226 +0,0 @@ -// Experience as one-line git log --graph output, the "git lg" way: -// <date> - (refs) <subject> <author> -// with the date standing in for the hash and the company as the author. -// -// The rows are plain text in index.html, so they read fine without JavaScript. -// This colours the graph by branch (data-lanes), colours the date, refs and -// author, and turns subjects that have a .gl-desc into buttons that expand it. -// Lanes: m main, u undergrad, t teaching-assistant, b bbd-software, i mwr-internship. -// -// When the log is wider than its box (on a phone), it wraps the way a narrow -// terminal would: at word boundaries, with each wrapped line starting with the -// commit's lane pipes and a short hanging indent. - -import { $, $$ } from "./util.js"; - -const LANE_CLASS = { m: "lm", u: "lu", t: "lt", b: "lb", i: "li" }; -const ROW = /^([|*/\\ ]*?)(\d{4}-\d{2}(?:-\d{2})?) - (?:\(([^)]*)\) ?)?(.*?)(?: ?<([^>]*)>)?$/; -const HANG = 2; - -function el(tag, cls, text) { - const e = document.createElement(tag); - if (cls) e.className = cls; - if (text != null) e.textContent = text; - return e; -} - -// The graph characters, coloured by lane and hidden from screen readers. -// `tip` makes the commit's * bold. -function graph(text, lanes = "", tip = false) { - const g = el("span", "gl-graph"); - g.setAttribute("aria-hidden", "true"); - [...text].forEach((ch, i) => { - const lane = LANE_CLASS[(lanes[i] || " ").trim()]; - if (ch === "*" && tip) g.append(el("span", "gl-tip", ch)); - else g.append(lane && ch.trim() ? el("span", lane, ch) : ch); - }); - return g; -} - -// The HEAD commit is dated with the month the page is viewed in. -function today() { - const d = new Date(); - return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`; -} - -function parse(div) { - const descEl = $(".gl-desc", div); - const body = descEl ? descEl.textContent.replace(/^\n+|\s+$/g, "").split("\n") : null; - descEl?.remove(); - const text = div.textContent.replace(/\s+$/, ""); - const m = ROW.exec(text); - const row = { - graph: m ? m[1] : text, lanes: div.dataset.lanes, cont: div.dataset.cont ?? "", contLanes: div.dataset.contLanes, - tip: "tip" in div.dataset, branch: div.dataset.branch, - }; - if (!m) return row; - return { - ...row, - date: "today" in div.dataset ? today() : m[2], - refs: m[3] ? m[3].split(/,\s*/).map((r) => (r.startsWith("HEAD -> ") ? { head: true, name: r.slice(8) } : { name: r })) : [], - subject: m[4], - author: m[5], - body, - }; -} - -const refsText = (refs) => `(${refs.map((r) => (r.head ? "HEAD -> " : "") + r.name).join(", ")})`; - -// A commit line as words, so it can be wrapped. Each word knows how to draw itself. -function words(row) { - const w = [{ text: row.date, cls: `gl-date ${LANE_CLASS[row.branch] ?? ""}` }, { text: "-" }]; - if (row.refs.length) w.push({ text: refsText(row.refs), refs: row.refs }); - if (row.subject) for (const s of row.subject.split(" ")) w.push({ text: s, subj: true }); - if (row.author) w.push({ text: `<${row.author}>`, cls: "gl-author" }); // kept on one line - return w; -} - -// Greedy word wrap. Returns lines of words; a word longer than the width gets a line to itself. -function wrap(list, width, hang) { - const lines = [[]]; - let used = 0; - for (const w of list) { - const line = lines[lines.length - 1]; - const need = (line.length ? 1 : 0) + w.text.length; - if (line.length && used + need > width) { - lines.push([w]); - used = hang + w.text.length; - } else { - line.push(w); - used += need; - } - } - return lines; -} - -// Re-flow a description to a width, keeping "- " bullets with a hanging indent. -function reflow(body, width) { - const blocks = []; - for (const line of body) { - if (line.startsWith("- ") || !blocks.length || !line.startsWith(" ")) blocks.push(line.trim()); - else blocks[blocks.length - 1] += ` ${line.trim()}`; - } - // plain paragraphs that were hard-wrapped become one block again - const merged = []; - for (const b of blocks) { - if (merged.length && !b.startsWith("- ") && !merged[merged.length - 1].startsWith("- ")) merged[merged.length - 1] += ` ${b}`; - else merged.push(b); - } - const out = []; - for (const b of merged) { - const bullet = b.startsWith("- "); - const lines = wrap(b.split(" ").map((text) => ({ text })), width, bullet ? 2 : 0); - lines.forEach((l, i) => out.push((i && bullet ? " " : "") + l.map((w) => w.text).join(" "))); - } - return out; -} - -export function initGitlog() { - const host = $(".gitlog"); - if (!host) return; - const rows = $$(":scope > .gl-line", host).map(parse); - const open = new Set(); - let lastCols = 0; - - function measureCols() { - const probe = el("span", "", "0".repeat(20)); - probe.style.cssText = "position:absolute;visibility:hidden;white-space:pre"; - host.append(probe); - const ch = probe.getBoundingClientRect().width / 20 || 7; - probe.remove(); - const cs = getComputedStyle(host); - const inner = host.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight); - return Math.max(24, Math.floor(inner / ch)); - } - - function render(focusRow = -1) { - const cols = measureCols(); - lastCols = cols; - const lineLen = (r) => r.graph.length + words(r).reduce((n, w, i) => n + (i ? 1 : 0) + w.text.length, 0); - const wide = rows.every((r) => !r.date || lineLen(r) <= cols); - const pipesOnly = (r) => r && !r.date && /^[| ]+$/.test(r.graph); - const frag = document.createDocumentFragment(); - - rows.forEach((row, n) => { - if (!row.date) { - const line = el("div", "gl-line"); - line.append(graph(row.graph, row.lanes)); - frag.append(line); - return; - } - - const isOpen = open.has(n); - const lines = wrap(words(row), cols - row.graph.length, HANG); - let subjSeen = false; - lines.forEach((ws, li) => { - const line = el("div", "gl-line"); - line.append(li ? graph(row.cont, row.contLanes) : graph(row.graph, row.lanes, row.tip)); - if (li) line.append(" ".repeat(HANG)); - // consecutive subject words on a line become one button (or span) so the underline is unbroken - for (let k = 0; k < ws.length; k++) { - if (k) line.append(" "); - const w = ws[k]; - if (w.subj) { - let text = w.text; - while (ws[k + 1]?.subj) text += ` ${ws[++k].text}`; - if (row.body) { - const b = el("button", "gl-subj", text); - b.type = "button"; - b.dataset.row = n; - b.setAttribute("aria-expanded", String(isOpen)); - if (subjSeen) b.tabIndex = -1; // one tab stop per commit, even when its subject wraps - line.append(b); - } else { - line.append(el("span", "gl-text", text)); - } - subjSeen = true; - } else if (w.refs) { - const refs = el("span", "gl-refs"); - refs.append("("); - w.refs.forEach((r, i) => { - if (i) refs.append(", "); - if (r.head) refs.append(el("span", "gl-head", "HEAD -> ")); - refs.append(el("span", "gl-branch", r.name)); - }); - refs.append(")"); - line.append(refs); - } else { - line.append(w.cls ? el("span", w.cls, w.text) : w.text); - } - } - frag.append(line); - }); - - if (row.body && isOpen) { - const refsLen = row.refs.length ? refsText(row.refs).length + 1 : 0; - // under the subject when there's room; otherwise a little deeper than wrapped lines - const indent = wide ? row.date.length + 3 + refsLen : HANG + 2; - const text = wide ? row.body : reflow(row.body, cols - row.cont.length - indent); - const tail = pipesOnly(rows[n + 1]) ? [] : [""]; - for (const t of [...text, ...tail]) { - const b = el("div", "gl-line gl-body"); - b.append(graph(row.cont, row.contLanes), t ? " ".repeat(indent) + t : ""); - frag.append(b); - } - } - }); - - host.replaceChildren(frag); - host.classList.add("is-built"); - if (focusRow >= 0) host.querySelector(`.gl-subj[data-row="${focusRow}"]`)?.focus({ preventScroll: true }); - } - - host.addEventListener("click", (e) => { - const b = e.target.closest(".gl-subj"); - if (!b) return; - const n = +b.dataset.row; - if (open.has(n)) open.delete(n); - else open.add(n); - render(n); - }); - - render(); - new ResizeObserver(() => { - if (measureCols() !== lastCols) render(); - }).observe(host); -} diff --git a/js/themes.js b/js/themes.js @@ -1,19 +0,0 @@ -// Themes for M-x load-theme. The colours live in css/style.css under -// :root[data-theme="…"]; keep this list, that CSS and the inline script in -// index.html in sync. - -export const THEMES = [ - { id: "doom-gruvbox", desc: "Gruvbox, medium contrast. The theme my own Emacs uses" }, - { id: "doom-gruvbox-light", desc: "Gruvbox's light variant" }, - { id: "doom-one", desc: "Doom Emacs's default, inspired by Atom One Dark" }, - { id: "atom-one-dark", desc: "Atom's One Dark" }, - { id: "modus-vivendi", desc: "Emacs's built-in high-contrast dark theme" }, - { id: "modus-operandi", desc: "Emacs's built-in high-contrast light theme" }, - { id: "doom-dracula", desc: "Dracula" }, - { id: "doom-nord", desc: "Nord, arctic and north-bluish" }, - { id: "catppuccin", desc: "Catppuccin, Mocha flavour" }, - { id: "doom-tokyo-night", desc: "Tokyo Night" }, - { id: "doom-solarized-light", desc: "Solarized light" }, -]; - -export const DEFAULT_THEME = "doom-gruvbox"; diff --git a/package-lock.json b/package-lock.json @@ -0,0 +1,3754 @@ +{ + "name": "personal-site", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "personal-site", + "version": "0.0.1", + "dependencies": { + "astro": "^7.3.8" + } + }, + "node_modules/@astrojs/compiler-binding": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.5.1.tgz", + "integrity": "sha512-oczyolLUl9mNrtuBuNjuvn5thpHrFLXAHAWGTRg0JDHQ8cGVsVeFekOu2uSoQGgainJIi+A3/9m0DyYwz3Nlnw==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@astrojs/compiler-binding-android-arm64": "0.5.1", + "@astrojs/compiler-binding-darwin-arm64": "0.5.1", + "@astrojs/compiler-binding-darwin-x64": "0.5.1", + "@astrojs/compiler-binding-linux-arm64-gnu": "0.5.1", + "@astrojs/compiler-binding-linux-arm64-musl": "0.5.1", + "@astrojs/compiler-binding-linux-x64-gnu": "0.5.1", + "@astrojs/compiler-binding-linux-x64-musl": "0.5.1", + "@astrojs/compiler-binding-wasm32-wasi": "0.5.1", + "@astrojs/compiler-binding-win32-arm64-msvc": "0.5.1", + "@astrojs/compiler-binding-win32-x64-msvc": "0.5.1" + } + }, + "node_modules/@astrojs/compiler-binding-android-arm64": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-android-arm64/-/compiler-binding-android-arm64-0.5.1.tgz", + "integrity": "sha512-nMb2nMIJtcWLNH+fV75Enmi+jp4tIOYOfsv4XtpgdOWkqc9P4uSSdK5u1xb340AzrXo5V18SxLl/nc3vcqtamQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-darwin-arm64": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.5.1.tgz", + "integrity": "sha512-5k4+nZ/WRt+dcVow4z7rBuI7iv9A58h/uQ91YJe1PrTivbcCkq3u2Ynx/AZJwII4CsZawBCeGpojkFjutZBhBQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-darwin-x64": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.5.1.tgz", + "integrity": "sha512-0Buw+YST9Ff2EqQyhRMQujuFq/dijLw3zXWhsvI0dJ2pGrT38iVoxTEca2eBX/PfhlwkVWSRJEKO5gMqKHyeHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.5.1.tgz", + "integrity": "sha512-x5LRpyCoMKuu3INr18cn42YhwSOaRpp9b5Ny3eJJ/sWVeejC16Zeshu1JlvlSmEZACLeWxU5JM0RX6T6nI+YyA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-arm64-musl": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.5.1.tgz", + "integrity": "sha512-mL7tQEuDk3rGfaKmrO63nw6WBy1TPVioQGmVyjcAr+C+a/k3SVMYBytNSMqH9mZPT/Swj30JaZ2N842Z1NnOEQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-x64-gnu": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.5.1.tgz", + "integrity": "sha512-uLGc9jtxwiDe4cQyhNPQim4ECiB/YzbWlXssfLAv8r374kArfTwBHjwR2+j+XVyF71yCx5mF9YNRclRqdNBgeg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-x64-musl": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.5.1.tgz", + "integrity": "sha512-G0cywinaQUc8v1MrytvYKUX7svTDMmYtOCZfxjwKPbJi59zIqM+Ll0rWgO0GQWLZH3XoPYo19ZwlP3Xt9ep9YA==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-wasm32-wasi": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.5.1.tgz", + "integrity": "sha512-yMhLL8asmLydoAdnEZxAw6eLfNDs3YJl6jqn0pjPt6zrb2U5qIDLnii4/twThpIFODKkQ6YDpBRTOz/vSfZCxw==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.3", + "@emnapi/runtime": "1.11.3", + "@napi-rs/wasm-runtime": "^1.2.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.5.1.tgz", + "integrity": "sha512-aClIG6poFt3Wf/bZykrEAX2nAnKvBHW6RXiKUa69QjBtWH0/FOlOAjnFcxRNlhej2AMWNYFx0o+LGjwMcH8P7Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-win32-x64-msvc": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.5.1.tgz", + "integrity": "sha512-/E6uBCagY70YpWqssBC+/FuniNSloeQPRgj7l3LDWiqjxIyTLnIgX1sTt18FU7jrigetpSnC9cHAM6b6IxSgPw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-rs": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.5.1.tgz", + "integrity": "sha512-1k1acnX7DepIiea9U9/Y+d1hdAFfylu1ZQQkkYgRSwBOBAsXInolyZuh/2tax+83vu/A+hOYP6P3+265RvMTvw==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler-binding": "0.5.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@astrojs/internal-helpers": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.12.0.tgz", + "integrity": "sha512-pKPuwCDtO0L7zgmt1JGd9X4Aes1+0SX3IEBSqBNPHsScYdPMlfmed3Y7DTbXyF7E+8ylnb563o/0OzGQPOFehw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.4", + "@types/mdast": "^4.0.4", + "picomatch": "^4.0.4", + "retext-smartypants": "^6.2.0", + "shiki": "^4.0.2", + "smol-toml": "^1.8.0", + "unified": "^11.0.5", + "yaml": "^2.9.1" + } + }, + "node_modules/@astrojs/markdown-satteri": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.4.3.tgz", + "integrity": "sha512-PFbEHPnwUlLvpXd7RXrrKM+j12akF4bG+DSuNuoN+3eiwjOwp4HaPi+QQdbkBV7QEYXmzyKca50OJsmGxhNIUA==", + "license": "MIT", + "dependencies": { + "@astrojs/internal-helpers": "0.12.0", + "@astrojs/prism": "4.0.2", + "github-slugger": "^2.0.0", + "satteri": "^0.10.3" + } + }, + "node_modules/@astrojs/prism": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.2.tgz", + "integrity": "sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==", + "license": "MIT", + "dependencies": { + "prismjs": "^1.30.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@astrojs/telemetry": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.3.tgz", + "integrity": "sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==", + "license": "MIT", + "dependencies": { + "ci-info": "^4.4.0", + "dset": "^3.1.4", + "is-docker": "^4.0.0", + "package-manager-detector": "^1.6.0" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bruits/satteri-darwin-arm64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.10.5.tgz", + "integrity": "sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@bruits/satteri-darwin-x64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.10.5.tgz", + "integrity": "sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@bruits/satteri-linux-arm64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.10.5.tgz", + "integrity": "sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-linux-arm64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.10.5.tgz", + "integrity": "sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-linux-x64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.10.5.tgz", + "integrity": "sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-linux-x64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.10.5.tgz", + "integrity": "sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-wasm32-wasi": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.10.5.tgz", + "integrity": "sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.2.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@bruits/satteri-win32-arm64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.10.5.tgz", + "integrity": "sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@bruits/satteri-win32-x64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.10.5.tgz", + "integrity": "sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@capsizecss/unpack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.1.tgz", + "integrity": "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@clack/core": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.5.1.tgz", + "integrity": "sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==", + "license": "MIT", + "dependencies": { + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@clack/prompts": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.8.1.tgz", + "integrity": "sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==", + "license": "MIT", + "dependencies": { + "@clack/core": "1.5.1", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz", + "integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz", + "integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz", + "integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==", + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz", + "integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz", + "integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz", + "integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz", + "integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz", + "integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz", + "integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz", + "integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz", + "integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz", + "integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz", + "integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz", + "integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz", + "integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz", + "integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz", + "integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz", + "integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz", + "integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz", + "integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz", + "integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz", + "integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz", + "integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz", + "integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz", + "integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz", + "integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.5.tgz", + "integrity": "sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + } + }, + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT" + }, + "node_modules/@oxc-project/types": { + "version": "0.153.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.153.0.tgz", + "integrity": "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.13.tgz", + "integrity": "sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.13.tgz", + "integrity": "sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.13.tgz", + "integrity": "sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.13.tgz", + "integrity": "sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.13.tgz", + "integrity": "sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.13.tgz", + "integrity": "sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.13.tgz", + "integrity": "sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.13.tgz", + "integrity": "sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.13.tgz", + "integrity": "sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.13.tgz", + "integrity": "sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.13.tgz", + "integrity": "sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.13.tgz", + "integrity": "sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.13.tgz", + "integrity": "sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.13.tgz", + "integrity": "sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.13.tgz", + "integrity": "sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "license": "MIT" + }, + "node_modules/@shikijs/core": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.5.0.tgz", + "integrity": "sha512-6CIgwq+bt2JZ3OSjb/nBkkwEf/CfpHcbam+Mg5Pllco7HAGRQ2/EFhZrrJtbyNTgKwknfVS+llsXGygiDGwJWw==", + "license": "MIT", + "dependencies": { + "@shikijs/primitive": "4.5.0", + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5", + "hast-util-to-html": "^9.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.5.0.tgz", + "integrity": "sha512-Ed6UdEj84LyYkwnxM5CvSMWAD+id9ExTYri0/+x41U9zrgNifPSS9lZm0JqBP0VfYI8yr8tY5nbNq9+p9R0kFA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.5.0.tgz", + "integrity": "sha512-dKVmbJecVdB9recl8a/CU4jdpNXyjJQrIcesIkpS70s5HS02ohpnCSpMUbotPnEUzbAcLQ+S4hwZYbkBBiTcJw==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/langs": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.5.0.tgz", + "integrity": "sha512-wwBTqwduXSz0X4v9Qa2EWeFaYJEw1clCncWjoRNQRbVDu3SPRTRWucnouYapKj3b8Q+sk/41Vbc4B5c8nuYzLA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/primitive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.5.0.tgz", + "integrity": "sha512-UM7ShlA8oz0OWxLLO8BmO9Ip6fVqdkt8yF0EH7nOCqHfrx1eEAzF0ZUVK7L+I8NEgeu1PEWSRlxaiPPeCb4iDg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/themes": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.5.0.tgz", + "integrity": "sha512-zGb87H3UBbpuI4yoh5UguB1XbU+2BDU3kflM7UfZ+Cy2hWo9lBtqjSVK20gmLY6ukYl040hAypGXMgud9vul8Q==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/types": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.5.0.tgz", + "integrity": "sha512-drtPrtD8N0DENyD2cyt6Ajy+IWsiCLgMxODwLTpvH1UsN6a9jf90tNTPjqwHvA+0Lzu9e0txk8DjfqH1p9UJRw==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "license": "ISC" + }, + "node_modules/am-i-vibing": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.5.0.tgz", + "integrity": "sha512-KLcsDhqf1XRrJmJr+9I/C0EX2K+sGrAGZFgkmd84c8TJO9zJBu+/kFInjazu1KfJWFhWDKdRWkpBzEs7s35DVA==", + "license": "MIT", + "dependencies": { + "process-ancestry": "^0.1.0" + }, + "bin": { + "am-i-vibing": "dist/cli.mjs" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/astro": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/astro/-/astro-7.3.8.tgz", + "integrity": "sha512-LHzDHSaV+YzZiR3EFndDYTLLeNeuMtP1qX1FLcCNUUHOCqTTIWPczy2UV3zpA5VqvJe5cWZolqM9Z8JFqR2i9w==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler-rs": "^0.5.1", + "@astrojs/internal-helpers": "0.12.0", + "@astrojs/markdown-satteri": "0.4.3", + "@astrojs/telemetry": "3.3.3", + "@capsizecss/unpack": "^4.0.1", + "@clack/prompts": "^1.8.1", + "@oslojs/encoding": "^1.1.0", + "am-i-vibing": "^0.5.0", + "aria-query": "^5.3.2", + "axobject-query": "^4.1.0", + "ci-info": "^4.4.0", + "clsx": "^2.1.1", + "common-ancestor-path": "^2.0.0", + "cookie": "^2.0.1", + "devalue": "^5.9.4", + "diff": "^9.0.0", + "dset": "^3.1.4", + "es-module-lexer": "^3.0.2", + "find-proc": "0.2.0", + "flattie": "^1.1.1", + "fontace": "~0.4.1", + "get-tsconfig": "5.0.0-beta.6", + "github-slugger": "^2.0.0", + "html-escaper": "3.0.3", + "http-cache-semantics": "^4.2.0", + "jsonc-parser": "^3.3.1", + "magic-string": "^1.4.2", + "magicast": "^0.5.5", + "mrmime": "^2.0.1", + "neotraverse": "^1.0.1", + "obug": "^3.0.0", + "p-limit": "^7.3.3", + "p-queue": "^9.3.3", + "package-manager-detector": "^1.8.0", + "piccolore": "^0.1.3", + "picomatch": "^4.0.7", + "rolldown": "^1.2.11", + "shiki": "^4.4.3", + "smol-toml": "^1.9.0", + "svgo": "^4.1.0", + "tinyclip": "^1.0.3", + "tinyexec": "^1.3.1", + "tinyglobby": "^0.2.17", + "ultrahtml": "^1.7.0", + "unifont": "~0.7.5", + "unstorage": "^1.17.5", + "verkit": "^0.5.0", + "vite": "^8.3.1", + "vitefu": "^1.1.3", + "xxhash-wasm": "^1.1.0", + "yargs-parser": "^22.0.0", + "zod": "^4.6.5" + }, + "bin": { + "astro": "bin/astro.mjs" + }, + "engines": { + "node": ">=22.12.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/astrodotbuild" + }, + "optionalDependencies": { + "sharp": "^0.35.4" + }, + "peerDependencies": { + "@astrojs/markdown-remark": "^7.3.0" + }, + "peerDependenciesMeta": { + "@astrojs/markdown-remark": { + "optional": true + } + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/common-ancestor-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz", + "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" + } + }, + "node_modules/cookie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==", + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cookie-es": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz", + "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==", + "license": "MIT" + }, + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/css-select": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.9.4", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.9.4.tgz", + "integrity": "sha512-sPAT4pztbu6586/hrhOnMKS17IJrvg12mXiSPSS3W5qDeN2RGgvZ0diZCm31dBbnevfVmujNO3IM2wrS4Y2Rhg==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dset": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-3.0.3.tgz", + "integrity": "sha512-yWGe1O/j+almnV4hOYrmZo8u58JdnmXEMneRQAYkWtqSiT86yoMIEKF4rpqEDj52tbYl3xceBD3DQIBwcsC9Pw==", + "license": "MIT" + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/find-proc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/find-proc/-/find-proc-0.2.0.tgz", + "integrity": "sha512-a6h2nTrgB3g5Wrn4au9Ux4kMk7IJtyF6oA8uGn+mk3weLZssUtc1cp6meHIzzuW2o1srrBAxzkmXLbqjRkgB6w==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/flattie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", + "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/fontace": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz", + "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.2" + } + }, + "node_modules/fontkitten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.3.tgz", + "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==", + "license": "MIT", + "dependencies": { + "tiny-inflate": "^1.0.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "5.0.0-beta.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.6.tgz", + "integrity": "sha512-X6fBC0pmImC70gvX2zm56go9hx0MyoGVdG0tUCkg/D+Xnh5TJsOZ7iDbOdI3PvmtrDxnu1YdDufpK2QJX1Meqw==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "engines": { + "node": ">=20.20.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" + }, + "node_modules/h3": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", + "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.3", + "crossws": "^0.3.5", + "defu": "^6.1.6", + "destr": "^2.0.5", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.4", + "radix3": "^1.1.2", + "ufo": "^1.6.3", + "uncrypto": "^0.1.3" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz", + "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==", + "license": "BSD-2-Clause" + }, + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" + } + }, + "node_modules/is-docker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-4.0.0.tgz", + "integrity": "sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.3.tgz", + "integrity": "sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/magicast": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.5.tgz", + "integrity": "sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "source-map-js": "^1.2.1" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.3.tgz", + "integrity": "sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/neotraverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-1.0.1.tgz", + "integrity": "sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-mock-http": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.5.tgz", + "integrity": "sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/obug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/obug/-/obug-3.0.0.tgz", + "integrity": "sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==", + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" + } + }, + "node_modules/ohash": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.12.tgz", + "integrity": "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==", + "license": "MIT" + }, + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/p-limit": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.3.tgz", + "integrity": "sha512-SKgVvDU5TNIxQ4r30U75BNLC6a+6GOEjngrk/ysM5+Zu3oJuk1SC5ApzIzY/7PjCEjoVPMWJ0zho/4QUiEB7TQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.2.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.5.tgz", + "integrity": "sha512-Lki/zhXFVmDhesBUn/yHRLW9Bte7mE7xoFHzTR8sIomV7a2z+LxYAPkGvdfidNiu4fKSfjtawixxSHcZci5QcQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.4", + "p-timeout": "^7.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.2.tgz", + "integrity": "sha512-prbX4Z3YszrFNgH+MW5Zoeq3baXrMtP/MQnFeET90UB/GtGcGDQ5Usg9OCy6ETjTTntOw1SL2z9fMPUppN3Guw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-manager-detector": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.9.0.tgz", + "integrity": "sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==", + "license": "MIT" + }, + "node_modules/piccolore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", + "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==", + "license": "ISC" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.19", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-ancestry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/process-ancestry/-/process-ancestry-0.1.0.tgz", + "integrity": "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/retext-smartypants": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rolldown": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.13.tgz", + "integrity": "sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.153.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.13", + "@rolldown/binding-android-arm64": "1.2.13", + "@rolldown/binding-darwin-arm64": "1.2.13", + "@rolldown/binding-darwin-x64": "1.2.13", + "@rolldown/binding-freebsd-x64": "1.2.13", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.13", + "@rolldown/binding-linux-arm64-gnu": "1.2.13", + "@rolldown/binding-linux-arm64-musl": "1.2.13", + "@rolldown/binding-linux-ppc64-gnu": "1.2.13", + "@rolldown/binding-linux-s390x-gnu": "1.2.13", + "@rolldown/binding-linux-x64-gnu": "1.2.13", + "@rolldown/binding-linux-x64-musl": "1.2.13", + "@rolldown/binding-openharmony-arm64": "1.2.13", + "@rolldown/binding-win32-arm64-msvc": "1.2.13", + "@rolldown/binding-win32-x64-msvc": "1.2.13" + } + }, + "node_modules/satteri": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.10.5.tgz", + "integrity": "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.5", + "@types/hast": "^3.0.5", + "@types/mdast": "^4.0.4", + "@types/unist": "^3.0.3" + }, + "optionalDependencies": { + "@bruits/satteri-darwin-arm64": "0.10.5", + "@bruits/satteri-darwin-x64": "0.10.5", + "@bruits/satteri-linux-arm64-gnu": "0.10.5", + "@bruits/satteri-linux-arm64-musl": "0.10.5", + "@bruits/satteri-linux-x64-gnu": "0.10.5", + "@bruits/satteri-linux-x64-musl": "0.10.5", + "@bruits/satteri-wasm32-wasi": "0.10.5", + "@bruits/satteri-win32-arm64-msvc": "0.10.5", + "@bruits/satteri-win32-x64-msvc": "0.10.5" + } + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz", + "integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.5", + "@img/sharp-darwin-x64": "0.35.5", + "@img/sharp-freebsd-wasm32": "0.35.5", + "@img/sharp-libvips-darwin-arm64": "1.3.4", + "@img/sharp-libvips-darwin-x64": "1.3.4", + "@img/sharp-libvips-linux-arm": "1.3.4", + "@img/sharp-libvips-linux-arm64": "1.3.4", + "@img/sharp-libvips-linux-ppc64": "1.3.4", + "@img/sharp-libvips-linux-riscv64": "1.3.4", + "@img/sharp-libvips-linux-s390x": "1.3.4", + "@img/sharp-libvips-linux-x64": "1.3.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4", + "@img/sharp-libvips-linuxmusl-x64": "1.3.4", + "@img/sharp-linux-arm": "0.35.5", + "@img/sharp-linux-arm64": "0.35.5", + "@img/sharp-linux-ppc64": "0.35.5", + "@img/sharp-linux-riscv64": "0.35.5", + "@img/sharp-linux-s390x": "0.35.5", + "@img/sharp-linux-x64": "0.35.5", + "@img/sharp-linuxmusl-arm64": "0.35.5", + "@img/sharp-linuxmusl-x64": "0.35.5", + "@img/sharp-webcontainers-wasm32": "0.35.5", + "@img/sharp-win32-arm64": "0.35.5", + "@img/sharp-win32-ia32": "0.35.5", + "@img/sharp-win32-x64": "0.35.5" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/shiki": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.5.0.tgz", + "integrity": "sha512-OcRW72ngQvc+MSVWBRIovC/BTW589iUE/Vxav7VeM4RcY9MUjqB+IR6ILG1k9nuW6LiG/nct9uma4/MBtnZbmQ==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.5.0", + "@shikijs/engine-javascript": "4.5.0", + "@shikijs/engine-oniguruma": "4.5.0", + "@shikijs/langs": "4.5.0", + "@shikijs/themes": "4.5.0", + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/smol-toml": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.9.1.tgz", + "integrity": "sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/svgo": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.1.0.tgz", + "integrity": "sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==", + "license": "MIT", + "dependencies": { + "commander": "^11.1.0", + "css-select": "^6.0.0", + "css-tree": "^3.0.1", + "css-what": "^7.0.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "1.6.1" + }, + "bin": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, + "node_modules/tinyclip": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-1.0.3.tgz", + "integrity": "sha512-nTv2raKFMzGG6JJp0lpNDsRPdfFE6UHlu2rVEjXo8vkx1ZS3LW2CVXqIaLu8xZlu+6tbFs9V58Qc/Jmk/Ii7wA==", + "license": "MIT", + "engines": { + "node": "^16.14.0 || >= 17.3.0" + } + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "license": "MIT" + }, + "node_modules/ultrahtml": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.7.0.tgz", + "integrity": "sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==", + "license": "MIT" + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/undici": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz", + "integrity": "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==", + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unifont": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.5.tgz", + "integrity": "sha512-ULe/Cs+ZIsq+dcFofNkhqielCrUJnb5mr+Yc4EBM2VlL+6OZR6+cjtI2mT1bJvRBrVncqHAbLURxmPLcCXzWMg==", + "license": "MIT", + "dependencies": { + "css-tree": "^3.1.0", + "ohash": "^2.0.11", + "undici": "^8.0.0" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unstorage": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz", + "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^5.0.0", + "destr": "^2.0.5", + "h3": "^1.15.10", + "lru-cache": "^11.2.7", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.3" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6 || ^7 || ^8", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1 || ^2 || ^3", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/verkit": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.5.0.tgz", + "integrity": "sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==", + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.4.tgz", + "integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==", + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.29", + "rolldown": "~1.2.12", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/xxhash-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", + "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", + "license": "MIT" + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.6.tgz", + "integrity": "sha512-4UmzQUF5fxvfcYHlbjBmejU+w+hbDnWFx4aS8kBx7nPBHcO2SqPbpAG8snbdg+Xse4pRefR98hgjFgIMCI/UhA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json @@ -0,0 +1,15 @@ +{ + "name": "personal-site", + "type": "module", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "astro": "^7.3.8" + } +} diff --git a/favicon.svg b/public/favicon.svg diff --git a/fonts/cm-italic.woff2 b/public/fonts/cm-italic.woff2 Binary files differ. diff --git a/fonts/cm-regular.woff2 b/public/fonts/cm-regular.woff2 Binary files differ. diff --git a/fonts/jetbrains-mono-regular.woff2 b/public/fonts/jetbrains-mono-regular.woff2 Binary files differ. diff --git a/fonts/jetbrains-mono-semibold.woff2 b/public/fonts/jetbrains-mono-semibold.woff2 Binary files differ. diff --git a/notes-to-self.txt b/public/notes-to-self.txt diff --git a/robots.txt b/public/robots.txt diff --git a/src/pages/index.astro b/src/pages/index.astro @@ -0,0 +1,352 @@ +--- +import "../styles/style.css"; +--- +<!doctype html> +<html lang="en" data-theme="doom-gruvbox"> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> +<title>Michael Neuper</title> +<meta name="description" content="Computer science student at Stellenbosch University. Low-level software, electronics, a little security, and a lot of Emacs."> +<link rel="icon" href="/favicon.svg" type="image/svg+xml"> +<link rel="preload" href="/fonts/jetbrains-mono-regular.woff2" as="font" type="font/woff2" crossorigin> +<link rel="preload" href="/fonts/cm-regular.woff2" as="font" type="font/woff2" crossorigin> +{/* is:inline: Astro ships this script as written instead of bundling it, so it still runs before first paint. */} +<script is:inline> + // Pick the theme before first paint so there is no flash. Keep this list in sync with src/scripts/themes.js. + try { + var t = localStorage.getItem("theme"); + var known = /^(doom-gruvbox|doom-gruvbox-light|doom-one|atom-one-dark|modus-vivendi|modus-operandi|doom-dracula|doom-nord|catppuccin|doom-tokyo-night|doom-solarized-light)$/; + if (!known.test(t || "")) t = matchMedia("(prefers-color-scheme: light)").matches ? "doom-gruvbox-light" : ""; + if (t) document.documentElement.dataset.theme = t; + } catch (e) {} + // Hide the name until src/scripts/decode.js has split it into letters, so it never flashes whole first. + // CSS shows it anyway after a moment in case the script never runs. + try { + if (!matchMedia("(prefers-reduced-motion: reduce)").matches && (!location.hash || location.hash === "#top")) { + document.documentElement.classList.add("boot"); + } + } catch (e) {} +</script> +<script src="../scripts/main.js"></script> +</head> +<!-- Reading the source? Good instinct. flag{view_source_is_recon} --> +<body> +<a class="skip" href="#about">Skip to content</a> + +<header class="top"> + <a class="brand" href="#top" aria-label="Michael Neuper, back to top"> + <svg class="logo" viewBox="0 0 32 16" aria-hidden="true"><path d="M1 14H3V2H9V14H11V2H17V14H20V2H26V14H31"/></svg> + <span>michael neuper</span> + </a> + <nav class="nav" id="nav" aria-label="Sections"> + <a href="#top">pinout</a> + <a href="#about">about</a> + <a href="#projects">projects</a> + <a href="#posts">posts</a> + <a href="#contact">contact</a> + </nav> + <button class="theme-key" type="button" title="SPC h t">load-theme</button> + <button class="menu-key" type="button" aria-expanded="false" aria-controls="nav">menu</button> +</header> + +<main> + + <!-- ─────────────────────────── landing ─────────────────────────── --> + <section class="hero" id="top" data-file="mn-2026.kicad_sym" data-mode="Lisp Data" aria-labelledby="hero-name"> + <div class="hero-id"> + <h1 class="hero-name" id="hero-name">Michael Neuper</h1> + <p class="hero-lede">Computer science student at Stellenbosch University. I like low-level software, electronics and the maths underneath both, and I do almost all of it in Emacs.</p> + <ul class="legend" aria-label="Colour key used across the site"> + <li data-cat="hw">hardware</li> + <li data-cat="sw">software</li> + <li data-cat="math">maths</li> + <li data-cat="sec">security</li> + </ul> + </div> + + <div class="hero-chip"> + <figure class="pinout"> + <div class="chip-wrap"><!-- built from the list below --></div> + <div class="pin-readout" aria-live="polite"><p class="dim">Point at a pin to read its function.</p></div> + <figcaption>Figure 1. MN-2026, DIP-16 package, top view.</figcaption> + <!-- Edit the pins here. data-cat: hw, sw, math or sec. "M-x some-command" in a description becomes a button. --> + <ol class="pin-list"> + <li data-name="VCC" data-type="power">Supply input: coffee. Top it up with M-x coffee-refill.</li> + <li data-name="C" data-type="I/O" data-cat="sw">Most of what I write, from a compiler to terminal toys like a spinning cube and the Game of Life.</li> + <li data-name="ASM" data-type="I/O" data-cat="sw">Assembly, starting with the 8-bit computer’s eleven instructions.</li> + <li data-name="JVM" data-type="output" data-cat="sw">The target of my compiler, so I read javap output for fun.</li> + <li data-name="LINUX" data-type="I/O" data-cat="sw">Daily driver. Dotfiles on GitHub, and posts on packaging formats and turning a window manager into a desktop.</li> + <li data-name="TTL" data-type="I/O" data-cat="hw">74-series logic. The 8-bit computer is dozens of these chips on breadboards.</li> + <li data-name="SEC" data-type="input" data-cat="sec">Security: a consulting internship, a web application assessment, and the habit of asking how things break.</li> + <li data-name="GND" data-type="power">Return path. Sleep, when the config is finished (it is never finished).</li> + <li data-name="RST" data-type="input">Active low. Asserted by a walk without a laptop.</li> + <li data-name="TA" data-type="output" data-cat="hw">Teaching assistant for introductory computer science and computer architecture.</li> + <li data-name="TEX" data-type="output" data-cat="math">Notes, templates and maths typeset in LaTeX, usually from Emacs.</li> + <li data-name="ORG" data-type="I/O" data-cat="sw">Org mode and org-roam for notes, literate configs, and replacing Jupyter.</li> + <li data-name="EMACS" data-type="I/O" data-cat="sw">Doom Emacs, with a literate config of over a thousand lines. Location: ~/.config/emacs/.</li> + <li data-name="MATH" data-type="input" data-cat="math">Project Euler, discrete maths, and modelling things in Python.</li> + <li data-name="CAN" data-type="I/O">CAN bus, the network inside every car. Cars are my one interest that isn’t a computer, mostly.</li> + <li data-name="NC" data-type="no connect">Reserved for the next obsession.</li> + </ol> + </figure> + </div> + </section> + + <!-- ───────────────────────────── datasheet ───────────────────────────── --> + <section class="sec" id="about" data-file="whoami.pdf" data-mode="PDFView"> + <p class="winbar"><span class="file">whoami.pdf</span><span class="rule" aria-hidden="true"></span><span class="meta">revised June 2026</span></p> + + <header class="ds-head"> + <p class="ds-part">MN-2026</p> + <h2 class="ds-title">About</h2> + </header> + + <p class="prose ds-desc">I study computer science at Stellenbosch University and have been a teaching assistant for introductory computer science and computer architecture. I like understanding things all the way down, from a line of C to the gates that run it, and I’m happiest when that ends in something I built: a scheduler, a compiler, or a computer on breadboards. Away from that I’m a linguistics nerd and a free-software advocate.</p> + + <!-- Experience, as the one-line git log that would print it: "<date> - (refs) <subject> <author>". + data-lanes colours each graph character by branch: m main, u undergrad, t teaching-assistant, + b bbd-software, i mwr-internship (the colours are set in src/styles/style.css). data-cont is the graph that continues below a commit, and a + .gl-desc becomes its expandable description. data-branch colours the date; data-tip makes the + * bold for a branch that's still going; data-today swaps in the current month when the page loads. + Without JavaScript this shows as plain text. --> + <h3 class="ds-h gitlog-cmd"><span class="prompt" aria-hidden="true">$ </span>git log --graph --all --color \ + --date=format:'%Y-%m' \ + --format='%ad -%C(auto)%d%C(reset) %s %C(blue)<%an>%C(reset)'</h3> + <div class="gitlog" aria-label="Experience, newest first"> +<div class="gl-line" data-lanes=" b u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="m" data-tip data-today>* | | | 2026-10 - (HEAD -> main)</div> +<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="b" data-tip>| * | | 2026-06 - (bbd-software) Vac Week 2026 <BBD Software><div class="gl-desc">Built an online foosball game: players steer the rods by +tilting their phones, using the gyroscope. Designed and +presented as a full-stack web app with a small team.</div></div> +<div class="gl-line" data-lanes="m b u " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="t" data-tip>| | | * 2026-06 - (teaching-assistant) Teach computer architecture as a TA <Stellenbosch University></div> +<div class="gl-line" data-lanes="m b u t">| | | |</div> +<div class="gl-line" data-lanes="m b u " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="t">| | | * 2026-02 - Teach introductory computer science as a TA <Stellenbosch University></div> +<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="b">| * | | 2025-06 - Vac Week 2025 <BBD Software><div class="gl-desc">Built an online laser tag game: computer vision finds players +in the camera feed and tags them. Designed and presented as a +full-stack web app with a small team.</div></div> +<div class="gl-line" data-lanes="m b u t">| | | |</div> +<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="b">| * | | 2025-01 - Join BBD Software as a bursar <BBD Software><div class="gl-desc">Part of the Bursary & Beyond Programme, which includes the +yearly Vac Weeks.</div></div> +<div class="gl-line" data-lanes="mb u t">|/ | |</div> +<div class="gl-line" data-lanes="m u t">| | |</div> +<div class="gl-line" data-lanes="mi u t">|\ | |</div> +<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m i u t " data-branch="i">| * | | 2024-12 - (mwr-internship) Complete a cybersecurity consultant internship <MWR CyberSec><div class="gl-desc">- Completed cybersecurity training with labs on TryHackMe. +- Assessed a web application end to end, documenting each + vulnerability with its risk and how to fix it. +- Wrote a professional report and presented it, client-style, + to a panel of industry professionals.</div></div> +<div class="gl-line" data-lanes="mi u t">|/ | |</div> +<div class="gl-line" data-lanes="m ut">| |/</div> +<div class="gl-line" data-lanes="m " data-cont="| | " data-cont-lanes="m u " data-branch="u" data-tip>| * 2024-01 - (undergrad) Start an undergraduate degree in computer science <Stellenbosch University></div> +<div class="gl-line" data-lanes="m u">| /</div> +<div class="gl-line" data-lanes="mu">|/</div> +<div class="gl-line" data-lanes=" " data-cont=" " data-cont-lanes=" " data-branch="m">* 2005-06 - Initial commit <Michael Neuper></div> + </div> + <p class="gitlog-hint dim">Click an underlined commit message to read the rest of it.</p> + + </section> + + <!-- ──────────────────────────── memory map ──────────────────────────── --> + <section class="sec" id="projects" data-file="memory.map" data-mode="Fundamental"> + <p class="winbar"><span class="file">memory.map</span><span class="rule" aria-hidden="true"></span><span class="meta" data-mm="meta"></span></p> + <h2 class="h2">Projects</h2> + <p class="lede">Laid out like a linker map: each project is a region in memory holding its one-line summary, and the hexdump shows exactly those bytes. Select one to read about it and try it out.</p> + + <div class="mm"> + <div class="mm-bar" aria-hidden="true"></div> + <div class="mm-cols"> + <div class="mm-table"> + <p class="mm-head" aria-hidden="true"><span>origin</span><span>length</span><span>name</span><span>source</span></p> + <!-- Edit projects here. data-cat: hw, sw, math or sec. data-src: shown in the source column. + data-demo: computer, scheduler, bytecode, othello or rbudp (optional); data-wide gives the + demo the full width under the list. --> + <ol class="mm-list"> + <li class="proj" data-cat="hw" data-src="built" data-demo="computer" data-wide> + <h3 class="proj-name">8-bit-computer</h3> + <p class="proj-sum">Ben Eater's 8-bit breadboard computer, built chip by chip.</p> + <div class="proj-body"> + <p>My most recent finished project: a programmable computer on breadboards, built from 74-series logic chips following Ben Eater’s video series. It has 16 bytes of RAM, an 8-bit bus, and microcode in EEPROMs that drives sixteen control lines.</p> + <p>The simulation below runs the same instruction set and microcode, so you can step through a program one control word at a time.</p> + <p class="proj-stack">74HC logic, EEPROMs, breadboards, a lot of jumper wire</p> + <p class="proj-links"><a href="https://eater.net/8bit">Ben Eater’s series</a></p> + </div> + </li> + <li class="proj" data-cat="sw" data-src="private" data-demo="scheduler"> + <h3 class="proj-name">os-scheduler</h3> + <p class="proj-sum">A multicore operating system scheduler, for a concurrency course.</p> + <div class="proj-body"> + <p>The part of an operating system that decides which process runs on which core, and for how long. I wrote it for a concurrency course, so the source stays private, but the idea fits in a small simulation: processes arrive, wait in a shared ready queue, and get dispatched to cores under first come, first served, round robin or preemptive priority scheduling.</p> + <p class="proj-links dim">Source private (concurrency coursework)</p> + </div> + </li> + <li class="proj" data-cat="sw" data-src="private" data-demo="othello"> + <h3 class="proj-name">othello-mcts</h3> + <p class="proj-sum">An Othello player in C that runs Monte Carlo tree search across MPI processes.</p> + <div class="proj-body"> + <p>The player picks a move by running thousands of random games from the current position and keeping the move that was explored most, using UCT to balance trying new moves against improving promising ones. Each move gets one second.</p> + <p>The project was for a concurrency course, so the next step was to parallelise it with MPI, which I did in three ways: independent search trees combined at the end with <code>MPI_Allreduce</code>, trees that share their statistics every so often, and the same sharing done asynchronously with non-blocking sends. In ten-game matches on four processes, each version beat the one before it, except the asynchronous version, which won half its games against the synchronous one.</p> + <p>You can play a serial version, rewritten in JavaScript for this page, below. While it thinks, each legal move is shaded by how often the search tried it.</p> + <p class="proj-stack">C, MPI, Docker</p> + <p class="proj-links dim">Source private (concurrency coursework)</p> + </div> + </li> + <li class="proj" data-cat="sw" data-src="private" data-demo="bytecode"> + <h3 class="proj-name">jvm-compiler</h3> + <p class="proj-sum">A compiler in C for a custom language that targets the JVM.</p> + <div class="proj-body"> + <p>I wrote it in C for a computer architecture course. It reads a small custom programming language and produces bytecode the Java virtual machine can run. The source stays private, but the last stage is easy to show: the JVM is a stack machine, so an expression compiles to instructions that push and pop an operand stack. Type one below to see the bytecode and run it.</p> + <p class="proj-stack">C, JVM bytecode</p> + <p class="proj-links dim">Source private (computer architecture coursework)</p> + </div> + </li> + <li class="proj" data-cat="sw" data-src="private" data-demo="rbudp"> + <h3 class="proj-name">chat-voip-p2p</h3> + <p class="proj-sum">Four networking projects in Java: chat, fast UDP file transfer, voice calls and P2P sharing.</p> + <div class="proj-body"> + <p>A series of networking projects built with my group for a university course:</p> + <ul> + <li>A chat server that handles many clients at once, with a JavaFX client, load-tested with dozens of simultaneous users.</li> + <li>File transfer over Reliable Blast UDP, measured against TCP across packet sizes, loss rates and file sizes from 1 to 100 MB.</li> + <li>The chat extended with voice calls and group calls streamed over UDP, plus voice notes.</li> + <li>Peer-to-peer file sharing: a server brokers searches, then peers send files to each other directly over TCP, encrypted with AES-GCM keys exchanged using RSA, with pause and resume. We tested it across four machines over Tailscale.</li> + </ul> + <p>Below is the RBUDP transfer in miniature: blast every packet over UDP, ask over TCP which ones arrived, and resend the gaps.</p> + <p class="proj-stack">Java, JavaFX, TCP and UDP sockets, Java Sound, RSA, AES-GCM</p> + <p class="proj-links dim">Source private (coursework, group project)</p> + </div> + </li> + </ol> + </div> + <article class="mm-detail" aria-live="polite"></article> + </div> + </div> + </section> + + <!-- ────────────────────────────── posts ────────────────────────────── --> + <section class="sec" id="posts" data-file="posts.org" data-mode="Org"> + <p class="winbar"><span class="file">posts.org</span><span class="rule" aria-hidden="true"></span><span class="meta" data-org="meta"></span></p> + <p class="org-p">From my blog at michaelneuper.com, shown the way I read them. <kbd>TAB</kbd> on a heading folds it, <kbd>S-TAB</kbd> cycles the whole buffer, and clicking a heading’s stars does the same.</p> + + <!-- Edit posts here. data-tags are space separated; each tag gets its own colour (see TAG_COLORS in src/scripts/org.js). --> + <ol class="posts"> + <li data-date="2024-11-22" data-tags="emacs org" data-cat="sw"><a href="https://michaelneuper.com/posts/how-i-use-org-roam-to-takes-notes-for-cs/">How I Use Org-Roam to Take Notes for CS</a></li> + <li data-date="2023-11-15" data-tags="emacs latex" data-cat="math"><a href="https://michaelneuper.com/posts/efficient-latex-editing-with-emacs/">Efficient LaTeX Editing With Emacs</a></li> + <li data-date="2023-11-12" data-tags="python maths" data-cat="math"><a href="https://michaelneuper.com/posts/modelling-population-growth-in-python/">Modelling Population Growth in Python</a></li> + <li data-date="2023-02-27" data-tags="emacs org" data-cat="sw"><a href="https://michaelneuper.com/posts/replace-jupyter-notebook-with-emacs-org-mode/">Replace Jupyter Notebook With Emacs Org Mode</a></li> + <li data-date="2023-01-09" data-tags="linux" data-cat="sw"><a href="https://michaelneuper.com/posts/what-linux-packaging-format-to-use/">Which Linux Packaging Format Should You Use?</a></li> + <li data-date="2022-12-16" data-tags="linux security" data-cat="sec"><a href="https://michaelneuper.com/posts/enable-monitor-mode-on-tp-link/">Enable Monitor Mode on TP-Link TL-WN722N</a></li> + <li data-date="2022-12-14" data-tags="security c" data-cat="sec"><a href="https://michaelneuper.com/posts/buffer-overflow/">Buffer Overflows: Keep Your Code Safe</a></li> + <li data-date="2022-12-11" data-tags="linux" data-cat="sw"><a href="https://michaelneuper.com/posts/turning-a-window-manager-into-a-desktop-environment/">A Guide to Building Your Own Desktop Environment</a></li> + <li data-date="2022-12-03" data-tags="web" data-cat="sw"><a href="https://michaelneuper.com/posts/how-to-create-your-own-website/">How to Create Your Own Static Website</a></li> + </ol> + </section> + + <!-- ───────────────────────────── contact ───────────────────────────── --> + <section class="sec" id="contact" data-file="*unsent mail*" data-mode="Message"> + <p class="winbar"><span class="file">*unsent mail*</span><span class="rule" aria-hidden="true"></span><span class="meta">draft</span></p> + <h2 class="h2">Say hello</h2> + <p class="lede">Email works best. For anything private, encrypt it with my GPG key below.</p> + + <div class="contact"> + <!-- The address is only ever put together in JavaScript, so scrapers reading this HTML don't see it. + The link and the copy button read data-user and data-host. --> + <a class="mail" href="#contact" data-user="michael" data-host="michaelneuper.com">michael<span class="at"> <at> </span>michaelneuper.com</a> + <button type="button" class="btn" data-email="copy">copy address</button> + </div> + + <div class="contact-grid"> + <div class="gpg"> + <h3 class="ds-h">Encrypt it</h3> + <p class="gpg-fp"><span class="dim">fingerprint</span><code>4E7B F800 0D86 182D F484 5C37 508B CF84 373C 8930</code></p> + <div class="gpg-cmd"> + <pre><code>curl -sL https://michaelneuper.com/michaelneuper.gpg | gpg --import</code></pre> + <button type="button" class="btn" data-copy=".gpg-cmd code">copy</button> + </div> + </div> + <div> + <h3 class="ds-h">Elsewhere</h3> + <ul class="elsewhere"> + <li><a href="https://github.com/michaelneuper">GitHub</a></li> + <li><a href="https://www.linkedin.com/in/michaelneuper/">LinkedIn</a></li> + <li><a href="https://michaelneuper.com">michaelneuper.com</a></li> + <li><a href="https://buymeacoffee.com/michaelneuper" target="_blank" rel="noopener">Buy me a coffee</a></li> + </ul> + </div> + </div> + + <div class="ctf"> + <h3 class="ds-h">Capture the flag</h3> + <p>Three flags are hidden on this site, the kind you would find in a beginner CTF. They look like <code>{"flag{…}"}</code>. Found one? Run <kbd>M-x</kbd> <code>submit-flag</code>, or use the button.</p> + <p class="ctf-row"><button type="button" class="btn" data-ctf="submit">submit a flag</button><span class="ctf-progress" aria-live="polite">0 of 3 found</span></p> + </div> + </section> + + <footer class="foot"> + <p>Made with HTML, CSS, JavaScript and Emacs, without a framework, a build step or cookies.</p> + <p class="dim">Press <kbd>SPC</kbd> for commands or <kbd>M-x</kbd> to run one by name.</p> + </footer> +</main> + +<!-- ───────────────────────── coffee, modeline and minibuffer ───────────────────────── --> +<div class="coffee" hidden role="dialog" aria-label="Coffee refill"> + <pre class="mug" aria-hidden="true"></pre> + <div class="coffee-info"> + <p class="winbar"><span class="file">*coffee*</span><span class="rule" aria-hidden="true"></span><span class="meta">q to close</span></p> + <p class="vcc"><span class="dim">VCC</span><span class="vbar" aria-hidden="true"></span><span class="volts">2.6 V</span></p> + <p class="coffee-msg" aria-live="polite">brewing…</p> + <p class="coffee-links"><a href="https://buymeacoffee.com/michaelneuper" target="_blank" rel="noopener">That one was simulated. Buy me an actual coffee</a></p> + </div> + <button type="button" class="coffee-close" aria-label="Close">×</button> +</div> +<div class="which-key" hidden aria-live="polite"></div> +<div class="frame-bottom"> + <div class="modeline"> + <span class="ml-evil" title="evil state"><N></span> + <span class="ml-buf">sap-1.asm</span> + <span class="ml-pos" aria-hidden="true">1:0</span> + <span class="ml-pct" aria-hidden="true">Top</span> + <span class="ml-spacer"></span> + <span class="ml-misc" aria-live="polite"></span> + <span class="ml-flags" aria-hidden="true"></span> + <span class="ml-mode">Asm</span> + <span class="ml-enc" aria-hidden="true">LF UTF-8</span> + <span class="ml-vc" aria-hidden="true">master</span> + <span class="ml-time" aria-hidden="true"></span> + </div> + <div class="mini" hidden> + <form class="mini-prompt" autocomplete="off"> + <label><span class="mini-count"></span><span class="mini-ps"></span><input type="text" spellcheck="false" autocapitalize="off" role="combobox" aria-expanded="true" aria-controls="mini-list" aria-autocomplete="list"></label> + </form> + <ul class="mini-list" id="mini-list" role="listbox"></ul> + </div> + <div class="echo" role="status"></div> +</div> + +<dialog class="help" aria-labelledby="help-title"> + <p class="winbar"><span class="file" id="help-title">*Help*</span><span class="rule" aria-hidden="true"></span><span class="meta">q or esc to close</span></p> + <div class="help-cols"> + <div> + <h3>Keys</h3> + <dl> + <div><dt><kbd>SPC</kbd></dt><dd>leader key: shows every command</dd></div> + <div><dt><kbd>M-x</kbd></dt><dd>run a command by name (Alt+x or Option+x)</dd></div> + <div><dt><kbd>SPC h t</kbd></dt><dd>load a theme, with live preview</dd></div> + <div><dt><kbd>:</kbd></dt><dd>evil ex commands, like <code>:q</code></dd></div> + <div><dt><kbd>C-g</kbd></dt><dd>cancel (so does <kbd>esc</kbd>)</dd></div> + </dl> + </div> + <div> + <h3>On this page</h3> + <dl> + <div><dt><kbd>c</kbd> <kbd>n</kbd> <kbd>r</kbd></dt><dd>computer: run or pause, step, reset</dd></div> + <div><dt><kbd>TAB</kbd></dt><dd>fold the Org heading under focus</dd></div> + <div><dt><kbd>S-TAB</kbd></dt><dd>cycle the whole Org buffer</dd></div> + <div><dt><code>coffee-refill</code></dt><dd>top up VCC and overclock the computer</dd></div> + <div><dt><code>submit-flag</code></dt><dd>check a CTF flag</dd></div> + </dl> + </div> + </div> + <form method="dialog"><button class="btn" type="submit">close</button></form> +</dialog> +</body> +</html> diff --git a/js/coffee.js b/src/scripts/coffee.js diff --git a/js/computer.js b/src/scripts/computer.js diff --git a/js/contact.js b/src/scripts/contact.js diff --git a/js/ctf.js b/src/scripts/ctf.js diff --git a/js/datasheet.js b/src/scripts/datasheet.js diff --git a/js/decode.js b/src/scripts/decode.js diff --git a/js/demos/bytecode.js b/src/scripts/demos/bytecode.js diff --git a/js/demos/computer.js b/src/scripts/demos/computer.js diff --git a/js/demos/othello.js b/src/scripts/demos/othello.js diff --git a/js/demos/rbudp.js b/src/scripts/demos/rbudp.js diff --git a/js/demos/scheduler.js b/src/scripts/demos/scheduler.js diff --git a/src/scripts/gitlog.js b/src/scripts/gitlog.js @@ -0,0 +1,226 @@ +// Experience as one-line git log --graph output, the "git lg" way: +// <date> - (refs) <subject> <author> +// with the date standing in for the hash and the company as the author. +// +// The rows are plain text in src/pages/index.astro, so they read fine without JavaScript. +// This colours the graph by branch (data-lanes), colours the date, refs and +// author, and turns subjects that have a .gl-desc into buttons that expand it. +// Lanes: m main, u undergrad, t teaching-assistant, b bbd-software, i mwr-internship. +// +// When the log is wider than its box (on a phone), it wraps the way a narrow +// terminal would: at word boundaries, with each wrapped line starting with the +// commit's lane pipes and a short hanging indent. + +import { $, $$ } from "./util.js"; + +const LANE_CLASS = { m: "lm", u: "lu", t: "lt", b: "lb", i: "li" }; +const ROW = /^([|*/\\ ]*?)(\d{4}-\d{2}(?:-\d{2})?) - (?:\(([^)]*)\) ?)?(.*?)(?: ?<([^>]*)>)?$/; +const HANG = 2; + +function el(tag, cls, text) { + const e = document.createElement(tag); + if (cls) e.className = cls; + if (text != null) e.textContent = text; + return e; +} + +// The graph characters, coloured by lane and hidden from screen readers. +// `tip` makes the commit's * bold. +function graph(text, lanes = "", tip = false) { + const g = el("span", "gl-graph"); + g.setAttribute("aria-hidden", "true"); + [...text].forEach((ch, i) => { + const lane = LANE_CLASS[(lanes[i] || " ").trim()]; + if (ch === "*" && tip) g.append(el("span", "gl-tip", ch)); + else g.append(lane && ch.trim() ? el("span", lane, ch) : ch); + }); + return g; +} + +// The HEAD commit is dated with the month the page is viewed in. +function today() { + const d = new Date(); + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`; +} + +function parse(div) { + const descEl = $(".gl-desc", div); + const body = descEl ? descEl.textContent.replace(/^\n+|\s+$/g, "").split("\n") : null; + descEl?.remove(); + const text = div.textContent.replace(/\s+$/, ""); + const m = ROW.exec(text); + const row = { + graph: m ? m[1] : text, lanes: div.dataset.lanes, cont: div.dataset.cont ?? "", contLanes: div.dataset.contLanes, + tip: "tip" in div.dataset, branch: div.dataset.branch, + }; + if (!m) return row; + return { + ...row, + date: "today" in div.dataset ? today() : m[2], + refs: m[3] ? m[3].split(/,\s*/).map((r) => (r.startsWith("HEAD -> ") ? { head: true, name: r.slice(8) } : { name: r })) : [], + subject: m[4], + author: m[5], + body, + }; +} + +const refsText = (refs) => `(${refs.map((r) => (r.head ? "HEAD -> " : "") + r.name).join(", ")})`; + +// A commit line as words, so it can be wrapped. Each word knows how to draw itself. +function words(row) { + const w = [{ text: row.date, cls: `gl-date ${LANE_CLASS[row.branch] ?? ""}` }, { text: "-" }]; + if (row.refs.length) w.push({ text: refsText(row.refs), refs: row.refs }); + if (row.subject) for (const s of row.subject.split(" ")) w.push({ text: s, subj: true }); + if (row.author) w.push({ text: `<${row.author}>`, cls: "gl-author" }); // kept on one line + return w; +} + +// Greedy word wrap. Returns lines of words; a word longer than the width gets a line to itself. +function wrap(list, width, hang) { + const lines = [[]]; + let used = 0; + for (const w of list) { + const line = lines[lines.length - 1]; + const need = (line.length ? 1 : 0) + w.text.length; + if (line.length && used + need > width) { + lines.push([w]); + used = hang + w.text.length; + } else { + line.push(w); + used += need; + } + } + return lines; +} + +// Re-flow a description to a width, keeping "- " bullets with a hanging indent. +function reflow(body, width) { + const blocks = []; + for (const line of body) { + if (line.startsWith("- ") || !blocks.length || !line.startsWith(" ")) blocks.push(line.trim()); + else blocks[blocks.length - 1] += ` ${line.trim()}`; + } + // plain paragraphs that were hard-wrapped become one block again + const merged = []; + for (const b of blocks) { + if (merged.length && !b.startsWith("- ") && !merged[merged.length - 1].startsWith("- ")) merged[merged.length - 1] += ` ${b}`; + else merged.push(b); + } + const out = []; + for (const b of merged) { + const bullet = b.startsWith("- "); + const lines = wrap(b.split(" ").map((text) => ({ text })), width, bullet ? 2 : 0); + lines.forEach((l, i) => out.push((i && bullet ? " " : "") + l.map((w) => w.text).join(" "))); + } + return out; +} + +export function initGitlog() { + const host = $(".gitlog"); + if (!host) return; + const rows = $$(":scope > .gl-line", host).map(parse); + const open = new Set(); + let lastCols = 0; + + function measureCols() { + const probe = el("span", "", "0".repeat(20)); + probe.style.cssText = "position:absolute;visibility:hidden;white-space:pre"; + host.append(probe); + const ch = probe.getBoundingClientRect().width / 20 || 7; + probe.remove(); + const cs = getComputedStyle(host); + const inner = host.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight); + return Math.max(24, Math.floor(inner / ch)); + } + + function render(focusRow = -1) { + const cols = measureCols(); + lastCols = cols; + const lineLen = (r) => r.graph.length + words(r).reduce((n, w, i) => n + (i ? 1 : 0) + w.text.length, 0); + const wide = rows.every((r) => !r.date || lineLen(r) <= cols); + const pipesOnly = (r) => r && !r.date && /^[| ]+$/.test(r.graph); + const frag = document.createDocumentFragment(); + + rows.forEach((row, n) => { + if (!row.date) { + const line = el("div", "gl-line"); + line.append(graph(row.graph, row.lanes)); + frag.append(line); + return; + } + + const isOpen = open.has(n); + const lines = wrap(words(row), cols - row.graph.length, HANG); + let subjSeen = false; + lines.forEach((ws, li) => { + const line = el("div", "gl-line"); + line.append(li ? graph(row.cont, row.contLanes) : graph(row.graph, row.lanes, row.tip)); + if (li) line.append(" ".repeat(HANG)); + // consecutive subject words on a line become one button (or span) so the underline is unbroken + for (let k = 0; k < ws.length; k++) { + if (k) line.append(" "); + const w = ws[k]; + if (w.subj) { + let text = w.text; + while (ws[k + 1]?.subj) text += ` ${ws[++k].text}`; + if (row.body) { + const b = el("button", "gl-subj", text); + b.type = "button"; + b.dataset.row = n; + b.setAttribute("aria-expanded", String(isOpen)); + if (subjSeen) b.tabIndex = -1; // one tab stop per commit, even when its subject wraps + line.append(b); + } else { + line.append(el("span", "gl-text", text)); + } + subjSeen = true; + } else if (w.refs) { + const refs = el("span", "gl-refs"); + refs.append("("); + w.refs.forEach((r, i) => { + if (i) refs.append(", "); + if (r.head) refs.append(el("span", "gl-head", "HEAD -> ")); + refs.append(el("span", "gl-branch", r.name)); + }); + refs.append(")"); + line.append(refs); + } else { + line.append(w.cls ? el("span", w.cls, w.text) : w.text); + } + } + frag.append(line); + }); + + if (row.body && isOpen) { + const refsLen = row.refs.length ? refsText(row.refs).length + 1 : 0; + // under the subject when there's room; otherwise a little deeper than wrapped lines + const indent = wide ? row.date.length + 3 + refsLen : HANG + 2; + const text = wide ? row.body : reflow(row.body, cols - row.cont.length - indent); + const tail = pipesOnly(rows[n + 1]) ? [] : [""]; + for (const t of [...text, ...tail]) { + const b = el("div", "gl-line gl-body"); + b.append(graph(row.cont, row.contLanes), t ? " ".repeat(indent) + t : ""); + frag.append(b); + } + } + }); + + host.replaceChildren(frag); + host.classList.add("is-built"); + if (focusRow >= 0) host.querySelector(`.gl-subj[data-row="${focusRow}"]`)?.focus({ preventScroll: true }); + } + + host.addEventListener("click", (e) => { + const b = e.target.closest(".gl-subj"); + if (!b) return; + const n = +b.dataset.row; + if (open.has(n)) open.delete(n); + else open.add(n); + render(n); + }); + + render(); + new ResizeObserver(() => { + if (measureCols() !== lastCols) render(); + }).observe(host); +} diff --git a/js/main.js b/src/scripts/main.js diff --git a/js/memmap.js b/src/scripts/memmap.js diff --git a/js/org.js b/src/scripts/org.js diff --git a/js/shell.js b/src/scripts/shell.js diff --git a/src/scripts/themes.js b/src/scripts/themes.js @@ -0,0 +1,19 @@ +// Themes for M-x load-theme. The colours live in src/styles/style.css under +// :root[data-theme="…"]; keep this list, that CSS and the inline script in +// src/pages/index.astro in sync. + +export const THEMES = [ + { id: "doom-gruvbox", desc: "Gruvbox, medium contrast. The theme my own Emacs uses" }, + { id: "doom-gruvbox-light", desc: "Gruvbox's light variant" }, + { id: "doom-one", desc: "Doom Emacs's default, inspired by Atom One Dark" }, + { id: "atom-one-dark", desc: "Atom's One Dark" }, + { id: "modus-vivendi", desc: "Emacs's built-in high-contrast dark theme" }, + { id: "modus-operandi", desc: "Emacs's built-in high-contrast light theme" }, + { id: "doom-dracula", desc: "Dracula" }, + { id: "doom-nord", desc: "Nord, arctic and north-bluish" }, + { id: "catppuccin", desc: "Catppuccin, Mocha flavour" }, + { id: "doom-tokyo-night", desc: "Tokyo Night" }, + { id: "doom-solarized-light", desc: "Solarized light" }, +]; + +export const DEFAULT_THEME = "doom-gruvbox"; diff --git a/js/util.js b/src/scripts/util.js diff --git a/src/styles/style.css b/src/styles/style.css @@ -0,0 +1,2443 @@ +/* ───────────────────────────── fonts ───────────────────────────── */ + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono-regular.woff2") format("woff2"); + font-weight: 400; + font-display: swap; +} + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono-semibold.woff2") format("woff2"); + font-weight: 600; + font-display: swap; +} + +/* Computer Modern, via KaTeX's build of it: the same family as Latin Modern */ +@font-face { + font-family: "Computer Modern"; + src: url("/fonts/cm-regular.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Computer Modern"; + src: url("/fonts/cm-italic.woff2") format("woff2"); + font-weight: 400; + font-style: italic; + font-display: swap; +} + +/* ───────────────────────────── themes ───────────────────────────── + Real Emacs themes. Each sets a background, a modeline background, + a foreground and seven accents; everything else is mixed from those. + Keep the names in sync with src/scripts/themes.js and the script in src/pages/index.astro. */ + +:root { + color-scheme: dark; + --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; + --serif: "Computer Modern", "Latin Modern Roman", "CMU Serif", Georgia, serif; + + --gutter: clamp(16px, 4.5vw, 56px); + --top-h: 44px; + --frame-h: 46px; + --col: 1088px; + + --bg: #282828; + --bg-alt: #3c3836; + --fg: #ebdbb2; + --red: #fb4934; + --orange: #fe8019; + --yellow: #fabd2f; + --green: #b8bb26; + --cyan: #8ec07c; + --blue: #83a598; + --magenta: #d3869b; + --glow: 1; + + --dim: color-mix(in srgb, var(--fg) 64%, var(--bg)); + --faint: color-mix(in srgb, var(--fg) 34%, var(--bg)); + --rule: color-mix(in srgb, var(--fg) 15%, var(--bg)); + --hl: color-mix(in srgb, var(--fg) 10%, var(--bg)); + --wash: color-mix(in srgb, var(--fg) 5%, transparent); + --led-off: color-mix(in srgb, var(--fg) 13%, var(--bg)); + --violet: color-mix(in oklch, var(--blue) 50%, var(--magenta)); + + --c-hw: var(--yellow); + --c-sw: var(--blue); + --c-math: var(--magenta); + --c-sec: var(--red); +} + +:root[data-theme="doom-gruvbox-light"] { + color-scheme: light; + --bg: #fbf1c7; --bg-alt: #ebdbb2; --fg: #3c3836; + --red: #9d0006; --orange: #af3a03; --yellow: #b57614; --green: #79740e; + --cyan: #427b58; --blue: #076678; --magenta: #8f3f71; + --glow: 0; +} + +:root[data-theme="doom-one"] { + --bg: #282c34; --bg-alt: #21242b; --fg: #bbc2cf; + --red: #ff6c6b; --orange: #da8548; --yellow: #ecbe7b; --green: #98be65; + --cyan: #46d9ff; --blue: #51afef; --magenta: #c678dd; +} + +:root[data-theme="atom-one-dark"] { + --bg: #282c34; --bg-alt: #21252b; --fg: #abb2bf; + --red: #e06c75; --orange: #d19a66; --yellow: #e5c07b; --green: #98c379; + --cyan: #56b6c2; --blue: #61afef; --magenta: #c678dd; +} + +:root[data-theme="modus-vivendi"] { + --bg: #000000; --bg-alt: #1e1e1e; --fg: #ffffff; + --red: #ff5f59; --orange: #fec43f; --yellow: #d0bc00; --green: #44bc44; + --cyan: #00d3d0; --blue: #2fafff; --magenta: #feacd0; +} + +:root[data-theme="modus-operandi"] { + color-scheme: light; + --bg: #ffffff; --bg-alt: #f2f2f2; --fg: #000000; + --red: #a60000; --orange: #884900; --yellow: #6f5500; --green: #006800; + --cyan: #005e8b; --blue: #0031a9; --magenta: #721045; + --glow: 0; +} + +:root[data-theme="doom-dracula"] { + --bg: #282a36; --bg-alt: #1e2029; --fg: #f8f8f2; + --red: #ff5555; --orange: #ffb86c; --yellow: #f1fa8c; --green: #50fa7b; + --cyan: #8be9fd; --blue: #61bfff; --magenta: #ff79c6; +} + +:root[data-theme="doom-nord"] { + --bg: #2e3440; --bg-alt: #3b4252; --fg: #eceff4; + --red: #bf616a; --orange: #d08770; --yellow: #ebcb8b; --green: #a3be8c; + --cyan: #88c0d0; --blue: #81a1c1; --magenta: #b48ead; +} + +:root[data-theme="catppuccin"] { + --bg: #1e1e2e; --bg-alt: #181825; --fg: #cdd6f4; + --red: #f38ba8; --orange: #fab387; --yellow: #f9e2af; --green: #a6e3a1; + --cyan: #94e2d5; --blue: #89b4fa; --magenta: #cba6f7; +} + +:root[data-theme="doom-tokyo-night"] { + --bg: #1a1b26; --bg-alt: #16161e; --fg: #c0caf5; + --red: #f7768e; --orange: #ff9e64; --yellow: #e0af68; --green: #9ece6a; + --cyan: #7dcfff; --blue: #7aa2f7; --magenta: #bb9af7; +} + +:root[data-theme="doom-solarized-light"] { + color-scheme: light; + --bg: #fdf6e3; --bg-alt: #eee8d5; --fg: #556b72; + --red: #dc322f; --orange: #cb4b16; --yellow: #b58900; --green: #859900; + --cyan: #2aa198; --blue: #268bd2; --magenta: #d33682; + --glow: 0; +} + +[data-cat="hw"] { --c: var(--c-hw); } +[data-cat="sw"] { --c: var(--c-sw); } +[data-cat="math"] { --c: var(--c-math); } +[data-cat="sec"] { --c: var(--c-sec); } + +/* ───────────────────────────── base ───────────────────────────── */ + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + background: var(--bg); + color: var(--fg); + scroll-behavior: smooth; + scroll-snap-type: y proximity; + scroll-padding-top: calc(var(--top-h) + 24px); + -webkit-text-size-adjust: 100%; + text-size-adjust: 100%; +} + +body { + margin: 0; + font: 400 13px/1.6 var(--mono); + font-variant-ligatures: none; + -webkit-font-smoothing: antialiased; + transition: background-color 200ms ease, color 200ms ease; +} + +::selection { + background: color-mix(in srgb, var(--blue) 35%, var(--bg)); + color: var(--fg); +} + +a { + color: inherit; + text-decoration-line: underline; + text-decoration-thickness: 1px; + text-decoration-color: var(--faint); + text-underline-offset: 0.2em; +} + +a:hover { + text-decoration-color: currentColor; +} + +button, +input, +output, +select { + font: inherit; + color: inherit; +} + +button { + cursor: pointer; +} + +:focus-visible { + outline: 1px solid var(--fg); + outline-offset: 2px; +} + +kbd { + font: inherit; + font-size: 0.95em; + padding: 0 0.45ch; + border: 1px solid var(--faint); + border-radius: 3px; +} + +code { + font-family: var(--mono); + font-size: 0.95em; +} + +.dim { + color: var(--dim); +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; +} + +.skip { + position: absolute; + left: 8px; + top: -100px; + z-index: 50; + padding: 6px 12px; + background: var(--fg); + color: var(--bg); +} + +.skip:focus { + top: 8px; +} + +.btn { + display: inline-flex; + align-items: center; + min-height: 30px; + padding: 0 14px; + border: 1px solid var(--faint); + border-radius: 0; + background: none; + font-size: 12px; + line-height: 1; + white-space: nowrap; +} + +.btn:hover { + border-color: var(--fg); +} + +.btn[aria-pressed="true"] { + border-color: var(--fg); + background: var(--fg); + color: var(--bg); +} + +/* ───────────────────────────── top line ───────────────────────────── */ + +.top { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 20; + display: flex; + align-items: center; + gap: 3ch; + height: var(--top-h); + padding: 0 var(--gutter); + font-size: 12px; + border-bottom: 1px solid transparent; + transition: background-color 200ms ease, border-color 200ms ease; +} + +.is-scrolled .top { + background: color-mix(in srgb, var(--bg) 90%, transparent); + border-bottom-color: var(--rule); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); +} + +.brand { + display: inline-flex; + align-items: center; + gap: 1.5ch; + margin-right: auto; + text-decoration: none; +} + +.logo { + width: 22px; + height: 11px; + overflow: visible; + fill: none; + stroke: currentColor; + stroke-width: 1.6; +} + +.nav { + display: flex; + gap: 2.5ch; +} + +.nav a { + color: var(--dim); + text-decoration: none; +} + +.nav a:hover, +.nav a[aria-current="true"] { + color: var(--fg); +} + +.nav a[aria-current="true"] { + text-decoration: underline; + text-decoration-color: var(--fg); + text-underline-offset: 6px; +} + +.theme-key, +.menu-key { + padding: 8px 0; + border: 0; + background: none; + color: var(--dim); + font-size: 12px; +} + +.theme-key:hover, +.menu-key:hover { + color: var(--fg); +} + +.menu-key { + display: none; +} + +/* ───────────────────────────── hero: the computer ───────────────────────────── */ + +.hero { + display: grid; + grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); + gap: 32px clamp(32px, 4vw, 64px); + align-items: center; + min-height: 100vh; + min-height: 100svh; + padding: calc(var(--top-h) + 28px) var(--gutter) calc(var(--frame-h) + 32px); + max-width: 1440px; + margin: 0 auto; +} + +.hero-name { + margin: 0 0 20px -0.04em; + font: 400 clamp(46px, 6.4vw, 96px)/0.94 var(--serif); + letter-spacing: -0.015em; +} + +/* On load the name decodes itself (src/scripts/decode.js): each letter starts as a byte + with a few bits flipped and changes one bit at a time until it is right. */ + +.boot .hero-name { + visibility: hidden; + animation: boot-failsafe 0s 2.5s forwards; +} + +@keyframes boot-failsafe { + to { visibility: visible; } +} + +/* each letter sits in a box as wide as the final letter, and whatever + character it shows is centred in it */ +.hero-name.is-cells .bc { + display: inline-block; + text-align: center; +} + +.hero-name.is-cells .bc-ch { + display: inline-block; + margin-inline: -1em; + white-space: pre; +} + +.bc-word { + white-space: nowrap; +} + +/* a wrong byte shows as a raw character in the mono face */ +.bc.is-wrong { + color: var(--dim); +} + +.bc.is-wrong .bc-ch { + font-family: var(--mono); + font-size: 0.78em; + letter-spacing: 0; +} + +.hero-lede { + max-width: 44ch; + margin: 0 0 20px; + font-size: 14px; + line-height: 1.6; +} + +.legend { + display: flex; + flex-wrap: wrap; + gap: 4px 2.5ch; + margin: 0; + padding: 0; + list-style: none; + font-size: 12px; + color: var(--dim); +} + +.legend li::before, +.features li::before { + content: ""; + display: inline-block; + width: 7px; + height: 7px; + margin-right: 1ch; + background: var(--c, var(--fg)); + vertical-align: 0.06em; +} + +/* landing: the MN-2026 pinout */ + +.hero-chip { + justify-self: center; + width: min(100%, 460px); +} + +.hero-chip .chip { + grid-template-columns: minmax(0, 1fr) 128px minmax(0, 1fr); + font-size: 13px; +} + +.hero-chip .pin { + height: 34px; +} + +.hero-chip .pin .leg { + height: 9px; +} + +.hero-chip .pin-readout { + min-height: 6.5em; +} + +/* the 8-bit computer, as the project's demo */ + +.demo-wide { + margin-top: 40px; + padding-top: 28px; + border-top: 1px solid var(--rule); +} + +.sim-bar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px 10px; + margin-top: 16px; + font-size: 12px; +} + +.sim-field { + display: inline-flex; + align-items: center; + gap: 1.2ch; + margin-left: 1.5ch; + color: var(--dim); +} + +.sim-field output { + min-width: 7ch; + color: var(--fg); + font-variant-numeric: tabular-nums; +} + +select { + min-height: 30px; + padding: 0 28px 0 10px; + border: 1px solid var(--faint); + border-radius: 0; + background: var(--bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23888'/%3E%3C/svg%3E") no-repeat right 10px center; + color: var(--fg); + font-size: 12px; + -webkit-appearance: none; + appearance: none; +} + +input[type="range"] { + width: 120px; + height: 22px; + margin: 0; + background: transparent; + -webkit-appearance: none; + appearance: none; +} + +input[type="range"]::-webkit-slider-runnable-track { + height: 1px; + background: var(--faint); +} + +input[type="range"]::-moz-range-track { + height: 1px; + background: var(--faint); +} + +input[type="range"]::-webkit-slider-thumb { + width: 9px; + height: 18px; + margin-top: -9px; + border: 0; + border-radius: 0; + background: var(--fg); + -webkit-appearance: none; + appearance: none; +} + +input[type="range"]::-moz-range-thumb { + width: 9px; + height: 18px; + border: 0; + border-radius: 0; + background: var(--fg); +} + +.sim-note { + max-width: 78ch; + margin: 12px 0 0; + font-size: 12px; + line-height: 1.6; + color: var(--dim); +} + +/* board: Ben Eater's layout, two columns of modules either side of the bus */ + +.board { + --led: 10px; + display: grid; + grid-template-columns: minmax(0, 1fr) 64px minmax(0, 1fr); + grid-template-areas: + "left bus right" + "ctrl ctrl ctrl"; + gap: 10px; + font-size: 11.5px; + font-variant-numeric: tabular-nums; +} + +.col { + display: flex; + flex-direction: column; + gap: 10px; +} + +.col-l { grid-area: left; } +.col-r { grid-area: right; } + +.mod { + padding: 7px 10px 9px; + border: 1px solid var(--rule); + background: color-mix(in srgb, var(--bg) 92%, var(--fg)); +} + +.mod.is-out { + border-color: var(--red); +} + +.mod.is-in { + border-color: var(--green); +} + +.mod-head { + display: flex; + align-items: baseline; + gap: 1ch; + margin-bottom: 6px; + color: var(--dim); + white-space: nowrap; +} + +.mod-name { + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; +} + +.sig { + padding: 0 0.4ch; + border-radius: 2px; + color: var(--faint); + font-size: 10.5px; +} + +.sig.on { + background: var(--blue); + color: var(--bg); +} + +.mod-body { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1ch; +} + +.mod-val { + color: var(--fg); + white-space: nowrap; +} + +.leds { + display: flex; + gap: calc(var(--led) * 0.45); +} + +.led { + display: block; + flex: none; + width: var(--led); + height: var(--led); + padding: 0; + border: 0; + border-radius: 50%; + background: var(--led-off); + --lc: var(--red); +} + +.led.on { + background: var(--lc); + box-shadow: 0 0 calc(var(--glow) * 7px) calc(var(--glow) * 1px) color-mix(in srgb, var(--lc) 70%, transparent); +} + +.led.g { --lc: var(--green); } +.led.y { --lc: var(--yellow); } +.led.b { --lc: var(--blue); } + +.leds .gap { + width: calc(var(--led) * 0.4); +} + +/* RAM: the whole 16-byte memory as a matrix you can edit */ + +.ram-rows { + display: grid; + gap: 1px; +} + +.ram-row { + --led: 8px; + display: grid; + grid-template-columns: 1.5ch 2ch auto minmax(0, 1fr); + align-items: center; + gap: 0.8ch; + padding: 1px 4px; + margin: 0 -4px; + line-height: 14px; +} + +.ram-row.is-mar { + background: var(--hl); +} + +.ram-row .pc { + color: var(--green); +} + +.ram-row .addr { + color: var(--dim); +} + +.ram-row .dis { + overflow: hidden; + color: var(--dim); + white-space: nowrap; + text-overflow: ellipsis; +} + +.ram-row.is-mar .dis { + color: var(--fg); +} + +.ram-row .led { + cursor: pointer; +} + +.ram-row .led:hover { + outline: 1px solid var(--faint); + outline-offset: 1px; +} + +/* the bus: eight lanes down the middle */ + +.bus { + grid-area: bus; + display: flex; + flex-direction: column; + align-items: center; + padding: 7px 0 9px; + border: 1px solid var(--rule); +} + +.bus .mod-head { + margin-bottom: 4px; +} + +.bus-val { + margin-bottom: 8px; +} + +.lanes { + display: flex; + flex: 1; + gap: 4px; +} + +.lane { + width: 2px; + background: var(--led-off); +} + +.lane.on { + background: var(--red); + box-shadow: 0 0 calc(var(--glow) * 6px) color-mix(in srgb, var(--red) 70%, transparent); +} + +/* output: a 7-segment display */ + +.seg7 { + display: flex; + gap: 6px; +} + +.seg7 svg { + width: 22px; + height: 38px; + overflow: visible; +} + +.seg7 path { + fill: var(--led-off); +} + +.seg7 path.on { + fill: var(--red); + filter: drop-shadow(0 0 calc(var(--glow) * 3px) color-mix(in srgb, var(--red) 80%, transparent)); +} + +.mod-out .mod-body { + cursor: pointer; +} + +/* control word */ + +.ctrl { + grid-area: ctrl; +} + +.ctrl-row { + display: flex; + flex-wrap: wrap; + align-items: flex-end; + gap: 8px 18px; +} + +.cw { + display: flex; + flex-wrap: wrap; + gap: 4px; +} + +.cw-bit { + display: flex; + flex-direction: column; + align-items: center; + gap: 3px; + width: 3.4ch; + color: var(--faint); + font-size: 10px; +} + +.cw-bit.on { + color: var(--fg); +} + +.ustep { + margin-top: 8px; + color: var(--dim); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.ustep b { + color: var(--fg); + font-weight: 600; +} + +/* ───────────────────────────── sections ───────────────────────────── */ + +.sec { + max-width: var(--col); + margin: 0 auto; + padding: 136px var(--gutter) 0; +} + +.hero, +.sec > .winbar { + scroll-snap-align: start; +} + +.winbar { + display: flex; + align-items: center; + gap: 1.5ch; + margin: 0 0 56px; + font-size: 12px; + line-height: 1; + color: var(--dim); +} + +.winbar .file { + color: var(--fg); +} + +.winbar .rule { + flex: 1; + height: 1px; + background: var(--rule); +} + +.h2 { + max-width: 17em; + margin: 0 0 20px; + font: 400 clamp(36px, 5.4vw, 62px)/1.04 var(--serif); + letter-spacing: -0.01em; +} + +.lede, +.prose { + max-width: 34em; + margin: 0 0 48px; + font: 400 19px/1.55 var(--serif); +} + +.prose { + margin-bottom: 0; +} + +.lede kbd { + font: 400 13px/1 var(--mono); + vertical-align: 0.15em; +} + +.sub-h { + margin: 72px 0 8px; + font: 400 28px/1.15 var(--serif); +} + +.sub-p { + max-width: 34em; + margin: 0 0 28px; + font: 400 17px/1.55 var(--serif); +} + +/* ───────────────────────────── datasheet ───────────────────────────── */ + +.ds-head { + display: grid; + grid-template-columns: 14ch minmax(0, 1fr); + gap: 8px 2ch; + align-items: baseline; + padding-top: 16px; + border-top: 2px solid var(--fg); +} + +.ds-part { + margin: 0; + font-weight: 600; + font-size: 15px; +} + +.ds-title { + max-width: 19em; + margin: 0; + font: 400 clamp(28px, 3.8vw, 44px)/1.1 var(--serif); +} + +.ds-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 400px); + gap: 72px; + align-items: start; +} + +.ds-desc { + margin: 40px 0 0; +} + +.ds-h { + margin: 48px 0 16px; + font-size: 12px; + font-weight: 600; + line-height: 1.4; +} + +.features { + margin: 0; + padding: 0; + list-style: none; +} + +.features li { + max-width: 62ch; + margin-bottom: 8px; + padding-left: 3ch; + text-indent: -3ch; +} + +.features li::before { + margin-right: 2ch; + text-indent: 0; +} + +.pinout { + margin: 0; +} + +.chip { + display: grid; + grid-template-columns: minmax(0, 1fr) 104px minmax(0, 1fr); + font-size: 12px; +} + +.chip-side { + display: flex; + flex-direction: column; + padding: 10px 0; +} + +.chip-body { + position: relative; + border: 1px solid var(--fg); + border-radius: 2px; +} + +.chip-body::before { + content: ""; + position: absolute; + top: -1px; + left: 50%; + width: 20px; + height: 10px; + border: 1px solid var(--fg); + border-top: 0; + border-radius: 0 0 10px 10px; + background: var(--bg); + transform: translateX(-50%); +} + +.chip-body span { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + color: var(--dim); + writing-mode: vertical-rl; + letter-spacing: 0.2em; +} + +.pin { + display: grid; + align-items: center; + height: 28px; + padding: 0; + border: 0; + background: none; + color: var(--dim); + text-align: left; +} + +.chip-side.left .pin { + grid-template-columns: 1fr 3ch 16px; + text-align: right; +} + +.chip-side.right .pin { + grid-template-columns: 16px 3ch 1fr; +} + +.pin .num { + text-align: center; + font-size: 11px; +} + +.pin .leg { + height: 8px; + border: 1px solid var(--faint); +} + +.chip-side.left .leg { + border-right: 0; +} + +.chip-side.right .leg { + border-left: 0; +} + +.pin .name { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.pin:hover, +.pin.is-active { + color: var(--fg); +} + +.pin.is-active .name { + color: var(--c, var(--fg)); + font-weight: 600; +} + +.pin.is-active .leg { + border-color: var(--c, var(--fg)); + background: var(--c, var(--fg)); +} + +.pin-readout { + min-height: 7.5em; + margin-top: 20px; + padding-top: 12px; + border-top: 1px solid var(--rule); + font-size: 12px; +} + +.pin-readout p { + margin: 0; +} + +.pin-readout .pr-head { + display: flex; + gap: 2ch; + margin-bottom: 6px; +} + +.pin-readout .pr-name { + color: var(--c, var(--fg)); + font-weight: 600; +} + +.pinout figcaption { + margin-top: 8px; + font-size: 12px; + color: var(--dim); +} + +.pin-list { + margin: 16px 0 0; + padding-left: 3ch; + font-size: 12px; +} + +.pinout.is-built .pin-list { + display: none; +} + +.pin-list li::before { + content: attr(data-name) " (" attr(data-type) ") "; + font-weight: 600; +} + +.ds-note { + margin: -8px 0 14px; + font-size: 12px; + color: var(--dim); +} + +.table-scroll { + overflow-x: auto; +} + +.ds-table { + width: 100%; + min-width: 560px; + border-collapse: collapse; + font-size: 12.5px; + font-variant-numeric: tabular-nums; +} + +.ds-table th, +.ds-table td { + padding: 8px 1.5ch 8px 0; + border-bottom: 1px solid var(--rule); + text-align: left; + vertical-align: baseline; +} + +.ds-table thead th { + border-top: 1px solid var(--fg); + border-bottom-color: var(--fg); + font-weight: 600; +} + +.ds-table tbody th { + font-weight: 400; +} + +.ds-table td:nth-child(2) { + color: var(--dim); +} + +.ds-table .num { + text-align: right; + padding-right: 3ch; +} + +/* experience as git log --graph --color */ + +.gitlog-cmd { + margin-bottom: 12px; + font-weight: 400; + color: var(--fg); + line-height: 1.5; + white-space: pre-wrap; + overflow-wrap: anywhere; +} + +.gitlog-cmd .prompt { + color: var(--green); +} + +.gitlog { + padding: 16px 18px; + overflow-x: auto; + border: 1px solid var(--rule); + font-size: 12px; + line-height: 1.7; + color: var(--fg); +} + +.gl-line { + width: max-content; + white-space: pre; +} + +/* one colour per branch */ +.gitlog .lm { color: var(--magenta); } /* main */ +.gitlog .lu { color: var(--green); } /* undergrad */ +.gitlog .lt { color: var(--yellow); } /* teaching-assistant */ +.gitlog .lb { color: var(--red); } /* bbd-software */ +.gitlog .li { color: var(--blue); } /* mwr-internship */ + +.gl-tip { + color: var(--fg); + font-weight: 600; +} + +.gl-refs { + color: var(--yellow); +} + +.gl-head { + color: var(--cyan); + font-weight: 600; +} + +.gl-branch { + color: var(--green); + font-weight: 600; +} + +.gl-author { + color: var(--blue); +} + +.gl-subj { + padding: 0; + border: 0; + background: none; + color: inherit; + font: inherit; + white-space: pre; + text-decoration: underline dotted; + text-decoration-color: var(--faint); + text-underline-offset: 0.25em; +} + +.gl-subj:hover, +.gl-subj[aria-expanded="true"] { + text-decoration-style: solid; + text-decoration-color: currentColor; +} + +.gl-body, +.gl-desc { + color: var(--dim); +} + +/* before the script runs (or without it), descriptions show under their commit */ +.gl-desc { + display: block; + padding-left: 4ch; +} + +.gitlog-hint { + margin: 8px 0 0; + font-size: 12px; +} + +/* ───────────────────────────── memory map ───────────────────────────── */ + +.mm { + --mm-cols: 8ch 8ch minmax(0, 1fr) 8ch; +} + +.mm-bar { + display: flex; + height: 36px; + margin-bottom: 32px; + border: 1px solid var(--rule); +} + +.mm-seg { + min-width: 3px; + padding: 0 6px; + overflow: hidden; + border-right: 1px solid var(--bg); + background: color-mix(in srgb, var(--c) 20%, transparent); + box-shadow: inset 0 2px 0 var(--c); + font-size: 11px; + line-height: 34px; + white-space: nowrap; + cursor: pointer; + transition: background-color 120ms ease; +} + +.mm-seg:last-child { + border-right: 0; +} + +.mm-seg:hover { + background: color-mix(in srgb, var(--c) 34%, transparent); +} + +.mm-seg.is-active { + background: var(--c); + color: var(--bg); +} + +.mm-cols { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); + gap: 48px; + align-items: start; +} + +.mm-head { + display: grid; + grid-template-columns: var(--mm-cols); + gap: 1.5ch; + margin: 0; + padding: 0 0 8px 12px; + border-bottom: 1px solid var(--rule); + font-size: 12px; + color: var(--dim); +} + +.mm-list { + margin: 0; + padding: 0; + list-style: none; +} + +.proj-name { + margin: 0; + font: inherit; +} + +.proj-row { + display: grid; + grid-template-columns: var(--mm-cols); + gap: 1.5ch; + align-items: baseline; + width: 100%; + padding: 11px 0 11px 12px; + border: 0; + border-bottom: 1px solid var(--rule); + background: none; + text-align: left; + font-size: 13px; + font-variant-numeric: tabular-nums; +} + +.proj-row:hover { + background: var(--wash); +} + +.proj-row .o, +.proj-row .l, +.proj-row .y { + font-size: 12px; + color: var(--dim); +} + +.proj-row .n { + font-weight: 600; +} + +.proj-row .n::before { + content: ""; + display: inline-block; + width: 7px; + height: 7px; + margin-right: 1.2ch; + background: var(--c); + vertical-align: 0.06em; +} + +.proj-row .s { + display: block; + margin-top: 2px; + font-weight: 400; + color: var(--dim); +} + +.proj-row[aria-pressed="true"] { + background: var(--wash); + box-shadow: inset 2px 0 0 var(--c); +} + +.proj-row[aria-pressed="true"] .o, +.proj-row[aria-pressed="true"] .l { + color: var(--c); +} + +.mm.is-built .proj-sum, +.mm.is-built .proj > .proj-body { + display: none; +} + +.mm-detail { + min-height: 320px; + padding-left: 32px; + border-left: 1px solid var(--rule); +} + +.mm-detail:empty { + display: none; +} + +.hex { + margin: 0 0 22px; + overflow-x: auto; + font-size: 11.5px; + line-height: 1.55; + color: var(--dim); + white-space: pre; +} + +.hex .a { + color: var(--fg); +} + +.hex .addr { + color: var(--c); +} + +.mm-detail h3 { + margin: 0 0 14px; + font: 400 32px/1.1 var(--serif); +} + +.mm-detail .proj-body p { + margin: 0 0 14px; + font: 400 17px/1.55 var(--serif); +} + +.mm-detail .proj-body .proj-stack, +.mm-detail .proj-body .proj-links { + font: 400 12px/1.6 var(--mono); +} + +.proj-stack { + color: var(--dim); +} + +.proj-links a { + margin-right: 2ch; +} + +/* project demos */ + +.demo { + margin-top: 22px; + padding-top: 18px; + border-top: 1px solid var(--rule); + font-size: 12px; +} + +.demo-bar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + margin-bottom: 12px; +} + +.demo-bar .dim { + margin-left: auto; +} + +.demo canvas { + display: block; + width: 100%; +} + +.demo pre { + margin: 0; + font-size: 12px; + line-height: 1.2; + user-select: none; + -webkit-user-select: none; +} + +.demo .cap { + margin: 10px 0 0; + color: var(--dim); +} + +.bc-input { + display: flex; + align-items: center; + gap: 1ch; + margin-bottom: 12px; +} + +.bc-input input { + flex: 1; + min-width: 0; + min-height: 30px; + padding: 0 10px; + border: 1px solid var(--faint); + border-radius: 0; + background: none; + font-size: 13px; +} + +.bc-input input:focus { + border-color: var(--fg); + outline: none; +} + +.bc-cols { + display: grid; + grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); + gap: 16px; +} + +.bc-code { + margin: 0; + padding: 0; + list-style: none; + font-variant-numeric: tabular-nums; +} + +.bc-code li { + display: grid; + grid-template-columns: 4ch 1fr; + gap: 1ch; + padding: 1px 6px; +} + +.bc-code li.is-pc { + background: var(--hl); +} + +.bc-code .off { + color: var(--dim); + text-align: right; +} + +.bc-code .op { + color: var(--blue); +} + +.bc-stack { + display: flex; + flex-direction: column-reverse; + justify-content: flex-start; + gap: 2px; + min-height: 120px; + padding: 6px; + border: 1px solid var(--rule); + border-top: 0; +} + +.bc-stack span { + padding: 2px 8px; + border: 1px solid var(--faint); + text-align: right; +} + +.bc-stack span:last-child { + border-color: var(--fg); +} + +.bc-err { + color: var(--red); + white-space: pre; +} + +/* othello */ + +.oth { + display: grid; + grid-template-columns: repeat(8, minmax(0, 1fr)); + gap: 2px; + width: min(100%, 336px); + aspect-ratio: 1; + padding: 2px; + background: color-mix(in srgb, var(--fg) 25%, var(--bg)); +} + +.oth-cell { + position: relative; + padding: 0; + border: 0; + border-radius: 0; + background: color-mix(in srgb, var(--green) 28%, var(--bg)); + cursor: default; +} + +.oth-cell.legal { + cursor: pointer; +} + +.oth-cell.legal::after { + content: ""; + position: absolute; + inset: 40%; + border-radius: 50%; + background: var(--fg); + opacity: 0.4; +} + +.oth-cell.last { + box-shadow: inset 0 0 0 2px var(--yellow); +} + +.oth-cell .disc { + position: absolute; + inset: 12%; + border-radius: 50%; +} + +.oth-cell .disc.b { + background: #1b1b1b; + box-shadow: 0 0 0 1px rgb(0 0 0 / 0.35); +} + +.oth-cell .disc.w { + background: #f1efe8; + box-shadow: 0 0 0 1px rgb(0 0 0 / 0.15); +} + +.oth-cell .heat { + position: absolute; + inset: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + background: color-mix(in srgb, var(--blue) var(--hp, 0%), transparent); + color: var(--fg); + font-size: 10px; +} + +.oth-cell .heat:empty { + background: none; +} + +/* rbudp */ + +.rb-canvas { + height: 200px; +} + +.rb-log { + max-height: 9.8em; + margin: 10px 0 0; + padding: 8px 10px; + overflow-y: auto; + border: 1px solid var(--rule); + list-style: none; + font-size: 11.5px; + line-height: 1.6; +} + +.rb-log li { + display: grid; + grid-template-columns: 8ch 5ch minmax(0, 1fr); + gap: 1ch; +} + +.rb-proto { + color: var(--cyan); +} + +.sched-legend { + display: flex; + flex-wrap: wrap; + gap: 4px 12px; + margin-top: 8px; + color: var(--dim); +} + +/* ───────────────────────────── posts: an Org buffer ───────────────────────────── */ + +.org { + max-width: 880px; + font-size: 13px; + line-height: 1.75; +} + +.org-kw { + margin: 0; + font: inherit; + color: var(--dim); +} + +.org-kw .v { + color: var(--fg); +} + +.org-title { + color: var(--fg); + font-weight: 600; +} + +.org-p { + max-width: 76ch; + margin: 20px 0 0; + font-size: 13px; + line-height: 1.75; +} + +.org > .org-tree { + margin-top: 20px; +} + +.org-tree { + margin: 0; + padding: 0; + list-style: none; +} + +.org-h { + display: flex; + align-items: baseline; + gap: 1ch; +} + +.org-h:focus-visible { + outline: none; + background: var(--hl); +} + +.org-stars { + flex: none; + padding: 0; + border: 0; + background: none; + color: inherit; + font: inherit; +} + +.org-h1 > .org-h { + color: var(--blue); + font-weight: 600; +} + +.org-h2 > .org-h { + color: var(--magenta); +} + +.org-h2 a { + min-width: 0; + color: inherit; + text-decoration: none; +} + +.org-h2 a:hover { + text-decoration: underline; + text-decoration-thickness: 1px; +} + +.org-h .count, +.org-ellipsis { + color: var(--dim); + font-weight: 400; +} + +.org-tags { + flex: none; + margin-left: auto; + padding-left: 2ch; + color: var(--dim); + white-space: nowrap; +} + +.org-tags .t { + color: var(--tag, var(--dim)); +} + +.org-drawer { + margin: 0 0 6px 3ch; + overflow-x: auto; + color: var(--dim); + font-size: 12px; + line-height: 1.6; + white-space: pre; +} + +.org-drawer .k { + color: var(--faint); +} + +.org-drawer .ts { + color: var(--cyan); +} + +.org-drawer a { + color: var(--fg); +} + +/* ───────────────────────────── contact ───────────────────────────── */ + +.contact { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 16px 32px; + margin-bottom: 8px; +} + +.mail { + font: 400 clamp(26px, 4.4vw, 52px)/1.1 var(--serif); + overflow-wrap: anywhere; +} + +.mail .at { + font: 400 0.42em/1 var(--mono); + color: var(--dim); + vertical-align: 0.35em; + white-space: pre; +} + +.linkish { + padding: 0; + border: 0; + background: none; + color: inherit; + font: inherit; + text-decoration: underline; + text-decoration-thickness: 1px; + text-decoration-color: var(--faint); + text-underline-offset: 0.2em; +} + +.linkish:hover { + text-decoration-color: currentColor; +} + +.contact-grid { + display: grid; + grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); + gap: 0 56px; +} + +.gpg-fp { + display: flex; + flex-wrap: wrap; + gap: 4px 2ch; + margin: 0 0 12px; +} + +.gpg-fp code { + letter-spacing: 0.02em; +} + +.gpg-cmd { + display: flex; + align-items: stretch; + gap: 8px; +} + +.gpg-cmd pre { + flex: 1; + min-width: 0; + margin: 0; + padding: 7px 12px; + overflow-x: auto; + border: 1px solid var(--rule); + background: var(--wash); + font-size: 12px; +} + +.elsewhere { + display: flex; + flex-wrap: wrap; + gap: 8px 3ch; + margin: 0; + padding: 0; + list-style: none; +} + +.ctf { + max-width: 70ch; + margin-top: 16px; +} + +.ctf p { + margin: 0 0 12px; +} + +.ctf-row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 12px 2ch; +} + +.ctf-progress { + color: var(--dim); +} + +.ctf-progress.done { + color: var(--green); +} + +.foot { + max-width: var(--col); + margin: 0 auto; + padding: 160px var(--gutter) calc(var(--frame-h) + 48px); + font-size: 12px; +} + +.foot p { + margin: 0 0 4px; +} + +/* ───────────────────────────── modeline, minibuffer, which-key ───────────────────────────── */ + +.frame-bottom { + position: fixed; + left: 0; + right: 0; + bottom: 0; + z-index: 30; + padding-bottom: env(safe-area-inset-bottom, 0px); + background: var(--bg); + font-size: 12px; + white-space: nowrap; +} + +.modeline { + display: flex; + align-items: stretch; + height: 24px; + line-height: 24px; + background: var(--bg-alt); + color: var(--fg); +} + +/* doom-modeline's bar */ +.modeline::before { + content: ""; + flex: none; + width: 4px; + background: var(--blue); +} + +.modeline > span { + padding: 0 1ch; +} + +.ml-evil { + color: var(--green); + font-weight: 600; +} + +.modeline[data-evil="I"] .ml-evil { color: var(--yellow); } +.modeline[data-evil="V"] .ml-evil { color: var(--magenta); } +.modeline[data-evil="E"] .ml-evil { color: var(--cyan); } + +.ml-buf { + font-weight: 600; +} + +.ml-pos, +.ml-pct, +.ml-enc, +.ml-time { + color: var(--dim); +} + +.ml-spacer { + flex: 1; + padding: 0 !important; +} + +.ml-flags { + color: var(--green); +} + +.ml-mode { + color: var(--blue); + font-weight: 600; +} + +.ml-vc { + color: var(--green); +} + +.echo { + height: 22px; + padding: 0 1ch; + overflow: hidden; + line-height: 22px; + color: var(--dim); + text-overflow: ellipsis; +} + +.echo.is-error { + color: var(--red); +} + +.echo.is-ok { + color: var(--green); +} + +.mini:not([hidden]) ~ .echo { + display: none; +} + +.mini-prompt { + margin: 0; +} + +.mini-prompt label { + display: flex; + height: 22px; + padding: 0 1ch; + line-height: 22px; +} + +.mini-count { + min-width: 6ch; + color: var(--dim); +} + +.mini-ps { + color: var(--blue); + white-space: pre; +} + +.mini-prompt input { + flex: 1; + min-width: 0; + padding: 0; + border: 0; + outline: 0; + background: none; + color: var(--fg); + caret-color: var(--fg); + font-size: 12px; + line-height: 22px; +} + +.mini-list { + max-height: calc(10 * 21px); + margin: 0; + padding: 0; + overflow-y: auto; + list-style: none; +} + +.mini-list:empty { + display: none; +} + +.mini-list li { + display: flex; + gap: 2ch; + height: 21px; + padding: 0 1ch; + line-height: 21px; + cursor: pointer; +} + +.mini-list li[aria-selected="true"] { + background: var(--hl); +} + +.mini-list .cand { + flex: none; + min-width: 24ch; + color: var(--fg); +} + +.mini-list .cand mark { + background: none; + color: var(--magenta); + font-weight: 600; +} + +.mini-list .ann { + flex: 1; + min-width: 0; + overflow: hidden; + color: var(--dim); + text-overflow: ellipsis; +} + +.mini-list .key { + flex: none; + color: var(--blue); +} + +.which-key { + position: fixed; + left: 0; + right: 0; + bottom: var(--frame-h); + z-index: 29; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(26ch, 1fr)); + gap: 2px 2ch; + padding: 10px 2ch 12px; + border-top: 1px solid var(--rule); + background: var(--bg-alt); + font-size: 12px; +} + +.which-key[hidden] { + display: none; +} + +.wk-title { + grid-column: 1 / -1; + margin-bottom: 4px; + color: var(--dim); +} + +.wk-item { + display: flex; + gap: 1ch; + white-space: nowrap; +} + +.wk-key { + min-width: 3ch; + color: var(--magenta); + font-weight: 600; +} + +.wk-arrow { + color: var(--faint); +} + +.wk-desc { + color: var(--fg); +} + +.wk-desc.group { + color: var(--blue); +} + +/* ───────────────────────────── M-x coffee-refill ───────────────────────────── */ + +.coffee { + position: fixed; + right: 2ch; + bottom: calc(var(--frame-h) + 12px); + z-index: 28; + display: flex; + gap: 3ch; + width: min(620px, calc(100% - 4ch)); + padding: 16px 20px 18px; + border: 1px solid var(--faint); + background: var(--bg); + box-shadow: 0 12px 40px rgb(0 0 0 / 0.35); + font-size: 12px; +} + +.coffee[hidden] { + display: none; +} + +.mug { + flex: none; + margin: 0; + font-size: 12px; + line-height: 1.25; + color: var(--fg); +} + +.mug .steam { + color: var(--dim); +} + +.mug .brew { + color: var(--orange); +} + +.mug .crema { + color: var(--yellow); +} + +.coffee-info { + flex: 1; + min-width: 0; +} + +.coffee-info .winbar { + margin: 0 28px 14px 0; +} + +.coffee-info p { + margin: 0 0 10px; +} + +.vcc { + display: flex; + gap: 1.5ch; + font-variant-numeric: tabular-nums; +} + +.vbar { + color: var(--green); + letter-spacing: -0.05em; +} + +.coffee.is-over .vbar, +.coffee.is-over .volts { + color: var(--red); +} + +.coffee-msg { + min-height: 3.2em; +} + +.coffee-links { + display: flex; + flex-wrap: wrap; + gap: 4px 2ch; +} + +.coffee-close { + position: absolute; + top: 6px; + right: 8px; + padding: 2px 6px; + border: 0; + background: none; + color: var(--dim); + font-size: 16px; + line-height: 1; +} + +.coffee-close:hover { + color: var(--fg); +} + +/* ───────────────────────────── help ───────────────────────────── */ + +.help { + width: min(780px, calc(100% - 32px)); + max-height: calc(100% - 64px); + padding: 24px 28px; + border: 1px solid var(--faint); + background: var(--bg); + color: var(--fg); + font-size: 12.5px; +} + +.help::backdrop { + background: rgb(0 0 0 / 0.5); +} + +.help .winbar { + margin-bottom: 28px; +} + +.help-cols { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 40px; +} + +.help h3 { + margin: 0 0 12px; + font-size: 12px; + font-weight: 600; +} + +.help dl { + margin: 0; +} + +.help dl div { + display: grid; + grid-template-columns: 13ch 1fr; + gap: 2ch; + padding: 3px 0; +} + +.help dt { + color: var(--fg); +} + +.help dd { + margin: 0; + color: var(--dim); +} + +.help form { + margin-top: 28px; +} + +/* ───────────────────────────── responsive ───────────────────────────── */ + +@media (max-width: 1100px) { + .hero { + grid-template-columns: minmax(0, 1fr); + align-items: start; + } + + .hero-id { + max-width: 640px; + } +} + +@media (max-width: 920px) { + .nav { + display: none; + } + + .nav.is-open { + position: absolute; + top: calc(var(--top-h) - 4px); + right: var(--gutter); + display: flex; + flex-direction: column; + gap: 10px; + min-width: 18ch; + padding: 14px 18px; + border: 1px solid var(--faint); + background: var(--bg); + } + + .menu-key { + display: block; + } + + .ds-grid, + .mm-cols, + .contact-grid { + grid-template-columns: minmax(0, 1fr); + } + + .ds-grid { + gap: 0; + } + + .pinout { + max-width: 420px; + } + + .mm-detail { + min-height: 0; + margin: 4px 0 8px; + padding: 20px 0 20px 12px; + border-left: 0; + border-bottom: 1px solid var(--rule); + } + + .ml-enc, + .ml-vc, + .ml-time, + .ml-pos { + display: none; + } +} + +@media (max-width: 640px) { + .board { + --led: 8px; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + grid-template-areas: + "bus bus" + "left right" + "ctrl ctrl"; + font-size: 10.5px; + } + + .bus { + flex-direction: row; + gap: 1.5ch; + padding: 6px 10px; + } + + .bus .mod-head, + .bus-val { + margin: 0; + } + + .lanes { + flex-direction: column; + justify-content: center; + height: 26px; + gap: 1px; + } + + .lane { + width: auto; + height: 2px; + } + + .mod { + padding: 6px 8px 8px; + } + + .ram-row { + --led: 6px; + grid-template-columns: 1.5ch 2ch auto; + } + + .ram-row .dis { + display: none; + } + + .seg7 svg { + width: 16px; + height: 28px; + } + + .sim-field { + margin-left: 0; + } + + .sec { + padding-top: 104px; + } + + .winbar { + margin-bottom: 40px; + } + + .lede, + .prose { + font-size: 17px; + } + + .ds-head { + grid-template-columns: minmax(0, 1fr); + } + + .mm { + --mm-cols: 7ch 6ch minmax(0, 1fr); + } + + .mm-head span:last-child, + .proj-row .y { + display: none; + } + + .bc-cols { + grid-template-columns: minmax(0, 1fr); + } + + .gitlog { + padding: 12px; + font-size: 11.5px; + } + + .gitlog-cmd { + font-size: 11.5px; + } + + .org-tags { + display: none; + } + + .help-cols { + grid-template-columns: minmax(0, 1fr); + gap: 24px; + } + + .ml-pct { + display: none; + } + + .coffee { + right: 0; + left: 0; + width: auto; + margin: 0 8px; + flex-direction: column; + gap: 8px; + } +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + + *, + *::before, + *::after { + transition: none !important; + } +} diff --git a/tsconfig.json b/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/base", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +}