Files
0pt/docs/05-design-system.md
T
adminandClaude Opus 4.8 22e09d984d feat: rebrand MONO->0pt (hero, header, layout) + add project docs/contract
Hero is now a data-native 0pt artifact (no photos, keeps grain/reveal/float); header is the 0pt wordmark with Swedish nav; layout is sv + loads JetBrains Mono + 0pt metadata; globals wires the loaded fonts. Adds CLAUDE.md + docs/01-09 as the build contract. next build green (5 routes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 17:38:07 +02:00

6.0 KiB
Raw Blame History

05 · Design system (mono)

Self-contained spec. Component-level v0 prompts live in docs/design/0pt-v0-build-brief.md; the full page/component inventory + visual rules in docs/design/0pt-design-coverage-and-visuals.md. This file is the source of truth for tokens + motion; build them once and reuse.

Derived from the mono / EVASION template (itself v0-generated). Light, editorial, monochrome, sharp, with a single red accent and animated grain + scroll-reveal motion. No photography — imagery is rendered data.

Tokens

THEME (light, default):
  --background #ffffff   --foreground #0a0a0a   --muted-foreground #737373
  --border #e5e5e5       --card #ffffff         --input #f5f5f5
THEME (dark sections — footer, one editorial block):
  --background #0a0a0a   --foreground #fafafa   --muted-foreground #a3a3a3   --border #262626
ACCENT (single, sparing): red --accent #e40014   (one CTA / one number / one marker per screen)
PROVENANCE squares (ONLY non-mono color besides the red CTA):
  level 0 #737373 (unavailable/licensed) · 1 #143aff (single source) · 2 #fcbb00 (partial) · 3 #00d294 (corroborated)
RADIUS: 0 everywhere (max 2px on tiny chips). No drop shadows; structure via 1px hairlines.
TYPE: Inter (everything; headlines weight 500–600, letter-spacing -0.02em, large) · JetBrains Mono (eyebrows, labels, numbers, codes, table headers — UPPERCASE, letter-spacing 0.12em, ~11px, #737373)
GRID: 8px base; graph-paper hairlines; generous whitespace; left-aligned headlines.
SECTION SPINE: real ordered indices 00–NN as mono eyebrows.

globals.css (add verbatim — guarantees identical motion + grain)

@keyframes reveal-up{0%{opacity:0;transform:translateY(60px)}to{opacity:1;transform:translateY(0)}}
@keyframes reveal-left{0%{opacity:0;transform:translateX(-60px)}to{opacity:1;transform:translateX(0)}}
@keyframes reveal-right{0%{opacity:0;transform:translateX(60px)}to{opacity:1;transform:translateX(0)}}
@keyframes scale-in{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}
@keyframes fadeIn{0%{opacity:0;transform:scale(1.02)}to{opacity:1;transform:scale(1)}}
@keyframes slideUp{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}
@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-20px)}}
@keyframes grain{0%,100%{transform:translate(0,0)}10%{transform:translate(-5%,-10%)}20%{transform:translate(-15%,5%)}30%{transform:translate(7%,-25%)}40%{transform:translate(-5%,25%)}50%{transform:translate(-15%,10%)}60%{transform:translate(15%,0)}70%{transform:translateY(15%)}80%{transform:translate(3%,35%)}90%{transform:translate(-10%,10%)}}
.reveal{opacity:0}
.reveal.in-view{animation:.8s ease-out forwards reveal-up}
.reveal-left.in-view{animation:.8s ease-out forwards reveal-left}
.reveal-right.in-view{animation:.8s ease-out forwards reveal-right}
.reveal-scale.in-view{animation:.6s ease-out forwards scale-in}
.reveal-fade.in-view{animation:.7s ease-out forwards fadeIn}
.delay-1{animation-delay:.1s}.delay-2{animation-delay:.2s}.delay-3{animation-delay:.3s}.delay-4{animation-delay:.4s}.delay-5{animation-delay:.5s}.delay-6{animation-delay:.6s}
.animate-float{animation:6s ease-in-out infinite float}
.grain-overlay::before{content:"";position:absolute;inset:-100%;opacity:.03;pointer-events:none;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");animation:8s steps(10,end) infinite grain}
@media(prefers-reduced-motion:reduce){.reveal,.reveal-left,.reveal-right,.reveal-scale,.reveal-fade{opacity:1;animation:none}.animate-float,.grain-overlay::before{animation:none}}

useReveal hook

"use client";
import { useEffect, useRef } from "react";
export function useReveal<T extends HTMLElement = HTMLElement>() {
  const ref = useRef<T>(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver((es) => es.forEach((e) => {
      if (e.isIntersecting) {
        el.querySelectorAll(".reveal,.reveal-left,.reveal-right,.reveal-scale,.reveal-fade")
          .forEach((n) => n.classList.add("in-view"));
        io.unobserve(el);
      }
    }), { threshold: 0.15, rootMargin: "0px 0px -10% 0px" });
    io.observe(el); return () => io.disconnect();
  }, []);
  return ref;
}

Every section wraps in a tag using useReveal(); children get reveal[/-left/-right/-scale/-fade] + delay-N.

Buttons & labels

  • Primary: solid #0a0a0a bg, white text, square, mono uppercase 12px / spacing 0.1em, padding 14px 26px; hover → bg #e40014.
  • Secondary: transparent, 1px #0a0a0a border; hover → bg #0a0a0a, white text.
  • Eyebrow: mono uppercase 11px, spacing 0.14em, #737373, with a 2-digit index ("01 — KATALOG").
  • Headlines: sentence case, never uppercase.

Visual system — no photos (DataArtifact)

Build one generative primitive; every "image" surface uses it, animating with the effect it replaces:

  • table (rows cascade in, provenance square per fact cell) — hero/cards.
  • map (country-code cells, fill bars animate width on view) — coverage.
  • schema (ER mini-diagram, key boxes red border) — schema previews.
  • chart (black bars/lines, exactly ONE red series, grow on view) — dashboards.
  • grid (hairline graph-paper + faint oversized numeral + one floating red square) — pure texture.

Mapping of template image elements → replacement + effect kept is in the coverage doc. Rules: code-only (CSS/SVG/canvas), color discipline inside visuals (mono + provenance squares + one red series), grain over any "image" surface, prefers-reduced-motion settles to static. Optional: add Lenis smooth scroll on top — preserves all effects.

The signature (carry everywhere)

Provenance + confidence is the identity: the provenance square on every fact, one red, mono numerals as texture, section spine, identical motion. A screen that lacks these is off-brand.