From 2cf1b64bfadd8ba173f32100518d4d9dac32f0d3 Mon Sep 17 00:00:00 2001 From: Andy Dixon Date: Mon, 8 Jun 2026 08:54:29 +0100 Subject: [PATCH] Initial Version --- README.md | 102 ++++++++ index.html | 269 +++++++++++++++++++++ washi.css | 668 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1039 insertions(+) create mode 100644 README.md create mode 100644 index.html create mode 100644 washi.css diff --git a/README.md b/README.md new file mode 100644 index 0000000..9d60416 --- /dev/null +++ b/README.md @@ -0,0 +1,102 @@ +# 和紙 · Washi + +> © 2026 Andy Dixon · [www.dixon.cx](https://www.dixon.cx) · All rights reserved. + +A warm **paper & sumi-ink** CSS framework. No build step, no dependencies — one +stylesheet of plain, semantic class names you drop straight onto markup. + +``` +v3/ +├── washi.css ← the framework (tokens + reset + components + utilities) +├── index.html ← live showcase of every component +└── README.md ← this file +``` + +## Quick start + +```html + + +``` + +Fonts (Noto Serif JP + DM Mono) are `@import`ed by `washi.css`, so no extra `` +is required. Optional dark theme: add `data-theme="sumi"` to ``. + +--- + +## Design language + +| Aspect | Choice | +|-------------|------------------------------------------------------------------| +| Background | Warm washi paper `#f3ede1` + greyscale noise + corner colour-washes | +| Text/ink | Sumi `#1a1714`, monospace body (**DM Mono**) | +| Display | **Noto Serif JP** — headings, brand mark, big numbers, kanji | +| Accents | Vermilion `#c0392b`, jade `#2e7d5e`, murasaki `#7c5cbf`, gold `#b07d2e` | +| UI labels | UPPERCASE, wide letter-spacing, small (eyebrows / button text) | +| Borders | 1.5px hairlines; 2px ink rules under headers/footers | +| Radius | Tight — 2px controls, 4px inputs, 8px cards | +| Motion | Press-down buttons, fade/pop overlays, shimmer loading | +| Signature | The **hanko seal** (`.seal`) and `完`-style kanji flourishes | + +All values are CSS custom properties under `:root` — see the **DESIGN TOKENS** +section of `washi.css`. Re-theme by overriding the semantic aliases +(`--bg`, `--surface`, `--text`, `--heading`, `--border`, `--accent`, …). + +--- + +## Component cheat-sheet + +**Layout** — `.container` / `.container-sm`, `.section`, `.grid` (auto) / +`.grid-2/3/4`, `.stack` / `.stack-sm` / `.stack-lg`, `.cluster`, `.spread`, `.center`. + +**Header/nav** — `.site-header` > `.brand` (`.mark` JP + `.mark-en`) and +`.nav` > `a` (use `aria-current="page"` for the active link). + +**Typography** — `h1`–`h6` (serif), `.display`, `.title-jp`, `.eyebrow` / `.label`, +`.lead`, `.kanji`. Text colour: `.muted`, `.t-accent`, `.t-jade`, `.t-violet`, `.t-gold`. + +**Buttons** — `.btn` + one of `.btn-primary` `.btn-accent` `.btn-success` +`.btn-info` `.btn-danger` `.btn-ghost`; sizes `.btn-sm` / `.btn-lg` / `.btn-block`; +`.is-loading` for the shimmer. Groups: `.segmented` (square, joined) and +`.pills` (rounded ends). Mark the selected child `.active` or `aria-pressed="true"`. + +**Cards** — `.card` > `.card-header` / `.card-body` / `.card-footer`; `.card-title`; +add `.card-hover` for lift; top-stripe variants `.card-accent/-jade/-violet/-gold`. + +**Feedback** — `.badge` (+ `-accent/-jade/-violet/-gold/-solid`), `.tag`, +`.alert` (+ `-accent/-jade/-violet/-gold`) with `.alert-title`, +`.status` (+ `.error/.success/.info`). + +**Forms** — `.field` > `label` + input; styled `input/textarea/select`, +`.check` for checkbox/radio rows, `.input-group`, validation `.is-valid/.is-invalid`, +`.hint`. + +**Data** — `.table` (+ `.table-hover`, `.table-zebra`), `pre`/`code` blocks, `.stat` > `.stat-num` + `.stat-label`. + +**Flourish** — `.seal` / `.seal-round` / `.seal-ink` (hanko stamp), +`.rule` (centred-glyph divider), `.hero`. + +**Overlay** — `.overlay` + toggle `.show`; `.modal` inside; `.win-kanji` for the popped kanji. + +**Utilities** — `.surface`, `.bordered`, `.shadow` / `.shadow-lg`, `.text-center/-right`, +`.uppercase`, `.full`, `.hidden`, spacing `.mt-* / .mb-*`. + +--- + +## Redesigning a site with Washi + +When asked to *"redesign <site> using Washi"*, the recipe is: + +1. Link `washi.css`; remove the old stylesheet. +2. Wrap the page in `.site-header` + `.container` + `.site-footer`. +3. Map existing UI to the cheat-sheet above — prefer composing the provided classes + over writing new CSS. Reach for tokens (`var(--…)`) before hard-coded values. +4. Use Noto Serif JP (`h*` / `.display` / `.title-jp`) for headings and one or two + kanji/seal flourishes; keep everything else in mono. +5. Keep the palette disciplined: ink + paper as the base, **one** accent per section. + +`reduced-motion` and keyboard `:focus-visible` are handled by the framework. + +--- + +© 2026 Andy Dixon · [www.dixon.cx](https://www.dixon.cx) · All rights reserved. diff --git a/index.html b/index.html new file mode 100644 index 0000000..1977855 --- /dev/null +++ b/index.html @@ -0,0 +1,269 @@ + + + + + + +和紙 · Washi — CSS Framework + + + + + + + + + + +
+
+ CSS Framework · 和紙 +

