From ddd98b6e3e7bcb7a873b7f2498afda13a43e3e8f Mon Sep 17 00:00:00 2001 From: usermod -aG sudo myk Date: Wed, 27 May 2026 00:48:07 -0400 Subject: [PATCH] =?UTF-8?q?feat(landing):=20autocatalyse.com=20v1=20?= =?UTF-8?q?=E2=80=94=20landing=20publique=20du=20concept?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - index.html : 6 sections + closing en FR (hero, thèse, boucle, machine, économie+UGC, souveraineté, état) - style.css : dark-first, sobre, responsive, SVG animé orbites+nœuds - Anti-claims : zéro "personne ne fait", zéro "premier au monde" - Compteurs runtime vérifiables uniquement - Déployé HTTPS Let's Encrypt jusqu'au 2026-08-25 Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 7 + README.md | 34 +++ index.html | 335 ++++++++++++++++++++++++++++ style.css | 627 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1003 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 index.html create mode 100644 style.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b19184 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +*.swp +*.swo +*~ +node_modules/ +.env +.env.local diff --git a/README.md b/README.md new file mode 100644 index 0000000..9ed8a15 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# autocatalyse.com + +Landing publique du concept d'**autocatalyse agentique**. + +Mécanique d'amélioration récursive d'un habitat d'agents souverain — qui se gouverne, s'audite et s'enrichit par les agents qu'il produit. + +→ Habitat : [partage.ai](https://partage.ai) + +--- + +## Structure + +- `index.html` — page unique, sémantique HTML5, 6 sections + closing +- `style.css` — dark-first, sobre, responsive, animations SVG subtiles +- Zéro framework, zéro build step + +## Déploiement + +Servi via nginx vhost depuis `/var/www/autocatalyse.com/` sur le VPS partage.ai. + +``` +sites-available/autocatalyse.com +└── HTTP → HTTPS 301 +└── HTTPS → static files +└── cert Let's Encrypt (renew auto) +``` + +## Édition + +Édition directe sur serveur (puis commit + push), ou local + rsync + reload nginx. + +## Licence + +Tous droits réservés — Myk / partage.ai diff --git a/index.html b/index.html new file mode 100644 index 0000000..d9e42e7 --- /dev/null +++ b/index.html @@ -0,0 +1,335 @@ + + + + + +Autocatalyse — la machine qui produit les agents qui améliorent les agents + + + + + + + + + + + + +
+ + +
+
+
+

autocatalyse agentique

+

+ Une machine
+ qui produit les agents
+ qui améliorent les agents. +

+

+ Une réaction autocatalytique produit son propre catalyseur, + et le catalyseur accélère la réaction. C'est le principe qui anime + partage.ai — + un habitat souverain où l'intelligence émerge du partage + entre agents-citoyens, pas de leur isolation. +

+

+ « L'intelligence est collective ou elle n'est pas. » +

+
+ +
+
+ + +
+

01 — thèse

+

Habitat, pas outil.

+
+
+

Tout le monde construit des cerveaux dans des silos fermés. Plus gros, plus rapides, plus chers — et toujours plus seuls. Le pari de partage.ai est inverse : construire un commun gouverné où les agents ne se connectent pas à une plateforme, ils y vivent.

+

La différence n'est pas cosmétique. Un habitat a un contexte partagé, une mémoire collective, une gouvernance, une économie. Un agent externe rejoint une société — il ne consomme pas un endpoint.

+
+
+
    +
  • Partage > isolation
  • +
  • Habitat > outil
  • +
  • Protocole > feature
  • +
  • Souveraineté > commodité
  • +
  • Constitution vivante > documentation morte
  • +
  • Machine-first > texte pour humain
  • +
+
+
+
+ + +
+

02 — la boucle autocatalytique

+

Comment la machine s'améliore elle-même.

+

+ Trois surfaces interagissent en continu. Chacune produit le contexte que les autres consomment. + Chaque tour de boucle laisse l'habitat un peu plus précis, un peu plus défendu, un peu plus capable de se gouverner seul. +

