diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..2c3d033 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# EditorConfig — whitespace/EOL baseline across every file surface (#16). +# https://editorconfig.org · Complements Prettier (CSS/JS/JSON/YAML/MD) and markdownlint; +# also governs the Hugo Go-template layouts, which Prettier deliberately leaves alone. +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +# Python (scripts/) conventionally uses 4-space indent. +[*.py] +indent_size = 4 + +# Markdown uses two trailing spaces for a hard line break — don't strip them. +[*.md] +trim_trailing_whitespace = false diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1c7e8c9..feb55cc 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -3,7 +3,7 @@ name: Bug report about: Report something broken on the site — a rendering glitch, broken link, or display issue title: "[Bug] " labels: bug -assignees: '' +assignees: "" --- ## What happened? @@ -12,7 +12,7 @@ A clear description of the bug — what you expected to see, and what actually h ## Where? -- **Page / URL:** (e.g. https://p2pool-starter-stack.github.io/#roadmap) +- **Page / URL:** (e.g. ) - **Section or element:** (hero, project card, FAQ, footer, …) ## Steps to reproduce diff --git a/.github/ISSUE_TEMPLATE/content_fix.md b/.github/ISSUE_TEMPLATE/content_fix.md index 57f6378..8a147fa 100644 --- a/.github/ISSUE_TEMPLATE/content_fix.md +++ b/.github/ISSUE_TEMPLATE/content_fix.md @@ -3,7 +3,7 @@ name: Content fix about: A typo, wording, broken/outdated link, or factual correction in the site copy title: "[Content] " labels: documentation -assignees: '' +assignees: "" --- ## What needs fixing? diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 8c3f974..c6edf63 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -3,7 +3,7 @@ name: Feature request about: Suggest an idea or improvement for the site title: "[Feature] " labels: enhancement -assignees: '' +assignees: "" --- ## Problem / motivation diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 46b02b7..bb6859e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,6 +10,7 @@ For anything non-trivial, open an issue first to discuss the change. ## Related issue + Closes # ## Checklist diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3ec60ef..02f152e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,10 +1,10 @@ -# Keep the SHA-pinned GitHub Actions current. Dependabot bumps the commit pin AND the trailing -# "# vX.Y.Z" comment together, and opens PRs for any security advisories affecting an action we use. +# Keep dependencies current and surface security advisories — grouped weekly PRs. # -# Scope is github-actions ONLY (#11): this repo is a static Hugo site with no app dependencies — -# no package.json, go.mod, pip, or docker to track. Hugo itself is installed by version-pinned -# `wget` of a release .deb in the workflows (HUGO_VERSION), which Dependabot cannot see, so Hugo -# bumps stay manual (see #15). +# Two ecosystems: +# - github-actions (#11): bumps the SHA pins in .github/workflows/ and their "# vX.Y.Z" comments. +# - npm (#16): the Prettier + markdownlint formatting toolchain in package.json (repo root). +# No pip/go/docker here. Hugo is installed by version-pinned `wget` of a release .deb in the +# workflows (HUGO_VERSION), which Dependabot cannot see, so Hugo bumps stay manual (see #15). version: 2 updates: - package-ecosystem: "github-actions" @@ -21,3 +21,16 @@ updates: github-actions: patterns: - "*" + - package-ecosystem: "npm" + directory: "/" # package.json (Prettier + markdownlint) lives at the repo root + schedule: + interval: "weekly" + commit-message: + prefix: "build" # -> "build(deps): bump prettier ..." + include: "scope" + labels: + - "infra" + groups: + npm: + patterns: + - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3483934..7e96840 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ name: CI on: push: - branches-ignore: [main] # main is covered by deploy.yml's build step + branches-ignore: [main] # main is covered by deploy.yml's build step pull_request: workflow_dispatch: @@ -28,7 +28,7 @@ jobs: uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 - persist-credentials: false # zizmor: artipacked + persist-credentials: false # zizmor: artipacked - name: Install Hugo (extended) run: | @@ -52,3 +52,23 @@ jobs: - name: Check internal links, anchors & images run: htmltest + + format: + name: Format & lint (Prettier + markdownlint) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false # zizmor: artipacked + - name: Setup Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "22" + cache: npm + - name: Install toolchain (pinned via package-lock.json) + run: npm ci + - name: Prettier (check mode) + run: npm run format:check + - name: markdownlint + run: npm run lint:md diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6c6a9aa..8e736b8 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -39,7 +39,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - persist-credentials: false # zizmor: artipacked + persist-credentials: false # zizmor: artipacked - name: Setup Pages id: pages uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 diff --git a/.gitignore b/.gitignore index 6b55673..6366338 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ # htmltest cache / log output /tmp/ +# Node toolchain (formatting/lint — Prettier + markdownlint) +/node_modules/ + # OS / editor cruft .DS_Store *.swp diff --git a/.htmltest.yml b/.htmltest.yml index 02a5c11..9091999 100644 --- a/.htmltest.yml +++ b/.htmltest.yml @@ -9,7 +9,7 @@ DirectoryPath: "public" CheckExternal: false CheckInternal: true -CheckInternalHash: true # verify nav anchors resolve to a real id +CheckInternalHash: true # verify nav anchors resolve to a real id CheckImages: true CheckScripts: true CheckLinks: true diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc new file mode 100644 index 0000000..9038ecd --- /dev/null +++ b/.markdownlint-cli2.jsonc @@ -0,0 +1,11 @@ +{ + // Markdown lint rules for the site. https://github.com/DavidAnson/markdownlint + "config": { + "default": true, + "MD013": false, // line length — long lines, tables, and links are fine here + "MD033": false, // inline HTML — issue/PR templates use HTML comments; copy may use inline HTML + "MD041": false, // first line need not be H1 — issue templates open at H2 after YAML front matter + }, + // Lint every Markdown file except dependencies / build output. + "globs": ["**/*.md", "!node_modules", "!public", "!resources"], +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 542e6fb..90ffe38 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,10 +3,20 @@ # pipx install pre-commit # or: pip install pre-commit # pre-commit install # -# Scope here is the secret-scanning gate from #11: gitleaks, pinned to the SAME version CI runs -# (.github/workflows/security.yml) so a leak is caught locally before it's ever pushed. +# Each hook is pinned in lockstep with its CI counterpart: +# - gitleaks — secret scan (#11), same version as .github/workflows/security.yml +# - prettier — formatting (#16), same version as package.json; respects .prettierignore +# - markdownlint — Markdown lint (#16), same version as package.json; uses .markdownlint-cli2.jsonc repos: - repo: https://github.com/gitleaks/gitleaks rev: v8.30.1 # keep in lockstep with GITLEAKS_VERSION in .github/workflows/security.yml hooks: - id: gitleaks + - repo: https://github.com/rbubley/mirrors-prettier + rev: v3.8.4 # keep in lockstep with the prettier version in package.json + hooks: + - id: prettier + - repo: https://github.com/DavidAnson/markdownlint-cli2 + rev: v0.22.1 # keep in lockstep with markdownlint-cli2 in package.json + hooks: + - id: markdownlint-cli2 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..39b26b8 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,16 @@ +# Generated / build output & dependencies +public/ +resources/ +node_modules/ + +# Hugo Go-template layouts — Prettier's HTML parser mangles {{ }} syntax, and the +# whitespace between inline elements here is visually significant. Governed by .editorconfig. +layouts/ + +# Generated data (refreshed from the GitHub API by scripts/refresh-releases.py) +data/releases.json + +# Lockfile + vendored / binary assets Prettier shouldn't touch +package-lock.json +static/ +*.svg diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..d0280c2 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "printWidth": 100, + "proseWrap": "preserve" +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e38d4df..7ddd5f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,6 +32,7 @@ not in the templates. See the [README](README.md#where-the-content-lives) for th hugo --gc --minify --panicOnWarning --baseURL "http://localhost/" # strict build htmltest # link/anchor/image check ``` + 4. Update the README or other docs for any user-facing change. ## Secret scanning diff --git a/README.md b/README.md index 3092baa..a7db555 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ flakes on a third-party outage — run `htmltest` with `CheckExternal: true` to All landing-page copy is in **[`data/content.yaml`](data/content.yaml)** — edit text there, not in the templates. The page is assembled by [`layouts/index.html`](layouts/index.html) from that data. -``` +```text data/content.yaml ← all copy (hero, stats, projects, roadmap, ethos, FAQ, CTA) data/releases.json ← latest pithead / rigforge release tags (version badges) layouts/index.html ← single-page assembly diff --git a/SECURITY.md b/SECURITY.md index 3ff60b0..3e24a9e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -12,7 +12,7 @@ The live site is whatever is on the latest `main` — it deploys on every push. branches; please check against current `main` before reporting. | Version | Supported | -|----------------|--------------------| +| -------------- | ------------------ | | latest `main` | ✅ | | anything older | ❌ (please update) | diff --git a/assets/css/main.css b/assets/css/main.css index 7042e4a..cdaa380 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -5,39 +5,53 @@ ════════════════════════════════════════════════════════════════════════ */ :root { - --bg: #0a0c10; - --bg-2: #0d1117; - --surface: #11161d; + --bg: #0a0c10; + --bg-2: #0d1117; + --surface: #11161d; --surface-2: #161b22; - --border: #222a33; - --border-2: #30363d; - --text: #e6edf3; - --muted: #9aa6b4; - --dim: #6e7989; - - --orange: #F26822; - --orange-2: #ff9457; - --orange-soft: rgba(242,104,34,.14); - --orange-glow: rgba(242,104,34,.45); - --ember: #ff5236; - --blue: #58a6ff; - --purple: #a371f7; - --green: #3fb950; - - --radius: 14px; + --border: #222a33; + --border-2: #30363d; + --text: #e6edf3; + --muted: #9aa6b4; + --dim: #6e7989; + + --orange: #f26822; + --orange-2: #ff9457; + --orange-soft: rgba(242, 104, 34, 0.14); + --orange-glow: rgba(242, 104, 34, 0.45); + --ember: #ff5236; + --blue: #58a6ff; + --purple: #a371f7; + --green: #3fb950; + + --radius: 14px; --radius-lg: 22px; - --maxw: 1140px; + --maxw: 1140px; - --mono: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", "Roboto Mono", Menlo, Consolas, monospace; - --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif; + --mono: + ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", "Roboto Mono", Menlo, Consolas, + monospace; + --sans: + -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif; - --ease: cubic-bezier(.22,.61,.36,1); + --ease: cubic-bezier(0.22, 0.61, 0.36, 1); } -*, *::before, *::after { box-sizing: border-box; } +*, +*::before, +*::after { + box-sizing: border-box; +} -html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; } -@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } } +html { + scroll-behavior: smooth; + -webkit-text-size-adjust: 100%; +} +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } +} body { margin: 0; @@ -51,389 +65,1359 @@ body { overflow-x: hidden; } -a { color: inherit; text-decoration: none; } -img { max-width: 100%; display: block; } -.mono { font-family: var(--mono); font-feature-settings: "ss01"; } -.dim { color: var(--dim); } -.accent { color: var(--orange); } +a { + color: inherit; + text-decoration: none; +} +img { + max-width: 100%; + display: block; +} +.mono { + font-family: var(--mono); + font-feature-settings: "ss01"; +} +.dim { + color: var(--dim); +} +.accent { + color: var(--orange); +} -.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 24px; } +.wrap { + width: 100%; + max-width: var(--maxw); + margin: 0 auto; + padding: 0 24px; +} .skip { - position: absolute; left: -999px; top: 0; z-index: 999; - background: var(--orange); color: #0a0c10; padding: 10px 16px; font-weight: 700; border-radius: 0 0 8px 0; + position: absolute; + left: -999px; + top: 0; + z-index: 999; + background: var(--orange); + color: #0a0c10; + padding: 10px 16px; + font-weight: 700; + border-radius: 0 0 8px 0; +} +.skip:focus { + left: 0; } -.skip:focus { left: 0; } /* ───────── Reveal-on-scroll (no-JS shows everything) ───────── */ -html.js .reveal { opacity: 0; transform: translateY(18px); transition: opacity .7s var(--ease), transform .7s var(--ease); } -html.js .reveal.in { opacity: 1; transform: none; } +html.js .reveal { + opacity: 0; + transform: translateY(18px); + transition: + opacity 0.7s var(--ease), + transform 0.7s var(--ease); +} +html.js .reveal.in { + opacity: 1; + transform: none; +} /* Load-triggered entrance for above-the-fold hero content — never scroll-gated, plays with CSS alone (works without JS), staggered top to bottom. */ -.rise { opacity: 0; animation: rise .85s var(--ease) both; } -@keyframes rise { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } } -.hero-inner > .rise:nth-child(1) { animation-delay: .05s; } -.hero-inner > .rise:nth-child(2) { animation-delay: .14s; } -.hero-inner > .rise:nth-child(3) { animation-delay: .23s; } -.hero-inner > .rise:nth-child(4) { animation-delay: .34s; } -.hero-inner > .rise:nth-child(5) { animation-delay: .45s; } -.hero-inner > .rise:nth-child(6) { animation-delay: .54s; } +.rise { + opacity: 0; + animation: rise 0.85s var(--ease) both; +} +@keyframes rise { + from { + opacity: 0; + transform: translateY(22px); + } + to { + opacity: 1; + transform: none; + } +} +.hero-inner > .rise:nth-child(1) { + animation-delay: 0.05s; +} +.hero-inner > .rise:nth-child(2) { + animation-delay: 0.14s; +} +.hero-inner > .rise:nth-child(3) { + animation-delay: 0.23s; +} +.hero-inner > .rise:nth-child(4) { + animation-delay: 0.34s; +} +.hero-inner > .rise:nth-child(5) { + animation-delay: 0.45s; +} +.hero-inner > .rise:nth-child(6) { + animation-delay: 0.54s; +} @media (prefers-reduced-motion: reduce) { - html.js .reveal { opacity: 1 !important; transform: none !important; transition: none; } - .rise { opacity: 1 !important; animation: none !important; } + html.js .reveal { + opacity: 1 !important; + transform: none !important; + transition: none; + } + .rise { + opacity: 1 !important; + animation: none !important; + } } /* ───────── Header ───────── */ .site-header { - position: sticky; top: 0; z-index: 100; + position: sticky; + top: 0; + z-index: 100; backdrop-filter: blur(12px); - background: rgba(10,12,16,.55); + background: rgba(10, 12, 16, 0.55); border-bottom: 1px solid transparent; - transition: background .3s var(--ease), border-color .3s var(--ease); + transition: + background 0.3s var(--ease), + border-color 0.3s var(--ease); +} +.site-header.scrolled { + background: rgba(10, 12, 16, 0.85); + border-bottom-color: var(--border); +} +.header-inner { + display: flex; + align-items: center; + justify-content: space-between; + height: 64px; } -.site-header.scrolled { background: rgba(10,12,16,.85); border-bottom-color: var(--border); } -.header-inner { display: flex; align-items: center; justify-content: space-between; height: 64px; } -.brand { display: inline-flex; align-items: center; gap: 10px; } -.brand-mark { display: inline-flex; width: 26px; height: 26px; color: var(--orange); - filter: drop-shadow(0 0 8px var(--orange-glow)); } -.brand-mark .ico { width: 100%; height: 100%; } -.brand-word { font-weight: 800; letter-spacing: 1.5px; font-size: 15px; white-space: nowrap; } -.brand-accent { color: var(--orange); } +.brand { + display: inline-flex; + align-items: center; + gap: 10px; +} +.brand-mark { + display: inline-flex; + width: 26px; + height: 26px; + color: var(--orange); + filter: drop-shadow(0 0 8px var(--orange-glow)); +} +.brand-mark .ico { + width: 100%; + height: 100%; +} +.brand-word { + font-weight: 800; + letter-spacing: 1.5px; + font-size: 15px; + white-space: nowrap; +} +.brand-accent { + color: var(--orange); +} -.nav { display: flex; align-items: center; gap: 28px; } -.nav a { color: var(--muted); font-size: 14.5px; font-weight: 500; letter-spacing: .2px; transition: color .2s; } -.nav a:hover { color: var(--text); } +.nav { + display: flex; + align-items: center; + gap: 28px; +} +.nav a { + color: var(--muted); + font-size: 14.5px; + font-weight: 500; + letter-spacing: 0.2px; + transition: color 0.2s; +} +.nav a:hover { + color: var(--text); +} .nav .nav-cta { - color: var(--text); border: 1px solid var(--border-2); padding: 7px 14px; border-radius: 8px; - background: var(--surface); transition: border-color .2s, background .2s; + color: var(--text); + border: 1px solid var(--border-2); + padding: 7px 14px; + border-radius: 8px; + background: var(--surface); + transition: + border-color 0.2s, + background 0.2s; +} +.nav .nav-cta:hover { + border-color: var(--orange); + background: var(--orange-soft); } -.nav .nav-cta:hover { border-color: var(--orange); background: var(--orange-soft); } /* ───────── Buttons ───────── */ .btn { - display: inline-flex; align-items: center; gap: 8px; - font-weight: 650; font-size: 15.5px; letter-spacing: .2px; - padding: 13px 22px; border-radius: 11px; border: 1px solid transparent; - cursor: pointer; transition: transform .18s var(--ease), box-shadow .25s, background .2s, border-color .2s; + display: inline-flex; + align-items: center; + gap: 8px; + font-weight: 650; + font-size: 15.5px; + letter-spacing: 0.2px; + padding: 13px 22px; + border-radius: 11px; + border: 1px solid transparent; + cursor: pointer; + transition: + transform 0.18s var(--ease), + box-shadow 0.25s, + background 0.2s, + border-color 0.2s; +} +.btn-sm { + padding: 9px 16px; + font-size: 14px; } -.btn-sm { padding: 9px 16px; font-size: 14px; } .btn-primary { background: linear-gradient(180deg, var(--orange-2), var(--orange)); - color: #160a02; box-shadow: 0 6px 24px -8px var(--orange-glow), inset 0 1px 0 rgba(255,255,255,.25); + color: #160a02; + box-shadow: + 0 6px 24px -8px var(--orange-glow), + inset 0 1px 0 rgba(255, 255, 255, 0.25); +} +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: + 0 12px 34px -8px var(--orange-glow), + inset 0 1px 0 rgba(255, 255, 255, 0.3); +} +.btn-ghost { + background: var(--surface); + color: var(--text); + border-color: var(--border-2); +} +.btn-ghost:hover { + border-color: var(--orange); + background: var(--orange-soft); + transform: translateY(-2px); } -.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 12px 34px -8px var(--orange-glow), inset 0 1px 0 rgba(255,255,255,.3); } -.btn-ghost { background: var(--surface); color: var(--text); border-color: var(--border-2); } -.btn-ghost:hover { border-color: var(--orange); background: var(--orange-soft); transform: translateY(-2px); } /* ───────── Eyebrows & section headings ───────── */ .eyebrow { - display: inline-flex; align-items: center; gap: 9px; - font-size: 13px; letter-spacing: 1.5px; text-transform: uppercase; - color: var(--orange); font-weight: 600; margin: 0 0 18px; + display: inline-flex; + align-items: center; + gap: 9px; + font-size: 13px; + letter-spacing: 1.5px; + text-transform: uppercase; + color: var(--orange); + font-weight: 600; + margin: 0 0 18px; +} +.eyebrow.mono { + letter-spacing: 0.5px; + text-transform: none; +} +.eyebrow .dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--orange); + box-shadow: + 0 0 0 4px var(--orange-soft), + 0 0 12px var(--orange); } -.eyebrow.mono { letter-spacing: .5px; text-transform: none; } -.eyebrow .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--orange); - box-shadow: 0 0 0 4px var(--orange-soft), 0 0 12px var(--orange); } -.section { padding: 104px 0; position: relative; } -.section-alt { background: - radial-gradient(1200px 600px at 50% -10%, rgba(242,104,34,.05), transparent 60%), - var(--bg-2); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); } -.section-title { font-size: clamp(28px, 4vw, 40px); font-weight: 800; letter-spacing: -.5px; line-height: 1.12; margin: 0 0 16px; max-width: 18ch; } -.section-sub { font-size: 18px; color: var(--muted); max-width: 60ch; margin: 0 0 48px; } +.section { + padding: 104px 0; + position: relative; +} +.section-alt { + background: + radial-gradient(1200px 600px at 50% -10%, rgba(242, 104, 34, 0.05), transparent 60%), + var(--bg-2); + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); +} +.section-title { + font-size: clamp(28px, 4vw, 40px); + font-weight: 800; + letter-spacing: -0.5px; + line-height: 1.12; + margin: 0 0 16px; + max-width: 18ch; +} +.section-sub { + font-size: 18px; + color: var(--muted); + max-width: 60ch; + margin: 0 0 48px; +} /* ───────── HERO ───────── */ -.hero { position: relative; padding: 74px 0 72px; overflow: hidden; } -.hero-bg { position: absolute; inset: 0; pointer-events: none; } +.hero { + position: relative; + padding: 74px 0 72px; + overflow: hidden; +} +.hero-bg { + position: absolute; + inset: 0; + pointer-events: none; +} .grid-lines { - position: absolute; inset: -2px; + position: absolute; + inset: -2px; background-image: - linear-gradient(rgba(255,255,255,.035) 1px, transparent 1px), - linear-gradient(90deg, rgba(255,255,255,.035) 1px, transparent 1px); + linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px), + linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px); background-size: 46px 46px; -webkit-mask-image: radial-gradient(120% 90% at 50% 0%, #000 30%, transparent 78%); - mask-image: radial-gradient(120% 90% at 50% 0%, #000 30%, transparent 78%); + mask-image: radial-gradient(120% 90% at 50% 0%, #000 30%, transparent 78%); } .hero .glow { - position: absolute; top: -180px; left: 50%; transform: translateX(-50%); - width: 900px; height: 620px; + position: absolute; + top: -180px; + left: 50%; + transform: translateX(-50%); + width: 900px; + height: 620px; background: radial-gradient(closest-side, var(--orange-glow), transparent 72%); - opacity: .5; filter: blur(20px); + opacity: 0.5; + filter: blur(20px); } .headframe { - position: absolute; right: -40px; top: 20px; width: 360px; height: 360px; - color: var(--orange); opacity: .12; + position: absolute; + right: -40px; + top: 20px; + width: 360px; + height: 360px; + color: var(--orange); + opacity: 0.12; filter: drop-shadow(0 0 24px var(--orange-glow)); } -.headframe .ico { width: 100%; height: 100%; } +.headframe .ico { + width: 100%; + height: 100%; +} -.hero-inner { position: relative; text-align: center; display: flex; flex-direction: column; align-items: center; } +.hero-inner { + position: relative; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; +} .hero-title { - font-size: clamp(40px, 7vw, 78px); font-weight: 850; letter-spacing: -1.5px; line-height: 1.02; - margin: 0 0 22px; max-width: 16ch; + font-size: clamp(40px, 7vw, 78px); + font-weight: 850; + letter-spacing: -1.5px; + line-height: 1.02; + margin: 0 0 22px; + max-width: 16ch; +} +.glow-text { + text-shadow: 0 0 36px var(--orange-glow); +} +.hero-sub { + font-size: clamp(17px, 2.2vw, 20px); + color: var(--muted); + max-width: 60ch; + margin: 0 0 34px; +} +.hero-sub strong { + color: var(--text); + font-weight: 650; } -.glow-text { text-shadow: 0 0 36px var(--orange-glow); } -.hero-sub { font-size: clamp(17px, 2.2vw, 20px); color: var(--muted); max-width: 60ch; margin: 0 0 34px; } -.hero-sub strong { color: var(--text); font-weight: 650; } /* terminal */ .terminal { - width: 100%; max-width: 600px; text-align: left; margin: 0 0 34px; + width: 100%; + max-width: 600px; + text-align: left; + margin: 0 0 34px; background: linear-gradient(180deg, #0e141b, #0b0f15); - border: 1px solid var(--border-2); border-radius: var(--radius); - box-shadow: 0 30px 80px -30px rgba(0,0,0,.8), 0 0 0 1px rgba(242,104,34,.06), 0 0 60px -20px var(--orange-glow); + border: 1px solid var(--border-2); + border-radius: var(--radius); + box-shadow: + 0 30px 80px -30px rgba(0, 0, 0, 0.8), + 0 0 0 1px rgba(242, 104, 34, 0.06), + 0 0 60px -20px var(--orange-glow); overflow: hidden; } -.term-bar { display: flex; align-items: center; gap: 7px; padding: 11px 14px; background: rgba(255,255,255,.025); border-bottom: 1px solid var(--border); } -.term-dot { width: 11px; height: 11px; border-radius: 50%; background: #30363d; } -.term-dot:nth-child(1){ background:#ff5f57; } .term-dot:nth-child(2){ background:#febc2e; } .term-dot:nth-child(3){ background:#28c840; } -.term-title { margin-left: 10px; font-size: 12.5px; color: var(--dim); } -.term-body { margin: 0; padding: 18px 18px 20px; font-size: 14px; line-height: 1.9; white-space: pre-wrap; word-break: break-word; } -.term-prompt { color: var(--orange); user-select: none; } -.term-cmd { color: var(--text); } -.term-ok { color: var(--green); } -.cursor { color: var(--orange); animation: blink 1.1s steps(2) infinite; } -@keyframes blink { 50% { opacity: 0; } } -@media (prefers-reduced-motion: reduce) { .cursor { animation: none; } } - -.hero-cta { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; } -.hero-meta { margin: 22px 0 0; font-size: 13px; color: var(--dim); letter-spacing: .3px; } +.term-bar { + display: flex; + align-items: center; + gap: 7px; + padding: 11px 14px; + background: rgba(255, 255, 255, 0.025); + border-bottom: 1px solid var(--border); +} +.term-dot { + width: 11px; + height: 11px; + border-radius: 50%; + background: #30363d; +} +.term-dot:nth-child(1) { + background: #ff5f57; +} +.term-dot:nth-child(2) { + background: #febc2e; +} +.term-dot:nth-child(3) { + background: #28c840; +} +.term-title { + margin-left: 10px; + font-size: 12.5px; + color: var(--dim); +} +.term-body { + margin: 0; + padding: 18px 18px 20px; + font-size: 14px; + line-height: 1.9; + white-space: pre-wrap; + word-break: break-word; +} +.term-prompt { + color: var(--orange); + user-select: none; +} +.term-cmd { + color: var(--text); +} +.term-ok { + color: var(--green); +} +.cursor { + color: var(--orange); + animation: blink 1.1s steps(2) infinite; +} +@keyframes blink { + 50% { + opacity: 0; + } +} +@media (prefers-reduced-motion: reduce) { + .cursor { + animation: none; + } +} + +.hero-cta { + display: flex; + gap: 14px; + flex-wrap: wrap; + justify-content: center; +} +.hero-meta { + margin: 22px 0 0; + font-size: 13px; + color: var(--dim); + letter-spacing: 0.3px; +} /* ───────── STATS ───────── */ -.stats-band { border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); background: var(--bg-2); } -.stats-grid { display: grid; grid-template-columns: repeat(5, 1fr); } -.stat { padding: 30px 18px; text-align: center; border-left: 1px solid var(--border); } -.stat:first-child { border-left: 0; } -.stat-val { display: block; font-size: 34px; font-weight: 750; color: var(--orange); line-height: 1; text-shadow: 0 0 24px var(--orange-glow); } -.stat-label { display: block; margin-top: 9px; font-size: 13px; color: var(--muted); } +.stats-band { + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); + background: var(--bg-2); +} +.stats-grid { + display: grid; + grid-template-columns: repeat(5, 1fr); +} +.stat { + padding: 30px 18px; + text-align: center; + border-left: 1px solid var(--border); +} +.stat:first-child { + border-left: 0; +} +.stat-val { + display: block; + font-size: 34px; + font-weight: 750; + color: var(--orange); + line-height: 1; + text-shadow: 0 0 24px var(--orange-glow); +} +.stat-label { + display: block; + margin-top: 9px; + font-size: 13px; + color: var(--muted); +} /* ───────── FLOW ───────── */ -.flow { display: flex; align-items: stretch; gap: 0; flex-wrap: wrap; padding-top: 32px; } +.flow { + display: flex; + align-items: stretch; + gap: 0; + flex-wrap: wrap; + padding-top: 32px; +} .flow-node { - flex: 1 1 0; min-width: 200px; display: flex; flex-direction: column; gap: 5px; - padding: 26px 22px; border-radius: var(--radius); border: 1px solid var(--border-2); background: var(--surface); + flex: 1 1 0; + min-width: 200px; + display: flex; + flex-direction: column; + gap: 5px; + padding: 26px 22px; + border-radius: var(--radius); + border: 1px solid var(--border-2); + background: var(--surface); + position: relative; +} +.flow-node.is-hub { + border-color: rgba(242, 104, 34, 0.55); + box-shadow: + 0 0 0 1px rgba(242, 104, 34, 0.2), + 0 18px 50px -28px var(--orange-glow); +} +.flow-mark { + width: 38px; + height: 38px; + margin-bottom: 8px; +} +.flow-mark.orange { + color: var(--orange); +} +.flow-mark.ember { + color: var(--ember); +} +.flow-mark .ico { + width: 100%; + height: 100%; +} +.chain-pair { + display: inline-flex; +} +.chain-pair .ico:first-child { + color: var(--orange); +} +.chain-pair .ico:last-child { + color: var(--purple); + margin-left: -8px; +} +.flow-kicker { + font-size: 12px; + letter-spacing: 0.5px; + color: var(--orange); +} +.node-miners .flow-kicker { + color: var(--ember); +} +.node-chains .flow-kicker { + color: var(--purple); +} +.flow-title { + font-size: 19px; + font-weight: 700; +} +.flow-note { + font-size: 13.5px; + color: var(--muted); +} +.flow-branch { + margin-top: 10px; + font-size: 12px; + color: var(--purple); +} +.flow-arrow { + flex: 0 0 64px; + display: flex; + align-items: center; + justify-content: center; position: relative; } -.flow-node.is-hub { border-color: rgba(242,104,34,.55); box-shadow: 0 0 0 1px rgba(242,104,34,.2), 0 18px 50px -28px var(--orange-glow); } -.flow-mark { width: 38px; height: 38px; margin-bottom: 8px; } -.flow-mark.orange { color: var(--orange); } .flow-mark.ember { color: var(--ember); } -.flow-mark .ico { width: 100%; height: 100%; } -.chain-pair { display: inline-flex; } -.chain-pair .ico:first-child { color: var(--orange); } -.chain-pair .ico:last-child { color: var(--purple); margin-left: -8px; } -.flow-kicker { font-size: 12px; letter-spacing: .5px; color: var(--orange); } -.node-miners .flow-kicker { color: var(--ember); } -.node-chains .flow-kicker { color: var(--purple); } -.flow-title { font-size: 19px; font-weight: 700; } -.flow-note { font-size: 13.5px; color: var(--muted); } -.flow-branch { margin-top: 10px; font-size: 12px; color: var(--purple); } -.flow-arrow { flex: 0 0 64px; display: flex; align-items: center; justify-content: center; position: relative; } .flow-arrow::before { - content: ""; position: absolute; left: 8px; right: 8px; top: 50%; height: 2px; + content: ""; + position: absolute; + left: 8px; + right: 8px; + top: 50%; + height: 2px; background-image: linear-gradient(90deg, var(--orange) 0 6px, transparent 6px 12px); - background-size: 12px 2px; opacity: .7; + background-size: 12px 2px; + opacity: 0.7; +} +.flow-arrow::after { + content: "▶"; + color: var(--orange); + font-size: 12px; + position: relative; + right: -2px; +} +.flow-arrow-label { + position: absolute; + top: -26px; + left: 50%; + transform: translateX(-50%); + font-size: 10.5px; + color: var(--dim); + white-space: nowrap; } -.flow-arrow::after { content: "▶"; color: var(--orange); font-size: 12px; position: relative; right: -2px; } -.flow-arrow-label { position: absolute; top: -26px; left: 50%; transform: translateX(-50%); font-size: 10.5px; color: var(--dim); white-space: nowrap; } /* ───────── PROJECTS ───────── */ -.accent-orange { --ac: var(--orange); --ac-glow: var(--orange-glow); } -.accent-ember { --ac: var(--ember); --ac-glow: rgba(255,82,54,.4); } -.accent-purple { --ac: var(--purple); --ac-glow: rgba(163,113,247,.4); } -.accent-muted { --ac: var(--dim); --ac-glow: rgba(110,121,137,.3); } +.accent-orange { + --ac: var(--orange); + --ac-glow: var(--orange-glow); +} +.accent-ember { + --ac: var(--ember); + --ac-glow: rgba(255, 82, 54, 0.4); +} +.accent-purple { + --ac: var(--purple); + --ac-glow: rgba(163, 113, 247, 0.4); +} +.accent-muted { + --ac: var(--dim); + --ac-glow: rgba(110, 121, 137, 0.3); +} .project { - position: relative; margin-top: 30px; padding: 36px; - background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--radius-lg); - transition: border-color .3s, box-shadow .3s, transform .3s var(--ease); + position: relative; + margin-top: 30px; + padding: 36px; + background: var(--surface); + border: 1px solid var(--border-2); + border-radius: var(--radius-lg); + transition: + border-color 0.3s, + box-shadow 0.3s, + transform 0.3s var(--ease); } .project::before { - content: ""; position: absolute; left: 0; top: 28px; bottom: 28px; width: 3px; border-radius: 3px; - background: var(--ac); box-shadow: 0 0 20px var(--ac-glow); -} -.project:hover { border-color: color-mix(in srgb, var(--ac) 55%, var(--border-2)); box-shadow: 0 24px 70px -40px var(--ac-glow); transform: translateY(-3px); } -.project-featured { background: - linear-gradient(180deg, rgba(242,104,34,.06), transparent 220px), var(--surface); - box-shadow: 0 0 0 1px rgba(242,104,34,.18), 0 30px 80px -50px var(--orange-glow); } - -.project-head { display: flex; align-items: center; gap: 16px; margin-bottom: 18px; } -.project-mark { width: 46px; height: 46px; color: var(--ac); flex: 0 0 auto; filter: drop-shadow(0 0 12px var(--ac-glow)); } -.project-mark .ico { width: 100%; height: 100%; } -.project-id { display: flex; flex-direction: column; } -.project-name { font-size: 27px; font-weight: 800; margin: 0; letter-spacing: -.4px; } -.project-role { font-size: 13px; color: var(--ac); letter-spacing: .5px; } -.project-tags { margin-left: auto; display: flex; align-items: center; gap: 10px; flex: 0 0 auto; } -.project-ver { font-size: 12px; color: var(--ac); letter-spacing: .5px; white-space: nowrap; + content: ""; + position: absolute; + left: 0; + top: 28px; + bottom: 28px; + width: 3px; + border-radius: 3px; + background: var(--ac); + box-shadow: 0 0 20px var(--ac-glow); +} +.project:hover { + border-color: color-mix(in srgb, var(--ac) 55%, var(--border-2)); + box-shadow: 0 24px 70px -40px var(--ac-glow); + transform: translateY(-3px); +} +.project-featured { + background: linear-gradient(180deg, rgba(242, 104, 34, 0.06), transparent 220px), var(--surface); + box-shadow: + 0 0 0 1px rgba(242, 104, 34, 0.18), + 0 30px 80px -50px var(--orange-glow); +} + +.project-head { + display: flex; + align-items: center; + gap: 16px; + margin-bottom: 18px; +} +.project-mark { + width: 46px; + height: 46px; + color: var(--ac); + flex: 0 0 auto; + filter: drop-shadow(0 0 12px var(--ac-glow)); +} +.project-mark .ico { + width: 100%; + height: 100%; +} +.project-id { + display: flex; + flex-direction: column; +} +.project-name { + font-size: 27px; + font-weight: 800; + margin: 0; + letter-spacing: -0.4px; +} +.project-role { + font-size: 13px; + color: var(--ac); + letter-spacing: 0.5px; +} +.project-tags { + margin-left: auto; + display: flex; + align-items: center; + gap: 10px; + flex: 0 0 auto; +} +.project-ver { + font-size: 12px; + color: var(--ac); + letter-spacing: 0.5px; + white-space: nowrap; border: 1px solid color-mix(in srgb, var(--ac) 35%, transparent); background: color-mix(in srgb, var(--ac) 10%, transparent); - padding: 5px 11px; border-radius: 20px; transition: border-color .2s, transform .2s var(--ease); } -.project-ver:hover { border-color: var(--ac); transform: translateY(-1px); } -.project-flag { font-size: 12px; color: var(--orange); border: 1px solid rgba(242,104,34,.4); background: var(--orange-soft); padding: 5px 11px; border-radius: 20px; white-space: nowrap; } -.project-tagline { font-size: 20px; font-weight: 650; color: var(--text); margin: 0 0 10px; max-width: 56ch; } -.project-blurb { color: var(--muted); margin: 0 0 26px; max-width: 70ch; } - -.feat-grid { list-style: none; padding: 0; margin: 0 0 28px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px 28px; } -.project-featured .feat-grid { grid-template-columns: repeat(3, 1fr); } -.feat { display: flex; gap: 13px; align-items: flex-start; } -.feat-ico { flex: 0 0 auto; width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center; - border-radius: 9px; background: var(--orange-soft); color: var(--ac); border: 1px solid color-mix(in srgb, var(--ac) 25%, transparent); } -.feat-ico .ico { width: 18px; height: 18px; } -.feat-text { font-size: 14.5px; color: var(--muted); line-height: 1.5; } -.feat-text strong { display: block; color: var(--text); font-weight: 650; font-size: 15px; margin-bottom: 2px; } - -.project-shot { margin: 0 0 26px; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--border-2); - box-shadow: 0 30px 80px -40px rgba(0,0,0,.9); position: relative; } -.project-shot img { width: 100%; } -.project-shot figcaption { position: absolute; bottom: 0; left: 0; right: 0; padding: 8px 14px; font-size: 11.5px; color: var(--muted); - background: linear-gradient(0deg, rgba(5,7,10,.92), transparent); } -.project-links { display: flex; gap: 12px; flex-wrap: wrap; } + padding: 5px 11px; + border-radius: 20px; + transition: + border-color 0.2s, + transform 0.2s var(--ease); +} +.project-ver:hover { + border-color: var(--ac); + transform: translateY(-1px); +} +.project-flag { + font-size: 12px; + color: var(--orange); + border: 1px solid rgba(242, 104, 34, 0.4); + background: var(--orange-soft); + padding: 5px 11px; + border-radius: 20px; + white-space: nowrap; +} +.project-tagline { + font-size: 20px; + font-weight: 650; + color: var(--text); + margin: 0 0 10px; + max-width: 56ch; +} +.project-blurb { + color: var(--muted); + margin: 0 0 26px; + max-width: 70ch; +} + +.feat-grid { + list-style: none; + padding: 0; + margin: 0 0 28px; + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 16px 28px; +} +.project-featured .feat-grid { + grid-template-columns: repeat(3, 1fr); +} +.feat { + display: flex; + gap: 13px; + align-items: flex-start; +} +.feat-ico { + flex: 0 0 auto; + width: 34px; + height: 34px; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 9px; + background: var(--orange-soft); + color: var(--ac); + border: 1px solid color-mix(in srgb, var(--ac) 25%, transparent); +} +.feat-ico .ico { + width: 18px; + height: 18px; +} +.feat-text { + font-size: 14.5px; + color: var(--muted); + line-height: 1.5; +} +.feat-text strong { + display: block; + color: var(--text); + font-weight: 650; + font-size: 15px; + margin-bottom: 2px; +} + +.project-shot { + margin: 0 0 26px; + border-radius: var(--radius); + overflow: hidden; + border: 1px solid var(--border-2); + box-shadow: 0 30px 80px -40px rgba(0, 0, 0, 0.9); + position: relative; +} +.project-shot img { + width: 100%; +} +.project-shot figcaption { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 8px 14px; + font-size: 11.5px; + color: var(--muted); + background: linear-gradient(0deg, rgba(5, 7, 10, 0.92), transparent); +} +.project-links { + display: flex; + gap: 12px; + flex-wrap: wrap; +} /* ───────── Card grids (next / ethos) ───────── */ -.cards-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; } +.cards-3 { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; +} .card { - padding: 28px; border-radius: var(--radius); border: 1px solid var(--border-2); background: var(--surface); - transition: border-color .3s, transform .3s var(--ease), box-shadow .3s; + padding: 28px; + border-radius: var(--radius); + border: 1px solid var(--border-2); + background: var(--surface); + transition: + border-color 0.3s, + transform 0.3s var(--ease), + box-shadow 0.3s; +} +.card:hover { + transform: translateY(-3px); +} +.card-title { + font-size: 18px; + font-weight: 700; + margin: 0 0 8px; +} +.card-text { + color: var(--muted); + font-size: 14.5px; + margin: 0; } -.card:hover { transform: translateY(-3px); } -.card-title { font-size: 18px; font-weight: 700; margin: 0 0 8px; } -.card-text { color: var(--muted); font-size: 14.5px; margin: 0; } /* ───────── Beliefs (the "why") ───────── */ -.beliefs-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 28px 36px; margin-top: 4px; } -.belief { padding-top: 22px; border-top: 2px solid var(--orange); } -.belief-title { font-size: clamp(19px, 2.1vw, 24px); font-weight: 800; letter-spacing: -.3px; - line-height: 1.18; margin: 0 0 12px; } -.belief-text { color: var(--muted); font-size: 15px; line-height: 1.65; margin: 0; } +.beliefs-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 28px 36px; + margin-top: 4px; +} +.belief { + padding-top: 22px; + border-top: 2px solid var(--orange); +} +.belief-title { + font-size: clamp(19px, 2.1vw, 24px); + font-weight: 800; + letter-spacing: -0.3px; + line-height: 1.18; + margin: 0 0 12px; +} +.belief-text { + color: var(--muted); + font-size: 15px; + line-height: 1.65; + margin: 0; +} /* ───────── Roadmap ───────── */ -.waves, .donate-band { --ac: var(--orange); --ac-glow: var(--orange-glow); } -.status-pill { font-size: 11px; letter-spacing: .5px; text-transform: uppercase; color: var(--ac); white-space: nowrap; - border: 1px solid color-mix(in srgb, var(--ac) 35%, transparent); padding: 4px 10px; border-radius: 20px; } - -.waves-label { color: var(--orange); font-size: 13px; letter-spacing: .5px; margin: 0 0 26px; } -.beyond-label { margin-top: 60px; } - -.waves { position: relative; display: flex; flex-direction: column; gap: 16px; } -.waves-rail { position: absolute; left: 21px; top: 24px; bottom: 64px; width: 2px; - background: linear-gradient(180deg, var(--orange), rgba(242,104,34,.12)); } -.wave { display: flex; gap: 22px; align-items: stretch; position: relative; } -.wave-node { flex: 0 0 44px; width: 44px; height: 44px; border-radius: 50%; border: 2px solid rgba(242,104,34,.5); - background: var(--bg-2); display: flex; align-items: center; justify-content: center; color: var(--orange); - z-index: 1; box-shadow: 0 0 0 5px var(--bg); } -.wave-node .mono { font-size: 14px; font-weight: 700; } -.wave-node.ship { background: linear-gradient(180deg, var(--orange-2), var(--orange)); border-color: var(--orange); - color: #160a02; box-shadow: 0 0 0 5px var(--bg), 0 0 28px var(--orange-glow); } -.wave-node.ship .ico { width: 22px; height: 22px; } -.wave-body { flex: 1; background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--radius); - padding: 16px 22px; transition: border-color .25s, transform .25s var(--ease); } -.wave:hover .wave-body { border-color: rgba(242,104,34,.45); transform: translateX(3px); } -.wave-ship .wave-body { border-color: rgba(242,104,34,.4); - background: linear-gradient(180deg, rgba(242,104,34,.07), transparent), var(--surface); } -.wave-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 5px; } -.wave-name { font-size: 18px; font-weight: 700; margin: 0; } -.ship-pill { color: var(--orange); border-color: var(--orange); background: var(--orange-soft); } -.wave-text { color: var(--muted); font-size: 14.5px; margin: 0; } - -.cards-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; } -.horizon-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; } -.horizon-mark { width: 38px; height: 38px; color: var(--ac); filter: drop-shadow(0 0 12px var(--ac-glow)); } -.horizon-mark .ico { width: 100%; height: 100%; } -.horizon-card:hover { border-color: color-mix(in srgb, var(--ac) 55%, var(--border-2)); box-shadow: 0 24px 60px -40px var(--ac-glow); } - -.donate-band { margin-top: 60px; text-align: center; padding: 44px 28px; border-radius: var(--radius-lg); +.waves, +.donate-band { + --ac: var(--orange); + --ac-glow: var(--orange-glow); +} +.status-pill { + font-size: 11px; + letter-spacing: 0.5px; + text-transform: uppercase; + color: var(--ac); + white-space: nowrap; + border: 1px solid color-mix(in srgb, var(--ac) 35%, transparent); + padding: 4px 10px; + border-radius: 20px; +} + +.waves-label { + color: var(--orange); + font-size: 13px; + letter-spacing: 0.5px; + margin: 0 0 26px; +} +.beyond-label { + margin-top: 60px; +} + +.waves { + position: relative; + display: flex; + flex-direction: column; + gap: 16px; +} +.waves-rail { + position: absolute; + left: 21px; + top: 24px; + bottom: 64px; + width: 2px; + background: linear-gradient(180deg, var(--orange), rgba(242, 104, 34, 0.12)); +} +.wave { + display: flex; + gap: 22px; + align-items: stretch; + position: relative; +} +.wave-node { + flex: 0 0 44px; + width: 44px; + height: 44px; + border-radius: 50%; + border: 2px solid rgba(242, 104, 34, 0.5); + background: var(--bg-2); + display: flex; + align-items: center; + justify-content: center; + color: var(--orange); + z-index: 1; + box-shadow: 0 0 0 5px var(--bg); +} +.wave-node .mono { + font-size: 14px; + font-weight: 700; +} +.wave-node.ship { + background: linear-gradient(180deg, var(--orange-2), var(--orange)); + border-color: var(--orange); + color: #160a02; + box-shadow: + 0 0 0 5px var(--bg), + 0 0 28px var(--orange-glow); +} +.wave-node.ship .ico { + width: 22px; + height: 22px; +} +.wave-body { + flex: 1; + background: var(--surface); border: 1px solid var(--border-2); - background: radial-gradient(700px 300px at 50% 0%, rgba(242,104,34,.08), transparent 70%), var(--surface); } -.donate-title { font-size: clamp(22px, 3.2vw, 31px); font-weight: 800; letter-spacing: -.4px; margin: 0 0 12px; } -.donate-text { color: var(--muted); max-width: 58ch; margin: 0 auto 26px; } -.copy-btn-lg { display: inline-flex; max-width: 100%; gap: 16px; padding: 14px 18px; align-items: center; background: var(--bg-2); } -.donate-addr-full { font-size: 13px; color: var(--text); word-break: break-all; text-align: left; line-height: 1.5; } -.donate-note { margin: 18px 0 0; font-size: 12px; color: var(--dim); } - -.ethos-card { position: relative; overflow: hidden; } -.ethos-card:hover { border-color: rgba(242,104,34,.4); box-shadow: 0 24px 60px -40px var(--orange-glow); } -.ethos-num { position: absolute; top: 16px; right: 18px; font-size: 13px; color: var(--orange); opacity: .55; } -.ethos-card .card-title { padding-right: 40px; } + border-radius: var(--radius); + padding: 16px 22px; + transition: + border-color 0.25s, + transform 0.25s var(--ease); +} +.wave:hover .wave-body { + border-color: rgba(242, 104, 34, 0.45); + transform: translateX(3px); +} +.wave-ship .wave-body { + border-color: rgba(242, 104, 34, 0.4); + background: linear-gradient(180deg, rgba(242, 104, 34, 0.07), transparent), var(--surface); +} +.wave-head { + display: flex; + align-items: center; + gap: 14px; + flex-wrap: wrap; + margin-bottom: 5px; +} +.wave-name { + font-size: 18px; + font-weight: 700; + margin: 0; +} +.ship-pill { + color: var(--orange); + border-color: var(--orange); + background: var(--orange-soft); +} +.wave-text { + color: var(--muted); + font-size: 14.5px; + margin: 0; +} + +.cards-2 { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; +} +.horizon-head { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16px; +} +.horizon-mark { + width: 38px; + height: 38px; + color: var(--ac); + filter: drop-shadow(0 0 12px var(--ac-glow)); +} +.horizon-mark .ico { + width: 100%; + height: 100%; +} +.horizon-card:hover { + border-color: color-mix(in srgb, var(--ac) 55%, var(--border-2)); + box-shadow: 0 24px 60px -40px var(--ac-glow); +} + +.donate-band { + margin-top: 60px; + text-align: center; + padding: 44px 28px; + border-radius: var(--radius-lg); + border: 1px solid var(--border-2); + background: + radial-gradient(700px 300px at 50% 0%, rgba(242, 104, 34, 0.08), transparent 70%), + var(--surface); +} +.donate-title { + font-size: clamp(22px, 3.2vw, 31px); + font-weight: 800; + letter-spacing: -0.4px; + margin: 0 0 12px; +} +.donate-text { + color: var(--muted); + max-width: 58ch; + margin: 0 auto 26px; +} +.copy-btn-lg { + display: inline-flex; + max-width: 100%; + gap: 16px; + padding: 14px 18px; + align-items: center; + background: var(--bg-2); +} +.donate-addr-full { + font-size: 13px; + color: var(--text); + word-break: break-all; + text-align: left; + line-height: 1.5; +} +.donate-note { + margin: 18px 0 0; + font-size: 12px; + color: var(--dim); +} + +.ethos-card { + position: relative; + overflow: hidden; +} +.ethos-card:hover { + border-color: rgba(242, 104, 34, 0.4); + box-shadow: 0 24px 60px -40px var(--orange-glow); +} +.ethos-num { + position: absolute; + top: 16px; + right: 18px; + font-size: 13px; + color: var(--orange); + opacity: 0.55; +} +.ethos-card .card-title { + padding-right: 40px; +} /* ───────── FAQ ───────── */ -.faq-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px 22px; } +.faq-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 18px 22px; +} .faq-item { - position: relative; padding: 26px 28px; border-radius: var(--radius); - border: 1px solid var(--border-2); background: var(--surface); - border-left: 3px solid rgba(242,104,34,.55); - transition: border-color .3s, transform .3s var(--ease), box-shadow .3s; -} -.faq-item:hover { border-color: rgba(242,104,34,.45); border-left-color: var(--orange); - transform: translateY(-3px); box-shadow: 0 24px 60px -40px var(--orange-glow); } -.faq-q { font-size: 16.5px; font-weight: 700; margin: 0 0 9px; letter-spacing: -.2px; line-height: 1.3; } -.faq-a { color: var(--muted); font-size: 14.5px; line-height: 1.6; margin: 0; } -.faq-link { display: inline-flex; align-items: center; gap: 5px; margin-top: 13px; - font-size: 12.5px; color: var(--orange); letter-spacing: .3px; transition: gap .2s; } -.faq-link:hover { gap: 9px; } + position: relative; + padding: 26px 28px; + border-radius: var(--radius); + border: 1px solid var(--border-2); + background: var(--surface); + border-left: 3px solid rgba(242, 104, 34, 0.55); + transition: + border-color 0.3s, + transform 0.3s var(--ease), + box-shadow 0.3s; +} +.faq-item:hover { + border-color: rgba(242, 104, 34, 0.45); + border-left-color: var(--orange); + transform: translateY(-3px); + box-shadow: 0 24px 60px -40px var(--orange-glow); +} +.faq-q { + font-size: 16.5px; + font-weight: 700; + margin: 0 0 9px; + letter-spacing: -0.2px; + line-height: 1.3; +} +.faq-a { + color: var(--muted); + font-size: 14.5px; + line-height: 1.6; + margin: 0; +} +.faq-link { + display: inline-flex; + align-items: center; + gap: 5px; + margin-top: 13px; + font-size: 12.5px; + color: var(--orange); + letter-spacing: 0.3px; + transition: gap 0.2s; +} +.faq-link:hover { + gap: 9px; +} /* ───────── CTA ───────── */ -.cta-section { text-align: center; overflow: hidden; border-bottom: 1px solid var(--border); } -.cta-bg { position: absolute; inset: 0; pointer-events: none; } -.cta-bg .glow { position: absolute; bottom: -260px; left: 50%; transform: translateX(-50%); - width: 800px; height: 500px; background: radial-gradient(closest-side, var(--orange-glow), transparent 72%); opacity: .42; filter: blur(16px); } -.cta-inner { position: relative; display: flex; flex-direction: column; align-items: center; } -.cta-title { font-size: clamp(30px, 5vw, 52px); font-weight: 850; letter-spacing: -1px; margin: 0 0 16px; max-width: 18ch; } -.cta-sub { font-size: 19px; color: var(--muted); margin: 0 0 34px; max-width: 52ch; } +.cta-section { + text-align: center; + overflow: hidden; + border-bottom: 1px solid var(--border); +} +.cta-bg { + position: absolute; + inset: 0; + pointer-events: none; +} +.cta-bg .glow { + position: absolute; + bottom: -260px; + left: 50%; + transform: translateX(-50%); + width: 800px; + height: 500px; + background: radial-gradient(closest-side, var(--orange-glow), transparent 72%); + opacity: 0.42; + filter: blur(16px); +} +.cta-inner { + position: relative; + display: flex; + flex-direction: column; + align-items: center; +} +.cta-title { + font-size: clamp(30px, 5vw, 52px); + font-weight: 850; + letter-spacing: -1px; + margin: 0 0 16px; + max-width: 18ch; +} +.cta-sub { + font-size: 19px; + color: var(--muted); + margin: 0 0 34px; + max-width: 52ch; +} /* ───────── Footer ───────── */ -.site-footer { background: var(--bg); border-top: 1px solid var(--border); padding: 64px 0 36px; } -.footer-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.3fr; gap: 40px; } -.footer-brand .brand { margin-bottom: 16px; } -.footer-tag { color: var(--muted); font-size: 14.5px; margin: 0 0 18px; } -.footer-badges { display: flex; gap: 8px; flex-wrap: wrap; margin: 0; } -.badge { font-family: var(--mono); font-size: 11px; color: var(--muted); border: 1px solid var(--border-2); border-radius: 6px; padding: 4px 9px; } -.footer-col h3 { font-size: 13px; text-transform: uppercase; letter-spacing: 1px; color: var(--dim); margin: 0 0 16px; } -.footer-col a { display: block; color: var(--muted); font-size: 14.5px; margin-bottom: 11px; transition: color .2s; } -.footer-col a:hover { color: var(--orange); } -.footer-note { font-size: 13px; color: var(--dim); margin: 0 0 12px; } -.copy-btn { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; background: var(--surface); - border: 1px solid var(--border-2); border-radius: 9px; padding: 9px 12px; transition: border-color .2s; } -.copy-btn:hover { border-color: var(--orange); } -.donate-addr { font-size: 12.5px; color: var(--text); } -.copy-state { font-size: 11px; color: var(--orange); text-transform: uppercase; letter-spacing: .5px; } -.footer-base { display: flex; justify-content: space-between; align-items: center; gap: 16px; margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--border); font-size: 12.5px; color: var(--dim); flex-wrap: wrap; } +.site-footer { + background: var(--bg); + border-top: 1px solid var(--border); + padding: 64px 0 36px; +} +.footer-grid { + display: grid; + grid-template-columns: 1.6fr 1fr 1fr 1.3fr; + gap: 40px; +} +.footer-brand .brand { + margin-bottom: 16px; +} +.footer-tag { + color: var(--muted); + font-size: 14.5px; + margin: 0 0 18px; +} +.footer-badges { + display: flex; + gap: 8px; + flex-wrap: wrap; + margin: 0; +} +.badge { + font-family: var(--mono); + font-size: 11px; + color: var(--muted); + border: 1px solid var(--border-2); + border-radius: 6px; + padding: 4px 9px; +} +.footer-col h3 { + font-size: 13px; + text-transform: uppercase; + letter-spacing: 1px; + color: var(--dim); + margin: 0 0 16px; +} +.footer-col a { + display: block; + color: var(--muted); + font-size: 14.5px; + margin-bottom: 11px; + transition: color 0.2s; +} +.footer-col a:hover { + color: var(--orange); +} +.footer-note { + font-size: 13px; + color: var(--dim); + margin: 0 0 12px; +} +.copy-btn { + display: inline-flex; + align-items: center; + gap: 10px; + cursor: pointer; + background: var(--surface); + border: 1px solid var(--border-2); + border-radius: 9px; + padding: 9px 12px; + transition: border-color 0.2s; +} +.copy-btn:hover { + border-color: var(--orange); +} +.donate-addr { + font-size: 12.5px; + color: var(--text); +} +.copy-state { + font-size: 11px; + color: var(--orange); + text-transform: uppercase; + letter-spacing: 0.5px; +} +.footer-base { + display: flex; + justify-content: space-between; + align-items: center; + gap: 16px; + margin-top: 48px; + padding-top: 24px; + border-top: 1px solid var(--border); + font-size: 12.5px; + color: var(--dim); + flex-wrap: wrap; +} /* ───────── Responsive ───────── */ @media (max-width: 940px) { - .nav { gap: 18px; } - .nav a:not(.nav-cta) { display: none; } - .stats-grid { grid-template-columns: repeat(2, 1fr); } - .stat:nth-child(odd) { border-left: 0; } - .stat { border-top: 1px solid var(--border); } - .stat:nth-child(1), .stat:nth-child(2) { border-top: 0; } - .cards-3 { grid-template-columns: repeat(2, 1fr); } - .project-featured .feat-grid { grid-template-columns: repeat(2, 1fr); } - .footer-grid { grid-template-columns: 1fr 1fr; } - .flow { flex-direction: column; padding-top: 8px; } - .flow-node { width: 100%; } - .flow-arrow { width: 100%; height: 42px; flex-basis: auto; } - .flow-arrow::before { left: 50%; right: auto; top: 8px; bottom: 8px; width: 2px; height: auto; - background-image: linear-gradient(180deg, var(--orange) 0 6px, transparent 6px 12px); background-size: 2px 12px; } - .flow-arrow::after { content: "▼"; right: auto; } - .flow-arrow-label { display: none; } + .nav { + gap: 18px; + } + .nav a:not(.nav-cta) { + display: none; + } + .stats-grid { + grid-template-columns: repeat(2, 1fr); + } + .stat:nth-child(odd) { + border-left: 0; + } + .stat { + border-top: 1px solid var(--border); + } + .stat:nth-child(1), + .stat:nth-child(2) { + border-top: 0; + } + .cards-3 { + grid-template-columns: repeat(2, 1fr); + } + .project-featured .feat-grid { + grid-template-columns: repeat(2, 1fr); + } + .footer-grid { + grid-template-columns: 1fr 1fr; + } + .flow { + flex-direction: column; + padding-top: 8px; + } + .flow-node { + width: 100%; + } + .flow-arrow { + width: 100%; + height: 42px; + flex-basis: auto; + } + .flow-arrow::before { + left: 50%; + right: auto; + top: 8px; + bottom: 8px; + width: 2px; + height: auto; + background-image: linear-gradient(180deg, var(--orange) 0 6px, transparent 6px 12px); + background-size: 2px 12px; + } + .flow-arrow::after { + content: "▼"; + right: auto; + } + .flow-arrow-label { + display: none; + } } @media (max-width: 620px) { - body { font-size: 16px; } - .brand { gap: 8px; } - .brand-word { font-size: 12.5px; letter-spacing: 1px; } - .brand-mark { width: 22px; height: 22px; } - .section { padding: 72px 0; } - .hero { padding: 80px 0 64px; } - .feat-grid, .project-featured .feat-grid, .cards-3, .cards-2, .faq-grid, .beliefs-grid { grid-template-columns: 1fr; } - .project { padding: 26px 22px; } - .project-head { flex-wrap: wrap; } /* version chip + ★ flag drop to their own line */ - .wave-body { padding: 14px 18px; } - .donate-band { padding: 32px 20px; } - .footer-grid { grid-template-columns: 1fr; gap: 30px; } - .headframe { width: 220px; right: -60px; opacity: .08; } - .stats-grid { grid-template-columns: 1fr; } - .stat { border-left: 0 !important; border-top: 1px solid var(--border); } - .stat:first-child { border-top: 0; } + body { + font-size: 16px; + } + .brand { + gap: 8px; + } + .brand-word { + font-size: 12.5px; + letter-spacing: 1px; + } + .brand-mark { + width: 22px; + height: 22px; + } + .section { + padding: 72px 0; + } + .hero { + padding: 80px 0 64px; + } + .feat-grid, + .project-featured .feat-grid, + .cards-3, + .cards-2, + .faq-grid, + .beliefs-grid { + grid-template-columns: 1fr; + } + .project { + padding: 26px 22px; + } + .project-head { + flex-wrap: wrap; + } /* version chip + ★ flag drop to their own line */ + .wave-body { + padding: 14px 18px; + } + .donate-band { + padding: 32px 20px; + } + .footer-grid { + grid-template-columns: 1fr; + gap: 30px; + } + .headframe { + width: 220px; + right: -60px; + opacity: 0.08; + } + .stats-grid { + grid-template-columns: 1fr; + } + .stat { + border-left: 0 !important; + border-top: 1px solid var(--border); + } + .stat:first-child { + border-top: 0; + } } diff --git a/assets/js/main.js b/assets/js/main.js index 5bda9d4..75674c6 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -23,16 +23,26 @@ // Reveal-on-scroll. If IntersectionObserver is missing, show everything. var reveals = document.querySelectorAll(".reveal"); var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches; - var show = function (el) { el.classList.add("in"); }; + var show = function (el) { + el.classList.add("in"); + }; if (!("IntersectionObserver" in window) || reduce) { reveals.forEach(show); } else { - var io = new IntersectionObserver(function (entries) { - entries.forEach(function (e) { - if (e.isIntersecting) { show(e.target); io.unobserve(e.target); } - }); - }, { rootMargin: "0px 0px -8% 0px", threshold: 0.12 }); - reveals.forEach(function (el) { io.observe(el); }); + var io = new IntersectionObserver( + function (entries) { + entries.forEach(function (e) { + if (e.isIntersecting) { + show(e.target); + io.unobserve(e.target); + } + }); + }, + { rootMargin: "0px 0px -8% 0px", threshold: 0.12 }, + ); + reveals.forEach(function (el) { + io.observe(el); + }); // Safety net: anything already on-screen at load reveals immediately, // even if the observer is slow to fire (tall monitors, anchor deep-links). requestAnimationFrame(function () { @@ -52,15 +62,22 @@ var done = function () { if (!state) return; state.textContent = "copied ✓"; - setTimeout(function () { state.textContent = original; }, 1600); + setTimeout(function () { + state.textContent = original; + }, 1600); }; if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(done).catch(done); } else { var ta = document.createElement("textarea"); - ta.value = text; document.body.appendChild(ta); ta.select(); - try { document.execCommand("copy"); } catch (e) {} - document.body.removeChild(ta); done(); + ta.value = text; + document.body.appendChild(ta); + ta.select(); + try { + document.execCommand("copy"); + } catch (e) {} + document.body.removeChild(ta); + done(); } }); }); diff --git a/data/content.yaml b/data/content.yaml index 8fcad27..faea64f 100644 --- a/data/content.yaml +++ b/data/content.yaml @@ -15,11 +15,14 @@ hero: command: title: "you@home: ~/pithead" lines: - - { p: true, text: "curl -fsSL https://github.com/p2pool-starter-stack/pithead/releases/latest/download/pithead.tar.gz | tar xz" } - - { p: true, text: "cd pithead && cp config.json.template config.json" } - - { p: true, text: "./pithead setup" } + - { + p: true, + text: "curl -fsSL https://github.com/p2pool-starter-stack/pithead/releases/latest/download/pithead.tar.gz | tar xz", + } + - { p: true, text: "cd pithead && cp config.json.template config.json" } + - { p: true, text: "./pithead setup" } - { p: false, text: "✓ Tor provisioned · kernel tuned · stack live over HTTPS" } - cta_primary: { label: "Get Pithead", href: "https://github.com/p2pool-starter-stack/pithead" } + cta_primary: { label: "Get Pithead", href: "https://github.com/p2pool-starter-stack/pithead" } cta_secondary: { label: "View on GitHub", href: "https://github.com/p2pool-starter-stack" } meta: "MIT-licensed · built in the open · zero third-party requests" @@ -53,11 +56,11 @@ beliefs: # Mono stat band under the hero. stats: - - { value: "9", label: "services, one compose file" } - - { value: "2", label: "chains, merge-mined" } - - { value: "1", label: "command to set up" } + - { value: "9", label: "services, one compose file" } + - { value: "2", label: "chains, merge-mined" } + - { value: "1", label: "command to set up" } - { value: ":3333", label: "one endpoint for every rig" } - - { value: "0", label: "ports forwarded · IP exposed" } + - { value: "0", label: "ports forwarded · IP exposed" } # "How they fit together" flow. flow: @@ -67,9 +70,9 @@ flow: Point as many RigForge miners as you like at a single Pithead. The stack handles the nodes, privacy, payouts, and optimization — the miners just hash. nodes: - miners: { kicker: "RigForge", title: "Miners", note: "many machines · just hash" } - orch: { kicker: "Pithead", title: "Orchestrator", note: "nodes · privacy · payouts · :3333" } - chains: { kicker: "Monero + Tari", title: "Merge-mined", note: "over Tor" } + miners: { kicker: "RigForge", title: "Miners", note: "many machines · just hash" } + orch: { kicker: "Pithead", title: "Orchestrator", note: "nodes · privacy · payouts · :3333" } + chains: { kicker: "Monero + Tari", title: "Merge-mined", note: "over Tor" } side: { kicker: "XMRvsBeast", title: "Bonus rounds", note: "algorithmic hashrate split" } # The projects. Pithead is the star (featured: true). @@ -92,14 +95,42 @@ projects: image: "img/dashboard.png" image_alt: "The Pithead dashboard — live hashrate, P2Pool/XvB split, XvB tier, and per-worker stats" features: - - { icon: "onion", title: "Private by default", text: "Tor hidden services for Monero, Tari, and P2Pool — your router stays shut and your home IP is never advertised to an inbound peer." } - - { icon: "pick", title: "Monero + Tari, merge-mined", text: "Every hash mines Monero on zero-fee P2Pool and merge-mines Tari at once — a second payout for zero extra power or config." } - - { icon: "brain", title: "Algorithmic yield optimization", text: "Watches the XMRvsBeast raffle and shifts hashrate to grab bonus rounds — donating only the minimum to hold your tier, then handing every spare cycle back to your own P2Pool payouts." } - - { icon: "plug", title: "One endpoint for every rig", text: "All your miners point at a single address — no wallet in the miner, no per-rig pool config. The stack routes the hashrate." } - - { icon: "chart", title: "A dashboard worth leaving open", text: "Live hashrate, the P2Pool/XvB split shading in real time, the PPLNS window, an honest tier + explicit VIP status, and per-worker stats — over HTTPS on your LAN." } - - { icon: "shield", title: "Hardened out of the box", text: "Least-privilege containers, SHA256-verified pinned binaries, and tightly scoped Docker-socket proxies — read-only for stats, start/stop-only for failover." } + - { + icon: "onion", + title: "Private by default", + text: "Tor hidden services for Monero, Tari, and P2Pool — your router stays shut and your home IP is never advertised to an inbound peer.", + } + - { + icon: "pick", + title: "Monero + Tari, merge-mined", + text: "Every hash mines Monero on zero-fee P2Pool and merge-mines Tari at once — a second payout for zero extra power or config.", + } + - { + icon: "brain", + title: "Algorithmic yield optimization", + text: "Watches the XMRvsBeast raffle and shifts hashrate to grab bonus rounds — donating only the minimum to hold your tier, then handing every spare cycle back to your own P2Pool payouts.", + } + - { + icon: "plug", + title: "One endpoint for every rig", + text: "All your miners point at a single address — no wallet in the miner, no per-rig pool config. The stack routes the hashrate.", + } + - { + icon: "chart", + title: "A dashboard worth leaving open", + text: "Live hashrate, the P2Pool/XvB split shading in real time, the PPLNS window, an honest tier + explicit VIP status, and per-worker stats — over HTTPS on your LAN.", + } + - { + icon: "shield", + title: "Hardened out of the box", + text: "Least-privilege containers, SHA256-verified pinned binaries, and tightly scoped Docker-socket proxies — read-only for stats, start/stop-only for failover.", + } links: - - { label: "GitHub", href: "https://github.com/p2pool-starter-stack/pithead", primary: true } + - { + label: "GitHub", + href: "https://github.com/p2pool-starter-stack/pithead", + primary: true, + } - { label: "Docs", href: "https://github.com/p2pool-starter-stack/pithead/tree/main/docs" } - id: "rigforge" @@ -115,15 +146,46 @@ projects: RandomX hashrate, and runs it as a managed service — then points it at your stack, or any RandomX pool. features: - - { icon: "bolt", title: "One command, bare metal to mining", text: "Installs the toolchain, compiles commit-pinned upstream XMRig, and starts it as a managed service — on Ubuntu/Debian or macOS." } - - { icon: "chart", title: "Measurably faster, and cooler", text: "+3.5% hashrate and +7.6% efficiency on a Ryzen 7800X3D, measured live against stock XMRig — and +6.6% on a 48-core EPYC." } - - { icon: "cpu", title: "Hardware-aware tuning", text: "Detects your CPU (EPYC, Ryzen X3D, …), applies a matching profile, then live-A/Bs the hardware prefetcher to keep the fastest." } - - { icon: "gear", title: "Kernel-tuned (Linux)", text: "HugePages (1 GB / 2 MB), MSR access, NUMA binding, and a performance governor — configured for you." } - - { icon: "plug", title: "Plug-and-play", text: "Points at Pithead, or any RandomX Stratum pool. No wallet in the miner; workers don't need Tor." } - - { icon: "shield", title: "Stock XMRig, verified", text: "Compiles upstream XMRig pinned to a verified commit — no custom binary, no curl | bash. Keeps XMRig's standard 1% dev fee (it funds the upstream XMRig project, not us); one line turns it off. Idempotent re-runs." } + - { + icon: "bolt", + title: "One command, bare metal to mining", + text: "Installs the toolchain, compiles commit-pinned upstream XMRig, and starts it as a managed service — on Ubuntu/Debian or macOS.", + } + - { + icon: "chart", + title: "Measurably faster, and cooler", + text: "+3.5% hashrate and +7.6% efficiency on a Ryzen 7800X3D, measured live against stock XMRig — and +6.6% on a 48-core EPYC.", + } + - { + icon: "cpu", + title: "Hardware-aware tuning", + text: "Detects your CPU (EPYC, Ryzen X3D, …), applies a matching profile, then live-A/Bs the hardware prefetcher to keep the fastest.", + } + - { + icon: "gear", + title: "Kernel-tuned (Linux)", + text: "HugePages (1 GB / 2 MB), MSR access, NUMA binding, and a performance governor — configured for you.", + } + - { + icon: "plug", + title: "Plug-and-play", + text: "Points at Pithead, or any RandomX Stratum pool. No wallet in the miner; workers don't need Tor.", + } + - { + icon: "shield", + title: "Stock XMRig, verified", + text: "Compiles upstream XMRig pinned to a verified commit — no custom binary, no curl | bash. Keeps XMRig's standard 1% dev fee (it funds the upstream XMRig project, not us); one line turns it off. Idempotent re-runs.", + } links: - - { label: "GitHub", href: "https://github.com/p2pool-starter-stack/rigforge", primary: true } - - { label: "Benchmarks", href: "https://github.com/p2pool-starter-stack/rigforge/blob/main/docs/benchmarks.md" } + - { + label: "GitHub", + href: "https://github.com/p2pool-starter-stack/rigforge", + primary: true, + } + - { + label: "Benchmarks", + href: "https://github.com/p2pool-starter-stack/rigforge/blob/main/docs/benchmarks.md", + } # High-level roadmap, sequenced from the repos' milestones & open issues (pithead #167 v1.0 waves + # the v1.1 / v2 milestones; rigforge v1.0 is fully closed). No dates — waves and versions only. @@ -136,33 +198,77 @@ roadmap: landing a single focus — all the way to v2: flash a drive, boot, and mine. waves_label: "v1.0 · shipped, wave by wave" waves: - - { n: "01", name: "Correctness & data-safety", status: "Shipped", - text: "Killed the silent-failure bugs that burn early adopters — no surprise re-syncs, no no-op applies, no stale generated config, no vanished share history." } - - { n: "02", name: "Privacy & security", status: "Shipped", - text: "Closed every clearnet DNS and stats leak, added optional stratum + dashboard auth, made the proxy fail closed on an empty token, and shut the SSRF door — with a privacy guide mapping every connection." } - - { n: "03", name: "The dashboard", status: "Shipped", - text: "The thing people screenshot — routed hashrate everywhere, an honest tier, explicit VIP status, a toggleable averaging window, and an operator-first layout." } - - { n: "04", name: "CI & test hardening", status: "Shipped", - text: "Every container image built in CI with hadolint, every script linted, and backup/restore plus host helpers under an expanded test suite." } - - { n: "05", name: "Release gate & launch", status: "Shipped", - text: "A full end-to-end test on a real Ubuntu server, the GHCR release pipeline, and refreshed launch assets — tagged and live as v1.0." } + - { + n: "01", + name: "Correctness & data-safety", + status: "Shipped", + text: "Killed the silent-failure bugs that burn early adopters — no surprise re-syncs, no no-op applies, no stale generated config, no vanished share history.", + } + - { + n: "02", + name: "Privacy & security", + status: "Shipped", + text: "Closed every clearnet DNS and stats leak, added optional stratum + dashboard auth, made the proxy fail closed on an empty token, and shut the SSRF door — with a privacy guide mapping every connection.", + } + - { + n: "03", + name: "The dashboard", + status: "Shipped", + text: "The thing people screenshot — routed hashrate everywhere, an honest tier, explicit VIP status, a toggleable averaging window, and an operator-first layout.", + } + - { + n: "04", + name: "CI & test hardening", + status: "Shipped", + text: "Every container image built in CI with hadolint, every script linted, and backup/restore plus host helpers under an expanded test suite.", + } + - { + n: "05", + name: "Release gate & launch", + status: "Shipped", + text: "A full end-to-end test on a real Ubuntu server, the GHCR release pipeline, and refreshed launch assets — tagged and live as v1.0.", + } ship: title: "v1.0 — the whole operation, live on real hardware." text: "End-to-end tested on a real Ubuntu server, packaged, versioned, and released in the open — both Pithead and RigForge shipped at v1.0." beyond_label: "the road ahead · release by release" releases: - - { n: "1.1", status: "Next", name: "Privacy, by default", - text: "Route the P2Pool sidechain and the XvB donation upstream through Tor by default (benchmark-gated, with a documented opt-out), run every container as a non-root user, and add a component-health panel that shows each connection's Tor-vs-clearnet posture at a glance." } - - { n: "1.2", status: "Planned", name: "Operator alerts", - text: "A Telegram ping the moment a node or worker drops — and when it recovers — plus an external Healthchecks dead-man's switch that catches a dead host or power loss the stack can't report itself, with outages flagged right on the chart." } - - { n: "1.3", status: "Planned", name: "Trends & insight", - text: "Persistent time-series telemetry instead of last-value gauges: reject-rate trends, a pool cadence & luck panel, host-health badges (AVX2, HugePages, low disk), and Tari + XvB earnings calculators." } - - { n: "1.4", status: "Planned", name: "Control from the dashboard", - text: "Change any setting from the dashboard and apply it safely — and a one-click, in-place upgrade the moment a new release lands. No SSH, no CLI, no hand-edited config." } - - { n: "1.5", status: "Planned", name: "Fleet management", - text: "Read and edit each rig's XMRig config from the dashboard with versioned history, consume RigForge's richer per-worker feed (power, tune, firmware identity), and keep a primary and backup stack in sync." } - - { n: "1.6", status: "Planned", name: "Deploy anywhere", - text: "Co-hosting migration guides, relaxed network bindings for shared home servers, and a remote Tari base-node option to mirror remote Monero." } + - { + n: "1.1", + status: "Next", + name: "Privacy, by default", + text: "Route the P2Pool sidechain and the XvB donation upstream through Tor by default (benchmark-gated, with a documented opt-out), run every container as a non-root user, and add a component-health panel that shows each connection's Tor-vs-clearnet posture at a glance.", + } + - { + n: "1.2", + status: "Planned", + name: "Operator alerts", + text: "A Telegram ping the moment a node or worker drops — and when it recovers — plus an external Healthchecks dead-man's switch that catches a dead host or power loss the stack can't report itself, with outages flagged right on the chart.", + } + - { + n: "1.3", + status: "Planned", + name: "Trends & insight", + text: "Persistent time-series telemetry instead of last-value gauges: reject-rate trends, a pool cadence & luck panel, host-health badges (AVX2, HugePages, low disk), and Tari + XvB earnings calculators.", + } + - { + n: "1.4", + status: "Planned", + name: "Control from the dashboard", + text: "Change any setting from the dashboard and apply it safely — and a one-click, in-place upgrade the moment a new release lands. No SSH, no CLI, no hand-edited config.", + } + - { + n: "1.5", + status: "Planned", + name: "Fleet management", + text: "Read and edit each rig's XMRig config from the dashboard with versioned history, consume RigForge's richer per-worker feed (power, tune, firmware identity), and keep a primary and backup stack in sync.", + } + - { + n: "1.6", + status: "Planned", + name: "Deploy anywhere", + text: "Co-hosting migration guides, relaxed network bindings for shared home servers, and a remote Tari base-node option to mirror remote Monero.", + } ship_beyond: tag: "v2" name: "The appliance era" @@ -178,12 +284,30 @@ ethos: eyebrow: "// how we build" title: "The XMR ethos, in the architecture." items: - - { title: "Privacy is the default, not a setting", text: "Inbound rides Tor hidden services — no port forwarding, your home IP never shown to a peer — and RPC stays localhost-bound. The few clearnet outbound paths left in v1.0 are documented, and go Tor-by-default in v1.1." } - - { title: "Least privilege, everywhere", text: "Capability-scoped containers, a read-only Docker-socket proxy kept separate from a start/stop-only one, owner-only secrets." } - - { title: "Verifiable and pinned", text: "Third-party binaries are SHA256-checked and version-pinned. No curl | bash trust." } - - { title: "The why lives in the code", text: "Non-obvious decisions are documented inline with their reasoning and the issue that drove them." } - - { title: "Small, reversible, issue-driven", text: "Config changes are previewed and warn before anything disruptive; failures degrade gracefully." } - - { title: "Respect the operator's time", text: "Sensible auto-tuning, one-command setup, and docs treated as a first-class deliverable." } + - { + title: "Privacy is the default, not a setting", + text: "Inbound rides Tor hidden services — no port forwarding, your home IP never shown to a peer — and RPC stays localhost-bound. The few clearnet outbound paths left in v1.0 are documented, and go Tor-by-default in v1.1.", + } + - { + title: "Least privilege, everywhere", + text: "Capability-scoped containers, a read-only Docker-socket proxy kept separate from a start/stop-only one, owner-only secrets.", + } + - { + title: "Verifiable and pinned", + text: "Third-party binaries are SHA256-checked and version-pinned. No curl | bash trust.", + } + - { + title: "The why lives in the code", + text: "Non-obvious decisions are documented inline with their reasoning and the issue that drove them.", + } + - { + title: "Small, reversible, issue-driven", + text: "Config changes are previewed and warn before anything disruptive; failures degrade gracefully.", + } + - { + title: "Respect the operator's time", + text: "Sensible auto-tuning, one-command setup, and docs treated as a first-class deliverable.", + } # FAQ — answers the real questions people (and AI assistants) ask about mining # Monero at home. Plain-text answers (no HTML) so they feed the FAQPage JSON-LD @@ -261,5 +385,9 @@ cta: eyebrow: "// start here" title: "Stand up the whole operation." sub: "A private, multi-rig, merge-mining stack — running before your coffee gets cold." - primary: { label: "Start with Pithead", href: "https://github.com/p2pool-starter-stack/pithead" } - secondary: { label: "Provision miners with RigForge", href: "https://github.com/p2pool-starter-stack/rigforge" } + primary: { label: "Start with Pithead", href: "https://github.com/p2pool-starter-stack/pithead" } + secondary: + { + label: "Provision miners with RigForge", + href: "https://github.com/p2pool-starter-stack/rigforge", + } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f907ef7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1364 @@ +{ + "name": "p2pool-starter-stack-site", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "p2pool-starter-stack-site", + "version": "0.0.0", + "devDependencies": { + "markdownlint-cli2": "0.22.1", + "prettier": "3.8.4" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/katex": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.0.tgz", + "integrity": "sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/linkify-it": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", + "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdownlint": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.40.0.tgz", + "integrity": "sha512-UKybllYNheWac61Ia7T6fzuQNDZimFIpCg2w6hHjgV1Qu0w1TV0LlSgryUGzM0bkKQCBhy2FDhEELB73Kb0kAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark": "4.0.2", + "micromark-core-commonmark": "2.0.3", + "micromark-extension-directive": "4.0.0", + "micromark-extension-gfm-autolink-literal": "2.1.0", + "micromark-extension-gfm-footnote": "2.1.0", + "micromark-extension-gfm-table": "2.1.1", + "micromark-extension-math": "3.1.0", + "micromark-util-types": "2.0.2", + "string-width": "8.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli2": { + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.22.1.tgz", + "integrity": "sha512-X14ZbytybDCXAViDmtN4DKLt9ZTrRn+oOrxTYlg3a65jS6QcYYbAkGPh/En2L/GDNbFYJ6lKaQSUNrrbN1bPrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "16.2.0", + "js-yaml": "4.1.1", + "jsonc-parser": "3.3.1", + "jsonpointer": "5.0.1", + "markdown-it": "14.1.1", + "markdownlint": "0.40.0", + "markdownlint-cli2-formatter-default": "0.0.6", + "micromatch": "4.0.8", + "smol-toml": "1.6.1" + }, + "bin": { + "markdownlint-cli2": "markdownlint-cli2-bin.mjs" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli2-formatter-default": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-default/-/markdownlint-cli2-formatter-default-0.0.6.tgz", + "integrity": "sha512-VVDGKsq9sgzu378swJ0fcHfSicUnMxnL8gnLm/Q4J/xsNJ4e5bA6lvAz7PCzIl0/No0lHyaWdqVD2jotxOSFMQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + }, + "peerDependencies": { + "markdownlint-cli2": ">=0.0.4" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-4.0.0.tgz", + "integrity": "sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "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-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "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-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.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==", + "dev": true, + "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-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "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" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "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-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "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" + } + }, + "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==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "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" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "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==", + "dev": true, + "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-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^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==", + "dev": true, + "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.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smol-toml": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", + "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..ddef483 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "p2pool-starter-stack-site", + "version": "0.0.0", + "private": true, + "description": "Formatting/lint toolchain for the P2Pool Starter Stack website (Hugo site; see README).", + "scripts": { + "format": "prettier --write .", + "format:check": "prettier --check .", + "lint:md": "markdownlint-cli2", + "lint": "npm run format:check && npm run lint:md" + }, + "devDependencies": { + "markdownlint-cli2": "0.22.1", + "prettier": "3.8.4" + } +}