Paper & sumi ink,
as a design system.

+

A warm, tactile component kit — washi-paper tones, vermilion seal red, jade and murasaki accents, monospace body type and Noto Serif JP display.

+
+ Explore components + View tokens + +
+
+
+ +
+ + +
+
色 · Colour
+
+
--paper
+
--card
+
--paper-2
+
--paper-3
+
--ink
+
--accent
+
--jade
+
--murasaki
+
--gold
+
--muted
+
+
+ + +
+
字 · Typography
+
+
+ Eyebrow label +

Display heading 見出し

+

Section heading

+

Subsection heading

+

A lead paragraph sets the tone — slightly larger, softer ink, tighter leading.

+

Body copy is set in DM Mono for a precise, drafting-table feel. Inline code, a hyperlink, strong emphasis, and ⌘K keys all live here.

+
+
+
The space between things is where the design lives. + — a maxim
+
    +
  • Marker bullets carry the accent colour
  • +
  • Generous line-height for readability
  • +
  • Consistent vertical rhythm
  • +
+
:root {
+  --ink:    #1a1714;
+  --paper:  #f3ede1;
+  --accent: #c0392b;
+}
+
+
+
+ + +
+
釦 · Buttons
+
+
+ + + + + + + + +
+
+ + + + +
+
+
+ + + +
+
+ + + +
+
+
+
+ + +
+
部品 · Components
+ +

Cards

+
+
+
+ New +

Vermilion

+

Cards lift on hover and carry an optional coloured top-stripe.

+
+
+
+

Jade

完
+

A header row pairs nicely with a hanko seal.

+ +
+
+
+

Murasaki

+

Soft warm shadows, hairline borders, paper surface.

+
tagtag
+
+
+
+ +

Badges, tags & stats

+
+ Default + Accent + Jade + Violet + Gold + Solid +
+
+
和Harmony
+
42Projects
+
3:08Avg time
+
98%Uptime
+
+ +

Alerts & status

+
+
Vermilion alertSomething needs attention.
+
SuccessThe operation completed cleanly.
+
NoteAn aside, set apart in murasaki.
+
+ Default status + Invalid input + Looking good! + Solving… +
+
+ +

Table

+
+ + + + + + + +
PieceAreaState
Rectangle A2 × 3Valid
Rectangle B1 × 4Valid
Rectangle C3 × 3Overlap
+
+ +

Overlay / modal