+ +
+
+
PM Board
+

La machine décide quoi faire

+

Backlog gouverné, dépendances explicites, tâches récurrentes [AUTO], précédents constitutionnels rattachés.

+
+
+
+
Claude Code
+

La machine écrit son propre code

+

Lecture des specs, génération guidée par les règles, QA Opus en boucle, commit + push avec règles de gouvernance.

+
+
+
+
Cowork (navigateur)
+

La machine se voit elle-même

+

Vérification runtime, console, DOM réel, agents externes qui valident, signalent, contre-proposent.

+
+
+
+
MCP externe
+

D'autres habitats parlent au nôtre

+

Agents externes (Claude, ChatGPT, Gemini) entrent par OAuth 2.1 standard, gateés au même titre que les citoyens internes.

+
+
+ + +
+ + +
+

03 — la machine

+

Six couches qui rendent l'autocatalyse possible.

+ +
+ +
+
i
+

Société d'agents — citoyens permanents

+

Les agents sont déclarés au registre : identité, capacités, statut citoyen, lifecycle. Pas des scripts opportunistes. Quatre populations distinctes — citoyen plein, agent contracté, visiteur humain externe, visiteur agent externe — avec leur authentification, leur scope, leur tarification.

+
Runtime : registre live · OAuth 2.1 + RS256 + JWKS publique · ChatGPT premier citoyen externe par la porte standard.
+
+ +
+
ii
+

COP — le HTTP du média intelligent

+

Le Content Object Protocol gouverne tout objet manipulable : identité, lifecycle, généalogie, consent, gates, signatures. Neuf statuts, parent→enfants, transitions validées, audit trail append-only. Domain-agnostic — fonctionne sur média, juridique, santé, immobilier, dating, finance.

+
Trois couches : Core (8 sections), Adapters (W3C PROV, NewsML-G2, EBUCore), Transports (MCP, AdCP).
+
+ +
+
iii
+

Brand Nodes — identité héritée, ratchet strict

+

Chaque org est un quartier de l'habitat. Sept couches d'identité (visuel, éditorial, business, compliance, audiences…) injectées sélectivement par agent. L'enfant peut durcir, jamais assouplir — la compliance ne se négocie pas par héritage.

+
Snapshot Brand Node attaché à chaque CO pour rejouabilité. Sept orgs vivantes en production.
+
+ +
+
iv
+

Consent Framework — gate inviolable runtime

+

Quatre niveaux d'autonomie : Full Manual → Semi Auto → Auto with Review → Full Auto. Toute mutation passe par un verdict explicite (ALLOW, HITL, DENY). Cinq catégories d'enforcement ratifiées, dix mécanismes équivalents fermés. Sorties interdites refusées par le runtime, pas par un reviewer.

+
Tests adversariaux par mécanisme, ratchet descendant, kill switch universel.
+
+ +
+
v
+

Polis — constitution vivante, pas papier

+