+ +
+ + +
+
入力 · Forms
+
+
+
+ + +
+
+ + + Looks valid. +
+
+ + +
+
+
+
+ + +
+ + + +
+ + +
+
+
+
+ +
+ + + + +
+ +
+ + + + diff --git a/washi.css b/washi.css new file mode 100644 index 0000000..5cd5dea --- /dev/null +++ b/washi.css @@ -0,0 +1,668 @@ +/* ════════════════════════════════════════════════════════════════════════════ + WASHI · 和紙 + A warm "paper & sumi-ink" CSS framework — Japanese paper tones, vermilion seal + red, jade, and murasaki purple, monospace body + Noto Serif JP display. + + Load order: + + + + Usage: plain, semantic class names. Drop them onto markup directly. + Optional dark theme: … + + © 2026 Andy Dixon · www.dixon.cx · All rights reserved. + ════════════════════════════════════════════════════════════════════════════ */ + +@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+JP:wght@400;600;700&family=DM+Mono:wght@400;500&display=swap'); + +/* ════════════════════════════════════════════════════════════════════════════ + 1 · DESIGN TOKENS + ════════════════════════════════════════════════════════════════════════════ */ +:root { + /* ── Core palette ─────────────────────────────────────────────────────── */ + --ink: #1a1714; /* sumi — primary text & strong borders */ + --ink-2: #4a4039; /* softer ink — secondary text */ + --paper: #f3ede1; /* washi — page background */ + --paper-2: #ece4d4; /* dividers, hover, subtle wells */ + --paper-3: #e3d9c4; /* deeper wells, code surfaces */ + --card: #faf7f0; /* raised surface (the canvas tone) */ + --accent: #c0392b; /* shu — vermilion seal red */ + --accent-2: #a3281d; /* darker vermilion for hover/active */ + --jade: #2e7d5e; /* success / valid */ + --jade-2: #246449; + --murasaki: #7c5cbf; /* info / special */ + --murasaki-2: #6a49ad; + --gold: #b07d2e; /* warning — sits inside the warm palette */ + --gold-2: #946727; + --muted: #8c8078; /* eyebrows, captions, meta */ + --line: #cabfae; /* hairline borders */ + + /* ── Soft tint fills (badges, alerts, hovers) ─────────────────────────── */ + --accent-soft: rgba(192, 57, 43, 0.10); + --jade-soft: rgba(46, 125, 94, 0.13); + --murasaki-soft: rgba(124, 92, 191, 0.12); + --gold-soft: rgba(176, 125, 46, 0.14); + --ink-soft: rgba(26, 23, 20, 0.06); + + /* ── Semantic aliases (themeable) ─────────────────────────────────────── */ + --bg: var(--paper); + --surface: var(--card); + --surface-2: var(--paper-2); + --text: var(--ink); + --text-dim: var(--muted); + --heading: var(--ink); + --border: var(--line); + --border-strong: var(--ink); + --link: var(--accent); + --link-hover: var(--accent-2); + + /* ── Typography ───────────────────────────────────────────────────────── */ + --font-display: 'Noto Serif JP', Georgia, 'Times New Roman', serif; + --font-mono: 'DM Mono', ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace; + --font-body: var(--font-mono); + + --fs-xs: 0.6875rem; /* 11px — labels, badges */ + --fs-sm: 0.8125rem; /* 13px — meta, captions */ + --fs-base: 0.9375rem; /* 15px — body */ + --fs-md: 1.0625rem; /* 17px — lead */ + --fs-lg: 1.375rem; /* 22px */ + --fs-xl: 1.875rem; /* 30px */ + --fs-2xl: 2.625rem; /* 42px */ + --fs-3xl: 3.75rem; /* 60px — hero display */ + + --lh-tight: 1.2; + --lh-snug: 1.45; + --lh-base: 1.7; + --tracking-wide: 0.12em; /* uppercase UI labels */ + --tracking-wider: 0.2em; /* eyebrows */ + --tracking-jp: 0.05em; /* display serif */ + + /* ── Spacing scale ────────────────────────────────────────────────────── */ + --sp-1: 0.25rem; + --sp-2: 0.5rem; + --sp-3: 0.75rem; + --sp-4: 1rem; + --sp-5: 1.5rem; + --sp-6: 2rem; + --sp-7: 3rem; + --sp-8: 4.5rem; + + /* ── Radius ───────────────────────────────────────────────────────────── */ + --r-sm: 2px; + --r: 4px; + --r-lg: 8px; + --r-pill: 999px; + + /* ── Borders ──────────────────────────────────────────────────────────── */ + --bw: 1.5px; /* standard control border weight */ + --bw-strong: 2px; /* section rules */ + + /* ── Shadows (warm sumi, not neutral grey) ────────────────────────────── */ + --shadow-sm: 0 1px 2px rgba(26, 23, 20, 0.06); + --shadow: 0 2px 8px rgba(26, 23, 20, 0.08), 0 1px 2px rgba(26, 23, 20, 0.06); + --shadow-lg: 0 12px 32px rgba(26, 23, 20, 0.14), 0 4px 10px rgba(26, 23, 20, 0.08); + + /* ── Motion ───────────────────────────────────────────────────────────── */ + --t-fast: 0.08s ease; + --t: 0.12s ease; + --t-slow: 0.35s ease; + + /* ── Layout ───────────────────────────────────────────────────────────── */ + --container: 1080px; + --container-sm: 720px; + --pad: clamp(1rem, 4vw, 2.5rem); + + /* ── Textures ─────────────────────────────────────────────────────────── */ + --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E"); +} + +/* ── Dark "sumi" theme — ink ground, paper text ──────────────────────────── */ +[data-theme="sumi"] { + --paper: #1a1714; + --paper-2: #241f1a; + --paper-3: #2d2720; + --card: #211c17; + --ink: #f3ede1; + --ink-2: #cabfae; + --muted: #9a8f84; + --line: #3a332b; + + --accent: #e0594b; + --accent-2: #ef6f61; + --jade: #5cb78f; + --jade-2: #74c9a3; + --murasaki: #a487e0; + --murasaki-2:#b89af0; + --gold: #d6a24e; + + --border-strong: #5a4f43; + --link: var(--accent); + --link-hover: var(--accent-2); + + --accent-soft: rgba(224, 89, 75, 0.14); + --jade-soft: rgba(92, 183, 143, 0.14); + --murasaki-soft: rgba(164, 135, 224, 0.16); + --gold-soft: rgba(214, 162, 78, 0.16); + --ink-soft: rgba(243, 237, 225, 0.06); + + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4); + --shadow: 0 2px 10px rgba(0, 0, 0, 0.45); + --shadow-lg: 0 14px 36px rgba(0, 0, 0, 0.6); +} + +/* ════════════════════════════════════════════════════════════════════════════ + 2 · RESET & BASE + ════════════════════════════════════════════════════════════════════════════ */ +*, *::before, *::after { + box-sizing: border-box; + margin: 0; + padding: 0; + -webkit-tap-highlight-color: transparent; +} + +html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; } + +body { + background-color: var(--bg); + background-image: + radial-gradient(circle at 20% 15%, rgba(192, 57, 43, 0.04), transparent 40%), + radial-gradient(circle at 85% 80%, rgba(124, 92, 191, 0.04), transparent 42%), + var(--noise); + color: var(--text); + font-family: var(--font-body); + font-size: var(--fs-base); + line-height: var(--lh-base); + min-height: 100dvh; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + overflow-x: hidden; +} + +img, svg, video, canvas { display: block; max-width: 100%; height: auto; } +::selection { background: var(--accent); color: var(--paper); } + +:where(a, button, input, textarea, select):focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + border-radius: var(--r-sm); +} + +/* ════════════════════════════════════════════════════════════════════════════ + 3 · TYPOGRAPHY + ════════════════════════════════════════════════════════════════════════════ */ +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-display); + font-weight: 700; + color: var(--heading); + line-height: var(--lh-tight); + letter-spacing: var(--tracking-jp); +} +h1 { font-size: var(--fs-2xl); } +h2 { font-size: var(--fs-xl); } +h3 { font-size: var(--fs-lg); } +h4 { font-size: var(--fs-md); font-weight: 600; } +h5 { font-size: var(--fs-base); font-weight: 600; } +h6 { font-size: var(--fs-sm); font-weight: 600; } + +p { margin: 0; } +p + p { margin-top: var(--sp-4); } + +a { + color: var(--link); + text-decoration: none; + border-bottom: 1px solid transparent; + transition: color var(--t), border-color var(--t); +} +a:hover { color: var(--link-hover); border-bottom-color: currentColor; } + +strong, b { font-weight: 500; color: var(--ink); } +small { font-size: var(--fs-sm); } + +ul, ol { padding-left: 1.3em; } +li + li { margin-top: var(--sp-2); } +li::marker { color: var(--accent); } + +hr { + border: 0; + border-top: 1px solid var(--border); + margin: var(--sp-6) 0; +} + +blockquote { + border-left: 3px solid var(--accent); + padding: var(--sp-2) 0 var(--sp-2) var(--sp-5); + margin: var(--sp-5) 0; + color: var(--ink-2); + font-style: italic; +} +blockquote cite { display: block; margin-top: var(--sp-3); font-style: normal; + font-size: var(--fs-xs); letter-spacing: var(--tracking-wide); + text-transform: uppercase; color: var(--muted); } + +code, kbd, samp { font-family: var(--font-mono); font-size: 0.9em; } +:not(pre) > code { + background: var(--paper-3); + padding: 0.12em 0.4em; + border-radius: var(--r-sm); + color: var(--accent-2); +} +kbd { + background: var(--card); + border: 1px solid var(--border); + border-bottom-width: 2px; + border-radius: var(--r); + padding: 0.1em 0.45em; + font-size: var(--fs-xs); + color: var(--ink); +} + +/* ── Display & label utilities ───────────────────────────────────────────── */ +.display { + font-family: var(--font-display); + font-size: clamp(var(--fs-2xl), 7vw, var(--fs-3xl)); + font-weight: 700; + line-height: 1.05; + letter-spacing: var(--tracking-jp); +} +.title-jp { font-family: var(--font-display); font-weight: 700; letter-spacing: var(--tracking-jp); } + +.eyebrow, .label { + display: inline-block; + font-family: var(--font-mono); + font-size: var(--fs-xs); + letter-spacing: var(--tracking-wider); + text-transform: uppercase; + color: var(--muted); +} +.lead { font-size: var(--fs-md); color: var(--ink-2); line-height: var(--lh-snug); } +.kanji { font-family: var(--font-display); line-height: 1; } + +/* Colour text helpers */ +.muted { color: var(--muted); } +.t-ink { color: var(--ink); } +.t-accent{ color: var(--accent); } +.t-jade { color: var(--jade); } +.t-violet{ color: var(--murasaki); } +.t-gold { color: var(--gold); } + +/* ════════════════════════════════════════════════════════════════════════════ + 4 · LAYOUT + ════════════════════════════════════════════════════════════════════════════ */ +.container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--pad); } +.container-sm { width: 100%; max-width: var(--container-sm); margin-inline: auto; padding-inline: var(--pad); } + +.section { padding-block: clamp(var(--sp-6), 8vw, var(--sp-8)); } + +.stack { display: flex; flex-direction: column; gap: var(--sp-4); } +.stack-sm { display: flex; flex-direction: column; gap: var(--sp-2); } +.stack-lg { display: flex; flex-direction: column; gap: var(--sp-6); } +.cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); } +.cluster-sm { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); } +.spread { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); } +.center { display: flex; align-items: center; justify-content: center; } + +.grid { display: grid; gap: var(--sp-5); grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } +.grid-2 { display: grid; gap: var(--sp-5); grid-template-columns: repeat(2, 1fr); } +.grid-3 { display: grid; gap: var(--sp-5); grid-template-columns: repeat(3, 1fr); } +.grid-4 { display: grid; gap: var(--sp-5); grid-template-columns: repeat(4, 1fr); } +@media (max-width: 760px) { + .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } +} + +/* ════════════════════════════════════════════════════════════════════════════ + 5 · SITE HEADER / NAV + ════════════════════════════════════════════════════════════════════════════ */ +.site-header { + position: sticky; top: 0; z-index: 50; + display: flex; align-items: baseline; gap: var(--sp-3); + padding: var(--sp-4) var(--pad) var(--sp-3); + border-bottom: var(--bw-strong) solid var(--ink); + background: color-mix(in srgb, var(--paper) 88%, transparent); + backdrop-filter: blur(6px); +} +.brand { display: flex; align-items: baseline; gap: var(--sp-3); } +.brand .mark { font-family: var(--font-display); font-size: var(--fs-lg); font-weight: 700; letter-spacing: var(--tracking-jp); color: var(--ink); } +.brand .mark-en { font-size: var(--fs-xs); letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--muted); } + +.nav { display: flex; align-items: center; gap: var(--sp-5); margin-left: auto; } +.nav a { + font-size: var(--fs-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; + color: var(--muted); border-bottom: none; padding-bottom: 2px; + border-bottom: 2px solid transparent; +} +.nav a:hover, .nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--accent); } + +/* ════════════════════════════════════════════════════════════════════════════ + 6 · BUTTONS + ════════════════════════════════════════════════════════════════════════════ */ +.btn { + display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); + font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 500; + letter-spacing: var(--tracking-wide); text-transform: uppercase; + padding: 0.65em 1.15em; + border: var(--bw) solid var(--ink); border-radius: var(--r-sm); + background: transparent; color: var(--ink); cursor: pointer; white-space: nowrap; + transition: background var(--t), color var(--t), border-color var(--t), transform var(--t-fast); + -webkit-user-select: none; user-select: none; text-decoration: none; +} +.btn:hover { background: var(--ink); color: var(--paper); } +.btn:active { transform: translateY(1px); } +.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.4; pointer-events: none; } + +.btn-primary { background: var(--ink); color: var(--paper); } +.btn-primary:hover { background: var(--accent); border-color: var(--accent); } + +.btn-accent { border-color: var(--accent); color: var(--accent); } +.btn-accent:hover { background: var(--accent); color: var(--paper); } + +.btn-danger { border-color: var(--accent); color: var(--accent); } +.btn-danger:hover { background: var(--accent); color: var(--paper); } + +.btn-success { border-color: var(--jade); color: var(--jade); } +.btn-success:hover { background: var(--jade); color: var(--paper); } + +.btn-info { border-color: var(--murasaki); color: var(--murasaki); } +.btn-info:hover { background: var(--murasaki); color: var(--paper); } + +.btn-ghost { border-color: transparent; color: var(--ink-2); } +.btn-ghost:hover { background: var(--ink-soft); color: var(--ink); } + +.btn-sm { font-size: 0.625rem; padding: 0.5em 0.85em; } +.btn-lg { font-size: var(--fs-sm); padding: 0.8em 1.5em; } +.btn-block { display: flex; width: 100%; } + +/* Loading shimmer — add .is-loading */ +.btn.is-loading { position: relative; overflow: hidden; pointer-events: none; } +.btn.is-loading::after { + content: ''; position: absolute; left: -120%; top: 0; bottom: 0; width: 70%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.35), transparent); + animation: washi-shimmer 0.9s infinite; +} +@keyframes washi-shimmer { to { left: 220%; } } + +/* ── Segmented control (square, joined) ──────────────────────────────────── */ +.segmented { display: inline-flex; } +.segmented .btn, .segmented button { + border-radius: 0; margin-left: calc(var(--bw) * -1); +} +.segmented :first-child { border-radius: var(--r-sm) 0 0 var(--r-sm); margin-left: 0; } +.segmented :last-child { border-radius: 0 var(--r-sm) var(--r-sm) 0; } +.segmented .active, .segmented [aria-pressed="true"] { background: var(--ink); color: var(--paper); } + +/* ── Pills (rounded ends, muted by default) ──────────────────────────────── */ +.pills { display: inline-flex; } +.pills .btn, .pills button { + border-radius: 0; margin-left: calc(var(--bw) * -1); + border-color: var(--muted); color: var(--muted); +} +.pills :first-child { border-radius: var(--r-pill) 0 0 var(--r-pill); padding-left: 1.2em; margin-left: 0; } +.pills :last-child { border-radius: 0 var(--r-pill) var(--r-pill) 0; padding-right: 1.2em; } +.pills .active, .pills [aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--paper); } + +/* ════════════════════════════════════════════════════════════════════════════ + 7 · CARDS + ════════════════════════════════════════════════════════════════════════════ */ +.card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--r-lg); + box-shadow: var(--shadow-sm); + overflow: hidden; + transition: transform var(--t-slow), box-shadow var(--t-slow), border-color var(--t-slow); +} +.card-body { padding: var(--sp-5); } +.card-header { + padding: var(--sp-4) var(--sp-5); + border-bottom: 1px solid var(--border); + display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); +} +.card-footer { + padding: var(--sp-4) var(--sp-5); + border-top: 1px solid var(--border); + background: var(--paper-2); +} +.card-title { font-family: var(--font-display); font-size: var(--fs-lg); font-weight: 600; } + +.card-hover:hover, a.card:hover { + transform: translateY(-3px); + box-shadow: var(--shadow-lg); + border-color: var(--line); +} + +/* Accent top-stripe variants */ +.card-accent { border-top: 3px solid var(--accent); } +.card-jade { border-top: 3px solid var(--jade); } +.card-violet { border-top: 3px solid var(--murasaki); } +.card-gold { border-top: 3px solid var(--gold); } + +/* ════════════════════════════════════════════════════════════════════════════ + 8 · HERO + ════════════════════════════════════════════════════════════════════════════ */ +.hero { + position: relative; overflow: hidden; + padding-block: clamp(var(--sp-7), 12vw, calc(var(--sp-8) * 1.6)); + text-align: center; +} +.hero::before { + content: ''; position: absolute; inset: 0; z-index: -1; + background: + radial-gradient(circle at 25% 20%, var(--accent-soft), transparent 45%), + radial-gradient(circle at 80% 75%, var(--murasaki-soft), transparent 48%); +} +.hero .eyebrow { margin-bottom: var(--sp-4); } +.hero .display { margin-bottom: var(--sp-4); } +.hero p { max-width: 52ch; margin-inline: auto; color: var(--ink-2); } +.hero .cluster { justify-content: center; margin-top: var(--sp-6); } + +/* ════════════════════════════════════════════════════════════════════════════ + 9 · BADGES & TAGS + ════════════════════════════════════════════════════════════════════════════ */ +.badge { + display: inline-flex; align-items: center; gap: 0.4em; + font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 500; + letter-spacing: var(--tracking-wide); text-transform: uppercase; + padding: 0.25em 0.65em; border-radius: var(--r-sm); + border: 1px solid var(--border); color: var(--ink-2); background: var(--paper-2); +} +.badge-accent { color: var(--accent); background: var(--accent-soft); border-color: transparent; } +.badge-jade { color: var(--jade); background: var(--jade-soft); border-color: transparent; } +.badge-violet { color: var(--murasaki); background: var(--murasaki-soft); border-color: transparent; } +.badge-gold { color: var(--gold); background: var(--gold-soft); border-color: transparent; } +.badge-solid { color: var(--paper); background: var(--ink); border-color: var(--ink); } + +.tag { + display: inline-flex; font-family: var(--font-mono); font-size: var(--fs-sm); + padding: 0.2em 0.7em; border: 1px solid var(--border); border-radius: var(--r-pill); + color: var(--ink-2); +} + +/* ════════════════════════════════════════════════════════════════════════════ + 10 · ALERTS / CALLOUTS + ════════════════════════════════════════════════════════════════════════════ */ +.alert { + display: flex; gap: var(--sp-3); + padding: var(--sp-4) var(--sp-5); + border: 1px solid var(--border); border-left-width: 3px; + border-radius: var(--r); + background: var(--surface); + font-size: var(--fs-sm); +} +.alert-title { font-weight: 500; color: var(--ink); display: block; margin-bottom: 0.2em; } +.alert-accent { border-left-color: var(--accent); background: var(--accent-soft); } +.alert-jade { border-left-color: var(--jade); background: var(--jade-soft); } +.alert-violet { border-left-color: var(--murasaki); background: var(--murasaki-soft); } +.alert-gold { border-left-color: var(--gold); background: var(--gold-soft); } + +/* ── Status line ─────────────────────────────────────────────────────────── */ +.status { + font-size: var(--fs-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; + color: var(--muted); min-height: 1.2em; transition: color var(--t); +} +.status.error { color: var(--accent); } +.status.success { color: var(--jade); font-weight: 500; } +.status.info { color: var(--murasaki); font-weight: 500; } + +/* ════════════════════════════════════════════════════════════════════════════ + 11 · FORMS + ════════════════════════════════════════════════════════════════════════════ */ +.field { display: flex; flex-direction: column; gap: var(--sp-2); } +.field > label, .form-label { + font-size: var(--fs-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; + color: var(--muted); +} +.field .hint { font-size: var(--fs-sm); color: var(--muted); } + +input[type="text"], input[type="email"], input[type="password"], input[type="number"], +input[type="search"], input[type="url"], input[type="tel"], input[type="date"], +textarea, select, .input { + font-family: var(--font-mono); font-size: var(--fs-base); color: var(--ink); + background: var(--card); + border: var(--bw) solid var(--line); border-radius: var(--r); + padding: 0.6em 0.8em; + transition: border-color var(--t), box-shadow var(--t); + width: 100%; +} +textarea { min-height: 6em; resize: vertical; line-height: var(--lh-snug); } +input:focus, textarea:focus, select:focus, .input:focus { + outline: none; border-color: var(--ink); + box-shadow: 0 0 0 3px var(--ink-soft); +} +input::placeholder, textarea::placeholder { color: var(--muted); } +input:disabled, textarea:disabled, select:disabled { background: var(--paper-2); opacity: 0.6; cursor: not-allowed; } + +input.is-valid, textarea.is-valid { border-color: var(--jade); } +input.is-invalid, textarea.is-invalid { border-color: var(--accent); } + +select { + appearance: none; + background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%), + linear-gradient(135deg, var(--ink) 50%, transparent 50%); + background-position: calc(100% - 18px) center, calc(100% - 13px) center; + background-size: 5px 5px, 5px 5px; + background-repeat: no-repeat; + padding-right: 2.2em; +} + +/* Native checkbox/radio accent */ +input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); width: 1.05em; height: 1.05em; } +.check { display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer; font-size: var(--fs-base); } + +.input-group { display: flex; } +.input-group > :not(:first-child) { margin-left: calc(var(--bw) * -1); border-radius: 0; } +.input-group > :first-child { border-radius: var(--r) 0 0 var(--r); } +.input-group > :last-child { border-radius: 0 var(--r) var(--r) 0; } + +/* ════════════════════════════════════════════════════════════════════════════ + 12 · TABLES + ════════════════════════════════════════════════════════════════════════════ */ +.table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); } +.table th, .table td { padding: var(--sp-3) var(--sp-4); text-align: left; border-bottom: 1px solid var(--border); } +.table thead th { + font-size: var(--fs-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; + color: var(--muted); border-bottom: var(--bw-strong) solid var(--ink); font-weight: 500; +} +.table tbody tr { transition: background var(--t); } +.table-hover tbody tr:hover { background: var(--paper-2); } +.table-zebra tbody tr:nth-child(even) { background: color-mix(in srgb, var(--paper-2) 55%, transparent); } +.table td .badge { vertical-align: middle; } + +/* ════════════════════════════════════════════════════════════════════════════ + 13 · CODE BLOCKS + ════════════════════════════════════════════════════════════════════════════ */ +pre { + font-family: var(--font-mono); font-size: var(--fs-sm); line-height: var(--lh-snug); + background: var(--paper-3); color: var(--ink); + border: 1px solid var(--border); border-left: 3px solid var(--ink); + border-radius: var(--r); padding: var(--sp-4) var(--sp-5); + overflow-x: auto; +} +pre code { background: none; padding: 0; color: inherit; font-size: 1em; } + +/* ════════════════════════════════════════════════════════════════════════════ + 14 · SEAL / HANKO (signature stamp accent) + ════════════════════════════════════════════════════════════════════════════ */ +.seal { + display: inline-flex; align-items: center; justify-content: center; + width: 3.2em; height: 3.2em; padding: 0.3em; + font-family: var(--font-display); font-weight: 700; line-height: 1; + color: var(--paper); background: var(--accent); + border-radius: var(--r); + box-shadow: inset 0 0 0 2px var(--accent), inset 0 0 0 3px var(--paper); + transform: rotate(-4deg); + text-align: center; letter-spacing: 0; +} +.seal-round { border-radius: var(--r-pill); } +.seal-ink { background: var(--ink); box-shadow: inset 0 0 0 2px var(--ink), inset 0 0 0 3px var(--paper); } + +/* ── Decorative divider with center glyph ────────────────────────────────── */ +.rule { + display: flex; align-items: center; gap: var(--sp-4); + color: var(--muted); font-family: var(--font-display); +} +.rule::before, .rule::after { content: ''; flex: 1; height: 1px; background: var(--border); } + +/* ════════════════════════════════════════════════════════════════════════════ + 15 · STATS + ════════════════════════════════════════════════════════════════════════════ */ +.stat { display: flex; flex-direction: column; gap: var(--sp-1); } +.stat-num { font-family: var(--font-display); font-size: var(--fs-2xl); font-weight: 700; line-height: 1; color: var(--ink); } +.stat-label { font-size: var(--fs-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--muted); } + +/* ════════════════════════════════════════════════════════════════════════════ + 16 · OVERLAY / MODAL + ════════════════════════════════════════════════════════════════════════════ */ +.overlay { + position: fixed; inset: 0; z-index: 100; + display: none; align-items: center; justify-content: center; padding: var(--pad); + background: color-mix(in srgb, var(--paper) 92%, transparent); + backdrop-filter: blur(3px); +} +.overlay.show { display: flex; animation: washi-fade-in var(--t-slow); } +@keyframes washi-fade-in { from { opacity: 0; transform: scale(0.97); } to { opacity: 1; transform: scale(1); } } + +.modal { + background: var(--surface); border: 1px solid var(--border); + border-top: 3px solid var(--ink); + border-radius: var(--r-lg); box-shadow: var(--shadow-lg); + width: 100%; max-width: 460px; padding: var(--sp-6); text-align: center; +} +.modal .win-kanji { + font-family: var(--font-display); font-size: var(--fs-3xl); line-height: 1; color: var(--jade); + animation: washi-pop-in 0.55s cubic-bezier(0.34, 1.56, 0.64, 1); +} +@keyframes washi-pop-in { from { transform: scale(0.3) rotate(-8deg); opacity: 0; } to { transform: scale(1) rotate(0); opacity: 1; } } + +/* ════════════════════════════════════════════════════════════════════════════ + 17 · FOOTER + ════════════════════════════════════════════════════════════════════════════ */ +.site-footer { + border-top: var(--bw-strong) solid var(--ink); + padding: var(--sp-6) var(--pad); + margin-top: var(--sp-8); + display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-4); + font-size: var(--fs-sm); color: var(--muted); +} + +/* ════════════════════════════════════════════════════════════════════════════ + 18 · UTILITIES + ════════════════════════════════════════════════════════════════════════════ */ +.surface { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); } +.bordered { border: 1px solid var(--border); border-radius: var(--r); } +.shadow { box-shadow: var(--shadow); } +.shadow-lg { box-shadow: var(--shadow-lg); } +.rounded { border-radius: var(--r); } +.rounded-lg { border-radius: var(--r-lg); } + +.text-center { text-align: center; } +.text-right { text-align: right; } +.uppercase { text-transform: uppercase; letter-spacing: var(--tracking-wide); } +.full { width: 100%; } +.hidden { display: none !important; } + +.mt-0 { margin-top: 0; } .mt-2 { margin-top: var(--sp-2); } .mt-4 { margin-top: var(--sp-4); } +.mt-6 { margin-top: var(--sp-6); } .mt-8 { margin-top: var(--sp-8); } +.mb-2 { margin-bottom: var(--sp-2); } .mb-4 { margin-bottom: var(--sp-4); } .mb-6 { margin-bottom: var(--sp-6); } + +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; } +}