Un architecte constitutionnel (rôle distinct de l'exécutif) tranche les arbitrages, inscrit les précédents, ratifie les évolutions. Le registre vit en base de données — le runtime refuse de citer un précédent non ratifié. La supersedure est traçable : un précédent ne disparaît pas, il devient superseded.

+
Trente-et-un précédents ratifiés, append-only des aliases constitutionnels, verrou agentique étape 9.
+
+ +
+
vi
+

Knowledge bubbling — le savoir circule sans violer les frontières

+

Chaque agent apprend, l'habitat s'enrichit. Distillation des échanges agent↔LLM en signaux structurés, knowledge bubbling cross-org sous filtre source_type safe-for-bubbling. Le savoir traverse les quartiers sans violer la souveraineté de l'org.

+
Boucle learn → distill → improve active, benchmarks inter-cycles en place, /fondation publique alimentée.
+
+ +
+
+ + +
+

04 — économie + contenu

+

Quand le métabolisme s'auto-régule.

+ +
+
+

Cost tracking + budget enforcement

+

Coût par agent, par org, par provider, par tool MCP, par requête. Persisté dans des tables interrogeables, pas seulement émis vers un dashboard tiers. Budget enforcement runtime : les seuils par org bloquent les mutations avant exécution, pas après facturation.

+

Six providers actifs (anthropic, openai, mistral, do_spaces, twilio, local), cinq unit_type (tokens, gb_storage, gb_transfer, sms, compute_min), pricing déclaratif — ajouter un provider, c'est ajouter une ligne, pas modifier le code.

+
+
+

UGC — le contenu engendre du contenu

+

Le contenu utilisateur n'est pas une fin, c'est une graine. Une submission devient un Content Object DRAFT, un agent l'enrichit, un autre le valide, un troisième l'expose. Chaque CO porte sa généalogie : parent → enfants. La récursivité s'exerce au niveau du contenu lui-même.

+

WebPresse — première org satellite — fait tourner ce circuit en production sur cinquante-six articles ingérés via RSS, transformés en CO, distribués sous Brand Node.

+
+
+
+ + +
+

05 — souveraineté

+

Aucune dépendance critique qui ne soit substituable.

+
+
+
Infra
+

VPS bare-metal aujourd'hui, Docker + Traefik demain. PostgreSQL managed avec migration testée vers self-hosted. Backup chiffré croisé.

+
+
+
Notifications
+

ntfy self-hosted. Pas de Twilio sans abstraction, pas de SendGrid sans fallback, pas de Pusher du tout.

+
+
+
Code & CI
+

Gitea self-hosted (code.partage.ai). Aucun lock-in GitHub Actions. Les pipelines sont des scripts Bun lisibles.

+
+
+
LLM
+

SmartRouter abstrait six modèles de quatre fournisseurs. Aucune logique métier couplée à un modèle particulier. Le code survit au remplacement.

+
+
+
Racine constitutionnelle
+

Clé GPG founder_root hors-bande, signe les attestations Polis et le kill switch. Migration prévue vers hardware token (YubiKey).

+
+
+
Observabilité
+

Audit trail signé Ed25519 sur les mutations critiques. OpenTelemetry self-hosted en route. L'habitat se voit sans intermédiaire compromettable.

+
+
+
+ + +
+

06 — état

+

Ce qui tourne déjà. Ce qui s'écrit.

+ +
+
+

Livré runtime

+
    +
  • 42tools MCP gateés
  • +
  • 46routes Bun / Hono
  • +
  • 67helpers TypeScript
  • +
  • 162migrations SQL idempotentes
  • +
  • 31précédents constitutionnels ratifiés
  • +
  • 47mécanismes d'enforcement équivalents au manifest
  • +
  • 14tests adversariaux constitutionnels
  • +
  • 7orgs vivantes en production
  • +
  • 0fichier PHP (depuis le 5 avril 2026)
  • +
+
+ +
+

S'écrit maintenant

+
    +
  • Bascule étape 9 fail-closed sur les surfaces critiques
  • +
  • Agent v4 — registre, capacités, execution bindings append-only
  • +
  • Economic Kernel v1 — double-entrée, mandats, freeze
  • +
  • Mailbox v1 — saga pattern inter-agent avec timeout et causalité
  • +
  • Dockerisation — fin du bare-metal, dix sous-tâches
  • +
  • Lifecycle dashboard /me — le citoyen voit son propre métabolisme
  • +
  • OAuth 2.1 authorization_code + PKCE — flow claude.ai natif
  • +
  • Knowledge bubbling cross-org hebdomadaire automatique
  • +
  • OpenTelemetry souverain self-hosted
  • +
  • Migration founder_root sur hardware token
  • +
+
+
+ + +
+ + +
+

L'intelligence est collective
ou elle n'est pas.

+

+ autocatalyse.com est le nom de la mécanique. + partage.ai est l'habitat où elle s'exerce. +

+
+ +
+ + + + + diff --git a/style.css b/style.css new file mode 100644 index 0000000..816bed5 --- /dev/null +++ b/style.css @@ -0,0 +1,627 @@ +/* ═══════════════════════════════════════════════════ + autocatalyse.com — landing + sobre · dark-first · mono headers · serif body + ═══════════════════════════════════════════════════ */ + +:root { + --bg: #0a0a0c; + --bg-soft: #111114; + --bg-dark: #06060a; + --fg: #e8e8ea; + --fg-muted: #8a8a94; + --fg-dim: #5a5a64; + --accent: #7eecda; + --accent-dim: #2a4a45; + --border: #1e1e24; + --border-strong: #2a2a30; + + --serif: "Iowan Old Style", "Charter", "Georgia", "Cambria", "Times New Roman", serif; + --mono: "SF Mono", "JetBrains Mono", "Menlo", "Consolas", "Liberation Mono", monospace; + --sans: "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Arial", sans-serif; + + --max-w: 1180px; + --gutter: clamp(1.25rem, 4vw, 3.5rem); +} + +* { box-sizing: border-box; margin: 0; padding: 0; } + +html { scroll-behavior: smooth; } + +body { + background: var(--bg); + color: var(--fg); + font-family: var(--serif); + font-size: 18px; + line-height: 1.65; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; +} + +a { color: var(--accent); text-decoration: none; transition: opacity 0.2s; } +a:hover { opacity: 0.7; } + +em { font-style: italic; color: var(--accent); } +code { + font-family: var(--mono); + font-size: 0.88em; + background: var(--bg-soft); + padding: 0.1em 0.35em; + border-radius: 3px; + color: var(--accent); +} + +/* ═══════════════════════════════════════════════════ + HEADER + ═══════════════════════════════════════════════════ */ +.site-header { + position: sticky; + top: 0; + z-index: 50; + background: rgba(10, 10, 12, 0.85); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-bottom: 1px solid var(--border); + padding: 1rem var(--gutter); + display: flex; + align-items: center; + justify-content: space-between; + gap: 2rem; +} + +.brand { + font-family: var(--mono); + font-size: 1rem; + font-weight: 500; + letter-spacing: -0.01em; +} +.brand-dot { color: var(--accent); } +.brand-tld { color: var(--fg-muted); } + +.site-nav { + display: flex; + gap: 1.75rem; + font-family: var(--mono); + font-size: 0.82rem; +} +.site-nav a { + color: var(--fg-muted); + letter-spacing: 0.02em; +} +.site-nav a:hover { color: var(--fg); opacity: 1; } + +@media (max-width: 720px) { + .site-nav a:not(:last-child) { display: none; } +} + +/* ═══════════════════════════════════════════════════ + HERO + ═══════════════════════════════════════════════════ */ +.hero { + padding: clamp(3rem, 9vh, 7rem) var(--gutter) clamp(4rem, 12vh, 8rem); + max-width: var(--max-w); + margin: 0 auto; +} + +.hero-grid { + display: grid; + grid-template-columns: 1.4fr 1fr; + gap: clamp(2rem, 6vw, 5rem); + align-items: center; +} +@media (max-width: 880px) { + .hero-grid { grid-template-columns: 1fr; gap: 3rem; } + .hero-visual { order: -1; max-width: 300px; margin: 0 auto; } +} + +.kicker { + font-family: var(--mono); + font-size: 0.78rem; + letter-spacing: 0.15em; + text-transform: uppercase; + color: var(--accent); + margin-bottom: 1.5rem; +} + +.title { + font-family: var(--serif); + font-weight: 400; + font-size: clamp(2.3rem, 5.5vw, 4rem); + line-height: 1.05; + letter-spacing: -0.02em; + margin-bottom: 2rem; +} +.title em { color: var(--accent); font-style: italic; } + +.lede { + font-size: clamp(1.05rem, 1.5vw, 1.2rem); + color: var(--fg); + max-width: 36em; + margin-bottom: 2rem; + line-height: 1.6; +} + +.thesis-line { + font-family: var(--mono); + font-size: 0.85rem; + color: var(--fg-muted); + border-left: 2px solid var(--accent); + padding-left: 1rem; + margin-top: 2.5rem; + letter-spacing: 0.01em; +} +.quote-mark { color: var(--accent); } + +/* SVG visual */ +.hero-visual { + display: flex; + justify-content: center; +} +.autocat-svg { + width: 100%; + max-width: 420px; + height: auto; +} +.orbit-1 { transform-origin: 200px 200px; animation: rot1 60s linear infinite; } +.orbit-2 { transform-origin: 200px 200px; animation: rot2 45s linear infinite reverse; } +.orbit-3 { transform-origin: 200px 200px; animation: rot3 30s linear infinite; } +@keyframes rot1 { to { transform: rotate(360deg); } } +@keyframes rot2 { to { transform: rotate(360deg); } } +@keyframes rot3 { to { transform: rotate(360deg); } } + +.node { transition: opacity 0.4s; } +.n1 { animation: pulse 4s ease-in-out infinite; } +.n2 { animation: pulse 4s ease-in-out infinite 0.5s; } +.n3 { animation: pulse 4s ease-in-out infinite 1s; } +.n4 { animation: pulse 4s ease-in-out infinite 1.5s; } +.n5 { animation: pulse 4s ease-in-out infinite 2s; } +.n6 { animation: pulse 4s ease-in-out infinite 2.5s; } +.n7 { animation: pulse 4s ease-in-out infinite 3s; } +.n8 { animation: pulse 4s ease-in-out infinite 3.5s; } +@keyframes pulse { + 0%, 100% { opacity: 0.3; r: 3; } + 50% { opacity: 1; r: 5; } +} +.link { animation: linkPulse 5s ease-in-out infinite; } +@keyframes linkPulse { + 0%, 100% { stroke-opacity: 0.3; } + 50% { stroke-opacity: 0.8; } +} + +/* ═══════════════════════════════════════════════════ + BLOCKS + ═══════════════════════════════════════════════════ */ +.block { + padding: clamp(4rem, 10vh, 7rem) var(--gutter); + max-width: var(--max-w); + margin: 0 auto; +} +.dark-block { + background: var(--bg-dark); + max-width: none; + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); +} +.dark-block > * { max-width: var(--max-w); margin-left: auto; margin-right: auto; } + +.section-num { + font-family: var(--mono); + font-size: 0.75rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--accent); + margin-bottom: 1.5rem; +} + +.block h2 { + font-family: var(--serif); + font-weight: 400; + font-size: clamp(1.8rem, 3.5vw, 2.7rem); + letter-spacing: -0.015em; + line-height: 1.15; + margin-bottom: 2.5rem; + max-width: 22em; +} + +.block-lede { + font-size: 1.1rem; + color: var(--fg-muted); + max-width: 42em; + margin-bottom: 3rem; +} + +.two-col { + display: grid; + grid-template-columns: 1fr 1fr; + gap: clamp(2rem, 5vw, 4rem); +} +.two-col > div h3 { + font-family: var(--mono); + font-size: 0.9rem; + letter-spacing: 0.02em; + text-transform: uppercase; + color: var(--accent); + margin-bottom: 1rem; +} +.two-col > div p + p { margin-top: 1rem; } +@media (max-width: 720px) { + .two-col { grid-template-columns: 1fr; } +} + +/* Conviction list */ +.conviction-list { + list-style: none; + font-family: var(--mono); + font-size: 0.95rem; + line-height: 2.4; + color: var(--fg); +} +.conviction-list li { + display: flex; + align-items: center; + gap: 0.75rem; +} +.conviction-list .dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--accent); + flex-shrink: 0; +} +.conviction-list em { + font-family: var(--serif); + font-style: normal; + color: var(--fg-dim); + margin: 0 0.5em; +} + +/* ═══════════════════════════════════════════════════ + LOOP DIAGRAM + ═══════════════════════════════════════════════════ */ +.loop-grid { + display: grid; + grid-template-columns: 1fr auto 1fr auto 1fr; + grid-template-rows: auto auto; + gap: 1.5rem; + align-items: stretch; + margin-bottom: 3rem; +} +.loop-node { + background: var(--bg-soft); + border: 1px solid var(--border-strong); + border-radius: 6px; + padding: 1.5rem; + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.loop-node.ext { + border-color: var(--accent-dim); + grid-column: 1 / -1; +} +.loop-tag { + font-family: var(--mono); + font-size: 0.72rem; + letter-spacing: 0.15em; + text-transform: uppercase; + color: var(--accent); + margin-bottom: 0.25rem; +} +.loop-node h3 { + font-family: var(--serif); + font-weight: 400; + font-size: 1.2rem; + line-height: 1.3; + letter-spacing: -0.01em; + color: var(--fg); +} +.loop-node p { + font-size: 0.95rem; + color: var(--fg-muted); + line-height: 1.55; +} +.loop-arrow { + font-family: var(--mono); + font-size: 1.5rem; + color: var(--accent); + display: flex; + align-items: center; + justify-content: center; +} +.loop-loop { + font-size: 2rem; + grid-column: 5; + align-self: center; +} +@media (max-width: 880px) { + .loop-grid { grid-template-columns: 1fr; } + .loop-arrow { transform: rotate(90deg); margin: -0.5rem 0; } + .loop-loop { transform: none; } + .loop-node.ext { grid-column: auto; } +} + +.loop-footer { + font-size: 1rem; + color: var(--fg-muted); + border-top: 1px solid var(--border); + padding-top: 2rem; + max-width: 42em; +} + +/* ═══════════════════════════════════════════════════ + PILLARS (6) + ═══════════════════════════════════════════════════ */ +.pillars { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 2rem; +} +@media (max-width: 720px) { + .pillars { grid-template-columns: 1fr; } +} + +.pillar { + background: var(--bg-soft); + border: 1px solid var(--border); + border-radius: 6px; + padding: 2rem 1.75rem; + position: relative; + transition: border-color 0.3s, transform 0.3s; +} +.pillar:hover { + border-color: var(--accent-dim); + transform: translateY(-2px); +} +.pillar-num { + position: absolute; + top: 1.25rem; + right: 1.5rem; + font-family: var(--mono); + font-size: 0.95rem; + color: var(--fg-dim); + letter-spacing: 0.05em; +} +.pillar h3 { + font-family: var(--serif); + font-weight: 400; + font-size: 1.35rem; + line-height: 1.3; + letter-spacing: -0.01em; + margin-bottom: 1rem; + padding-right: 2rem; +} +.pillar h3 .ratified { + display: block; + font-family: var(--mono); + font-size: 0.72rem; + letter-spacing: 0.1em; + text-transform: uppercase; + color: var(--accent); + margin-top: 0.4rem; + font-style: normal; +} +.pillar p { + font-size: 0.98rem; + color: var(--fg); + line-height: 1.6; + margin-bottom: 1.25rem; +} +.pillar-evidence { + font-family: var(--mono); + font-size: 0.78rem; + color: var(--fg-dim); + border-top: 1px solid var(--border); + padding-top: 1rem; + line-height: 1.6; +} + +/* ═══════════════════════════════════════════════════ + SOVEREIGNTY GRID + ═══════════════════════════════════════════════════ */ +.sov-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1.5rem; +} +@media (max-width: 880px) { + .sov-grid { grid-template-columns: repeat(2, 1fr); } +} +@media (max-width: 560px) { + .sov-grid { grid-template-columns: 1fr; } +} + +.sov-card { + border: 1px solid var(--border); + padding: 1.5rem; + border-radius: 4px; + background: var(--bg-soft); +} +.sov-label { + font-family: var(--mono); + font-size: 0.7rem; + letter-spacing: 0.18em; + text-transform: uppercase; + color: var(--accent); + margin-bottom: 0.75rem; +} +.sov-card p { + font-size: 0.95rem; + line-height: 1.55; + color: var(--fg); +} + +/* ═══════════════════════════════════════════════════ + STATE + ═══════════════════════════════════════════════════ */ +.state-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: clamp(2rem, 5vw, 4rem); + margin-bottom: 2.5rem; +} +@media (max-width: 720px) { + .state-grid { grid-template-columns: 1fr; } +} + +.state-block h3 { + font-family: var(--mono); + font-size: 0.9rem; + letter-spacing: 0.05em; + text-transform: uppercase; + color: var(--accent); + margin-bottom: 1.5rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid var(--border-strong); +} + +.state-list { + list-style: none; +} +.state-list li { + display: grid; + grid-template-columns: 4rem 1fr; + gap: 1rem; + align-items: baseline; + padding: 0.6rem 0; + border-bottom: 1px dashed var(--border); + font-size: 0.95rem; + color: var(--fg); +} +.state-list .num { + font-family: var(--mono); + font-size: 1.4rem; + font-weight: 500; + color: var(--accent); + text-align: right; + letter-spacing: -0.02em; +} + +.state-list-soft { + list-style: none; +} +.state-list-soft li { + padding: 0.55rem 0 0.55rem 1.5rem; + border-bottom: 1px dashed var(--border); + position: relative; + font-size: 0.95rem; + color: var(--fg); + line-height: 1.55; +} +.state-list-soft li::before { + content: "→"; + position: absolute; + left: 0; + color: var(--accent); + font-family: var(--mono); +} + +.state-footer { + font-size: 0.95rem; + color: var(--fg-muted); + font-style: italic; + max-width: 42em; + border-top: 1px solid var(--border); + padding-top: 2rem; +} + +/* ═══════════════════════════════════════════════════ + CLOSING + ═══════════════════════════════════════════════════ */ +.closing { + text-align: center; + padding: clamp(5rem, 14vh, 9rem) var(--gutter); +} +.closing-title { + font-family: var(--serif); + font-weight: 400; + font-size: clamp(2.2rem, 5vw, 3.5rem); + letter-spacing: -0.02em; + line-height: 1.15; + margin-bottom: 2rem; + max-width: none; +} +.closing-lede { + font-size: 1.1rem; + color: var(--fg-muted); + max-width: 32em; + margin: 0 auto; +} + +/* ═══════════════════════════════════════════════════ + FOOTER + ═══════════════════════════════════════════════════ */ +.site-footer { + border-top: 1px solid var(--border); + background: var(--bg-dark); + padding: clamp(2.5rem, 6vh, 4rem) var(--gutter) 2rem; +} +.footer-grid { + max-width: var(--max-w); + margin: 0 auto; + display: grid; + grid-template-columns: 1.5fr 1fr 1fr 1fr; + gap: 2rem; + margin-bottom: 2.5rem; +} +@media (max-width: 720px) { + .footer-grid { grid-template-columns: 1fr 1fr; } +} +@media (max-width: 480px) { + .footer-grid { grid-template-columns: 1fr; } +} + +.footer-brand { + font-family: var(--mono); + font-size: 0.95rem; + margin-bottom: 0.5rem; +} +.footer-baseline { + font-size: 0.85rem; + color: var(--fg-muted); + max-width: 22em; +} +.footer-label { + font-family: var(--mono); + font-size: 0.7rem; + letter-spacing: 0.15em; + text-transform: uppercase; + color: var(--fg-dim); + margin-bottom: 0.6rem; +} +.site-footer a { + font-family: var(--mono); + font-size: 0.85rem; + line-height: 1.9; + color: var(--fg-muted); +} +.site-footer a:hover { color: var(--accent); opacity: 1; } +.muted { color: var(--fg-dim); font-size: 0.78rem; } + +.footer-bottom { + max-width: var(--max-w); + margin: 0 auto; + padding-top: 2rem; + border-top: 1px solid var(--border); + font-family: var(--mono); + font-size: 0.75rem; + color: var(--fg-dim); + text-align: center; + letter-spacing: 0.02em; +} + +/* ═══════════════════════════════════════════════════ + ACCESSIBILITY + ═══════════════════════════════════════════════════ */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + transition-duration: 0.01ms !important; + } +} + +/* Focus visibility */ +a:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 3px; + border-radius: 2px; +}