commit 265b1202adbbe20c7e1db1cbced88a0c50d2d28b Author: hexdev Date: Mon Aug 10 12:01:03 2026 +0700 v0.0.01b diff --git a/.design/DESIGN.md b/.design/DESIGN.md new file mode 100644 index 0000000..8b1131e --- /dev/null +++ b/.design/DESIGN.md @@ -0,0 +1,69 @@ +--- +name: "Malenia" +category: Brands +surface: web +colors: + cream: "#faf7f2" + warm-white: "#f5f0e8" + ink: "#1a1610" + ink-soft: "#3d3428" + gold: "#c9a84c" +--- + +# Malenia + +> Category: Brands + +> Surface: web + +*Свобода. Практика. Простота.* + +A minimalist, high-aesthetic brand focused on network freedom and simplicity, characterized by a luxury-leaning, archival visual language. + +## Color Palette + +| Role | Name | Hex | Usage | +| --- | --- | --- | --- | +| background | Cream | `#faf7f2` | Main page background | +| surface | Warm White | `#f5f0e8` | Secondary surfaces | +| foreground | Ink | `#1a1610` | Primary text and primary buttons | +| muted | Ink Soft | `#3d3428` | Secondary text | +| accent | Gold | `#c9a84c` | Highlights, emblems, and key accents | + +## Typography +- **Display:** Cormorant Garamond — weights 400, 700 — fallbacks: serif +- **Body:** Tenor Sans — weights 400, 700 — fallbacks: sans-serif + +## Voice & Tone + +- **Adjectives:** Sophisticated, Quiet, Essential, Free +- **Tone:** Restrained, archival, sophisticated, and minimal. + +### Messaging pillars +- Network freedom +- Practical simplicity +- Aesthetic restraint + +### Vocabulary +- **Use:** (none yet) +- **Avoid:** (none yet) + +## Imagery + +- **Style:** Geometric, symbolic, and minimalist with a focus on symmetry and gold-on-cream palettes. +- **Subjects:** Diamonds, Rings, Symmetrical emblems +- **Treatment:** Fine-line vector art, subtle noise textures, and centered compositions. +- **Avoid:** (none yet) + +## Layout + +- **Radius:** 8px +- **Border weight:** 1px +- **Spacing:** 8px baseline grid + +### Posture rules +- Extreme whitespace and centered alignment +- Strict horizontal rules for structural division +- Custom cursor interactions (dot and ring) +- Subtle grain/noise overlay for organic feel +- Fade-up animations for sequential content reveal diff --git a/.design/brand.json b/.design/brand.json new file mode 100644 index 0000000..33f19f6 --- /dev/null +++ b/.design/brand.json @@ -0,0 +1,106 @@ +{ + "name": "Malenia", + "tagline": "Свобода. Практика. Простота.", + "description": "A minimalist, high-aesthetic brand focused on network freedom and simplicity, characterized by a luxury-leaning, archival visual language.", + "sourceUrl": "https://malenia.space/", + "logo": { + "primary": "https://malenia.space/favicon.ico", + "alternates": [], + "notes": "Logotype uses Cormorant Garamond with high letter-spacing (0.35em), uppercase, and a gold accent on the 'e'." + }, + "colors": [ + { + "role": "background", + "hex": "#faf7f2", + "oklch": "", + "name": "Cream", + "usage": "Main page background" + }, + { + "role": "surface", + "hex": "#f5f0e8", + "oklch": "", + "name": "Warm White", + "usage": "Secondary surfaces" + }, + { + "role": "foreground", + "hex": "#1a1610", + "oklch": "", + "name": "Ink", + "usage": "Primary text and primary buttons" + }, + { + "role": "muted", + "hex": "#3d3428", + "oklch": "", + "name": "Ink Soft", + "usage": "Secondary text" + }, + { + "role": "accent", + "hex": "#c9a84c", + "oklch": "", + "name": "Gold", + "usage": "Highlights, emblems, and key accents" + } + ], + "typography": { + "display": { + "family": "Cormorant Garamond", + "fallbacks": [ + "serif" + ], + "weights": [], + "googleFontsUrl": "https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;1,300;1,400&display=swap" + }, + "body": { + "family": "Tenor Sans", + "fallbacks": [ + "sans-serif" + ], + "weights": [], + "googleFontsUrl": "https://fonts.googleapis.com/css2?family=Tenor+Sans&display=swap" + } + }, + "voice": { + "adjectives": [ + "Sophisticated", + "Quiet", + "Essential", + "Free" + ], + "tone": "Restrained, archival, sophisticated, and minimal.", + "messagingPillars": [ + "Network freedom", + "Practical simplicity", + "Aesthetic restraint" + ], + "vocabulary": { + "use": [], + "avoid": [] + } + }, + "imagery": { + "style": "Geometric, symbolic, and minimalist with a focus on symmetry and gold-on-cream palettes.", + "subjects": [ + "Diamonds", + "Rings", + "Symmetrical emblems" + ], + "treatment": "Fine-line vector art, subtle noise textures, and centered compositions.", + "avoid": [] + }, + "layout": { + "radius": "8px", + "borderWeight": "1px", + "spacing": "8px baseline grid", + "postureRules": [ + "Extreme whitespace and centered alignment", + "Strict horizontal rules for structural division", + "Custom cursor interactions (dot and ring)", + "Subtle grain/noise overlay for organic feel", + "Fade-up animations for sequential content reveal" + ] + } +} \ No newline at end of file diff --git a/.design/fonts/cormorant-garamond-300-italic.woff2 b/.design/fonts/cormorant-garamond-300-italic.woff2 new file mode 100644 index 0000000..ca5fbeb Binary files /dev/null and b/.design/fonts/cormorant-garamond-300-italic.woff2 differ diff --git a/.design/fonts/cormorant-garamond-300.woff2 b/.design/fonts/cormorant-garamond-300.woff2 new file mode 100644 index 0000000..7c345ae Binary files /dev/null and b/.design/fonts/cormorant-garamond-300.woff2 differ diff --git a/.design/fonts/cormorant-garamond-400-italic.woff2 b/.design/fonts/cormorant-garamond-400-italic.woff2 new file mode 100644 index 0000000..ca5fbeb Binary files /dev/null and b/.design/fonts/cormorant-garamond-400-italic.woff2 differ diff --git a/.design/fonts/cormorant-garamond-400.woff2 b/.design/fonts/cormorant-garamond-400.woff2 new file mode 100644 index 0000000..7c345ae Binary files /dev/null and b/.design/fonts/cormorant-garamond-400.woff2 differ diff --git a/.design/fonts/cormorant-garamond-600.woff2 b/.design/fonts/cormorant-garamond-600.woff2 new file mode 100644 index 0000000..7c345ae Binary files /dev/null and b/.design/fonts/cormorant-garamond-600.woff2 differ diff --git a/.design/fonts/fonts.css b/.design/fonts/fonts.css new file mode 100644 index 0000000..aac9115 --- /dev/null +++ b/.design/fonts/fonts.css @@ -0,0 +1,48 @@ +@font-face { + font-family: "Cormorant Garamond"; + src: url("./cormorant-garamond-300-italic.woff2") format("woff2"); + font-weight: 300; + font-style: italic; + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; + font-display: swap; +} +@font-face { + font-family: "Cormorant Garamond"; + src: url("./cormorant-garamond-400-italic.woff2") format("woff2"); + font-weight: 400; + font-style: italic; + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; + font-display: swap; +} +@font-face { + font-family: "Cormorant Garamond"; + src: url("./cormorant-garamond-300.woff2") format("woff2"); + font-weight: 300; + font-style: normal; + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; + font-display: swap; +} +@font-face { + font-family: "Cormorant Garamond"; + src: url("./cormorant-garamond-400.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; + font-display: swap; +} +@font-face { + font-family: "Cormorant Garamond"; + src: url("./cormorant-garamond-600.woff2") format("woff2"); + font-weight: 600; + font-style: normal; + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; + font-display: swap; +} +@font-face { + font-family: "Tenor Sans"; + src: url("./tenor-sans-400.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; + font-display: swap; +} diff --git a/.design/fonts/manifest.json b/.design/fonts/manifest.json new file mode 100644 index 0000000..ba72b3a --- /dev/null +++ b/.design/fonts/manifest.json @@ -0,0 +1,65 @@ +{ + "format": "brand-fonts/1", + "files": [ + { + "family": "Cormorant Garamond", + "weight": "300", + "style": "italic", + "file": "cormorant-garamond-300-italic.woff2", + "format": "woff2", + "sourceUrl": "https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtHmSqn7B6DxjY.woff2", + "bytes": 11556, + "unicodeRange": "U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB" + }, + { + "family": "Cormorant Garamond", + "weight": "400", + "style": "italic", + "file": "cormorant-garamond-400-italic.woff2", + "format": "woff2", + "sourceUrl": "https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtHmSqn7B6DxjY.woff2", + "bytes": 11556, + "unicodeRange": "U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB" + }, + { + "family": "Cormorant Garamond", + "weight": "300", + "style": "normal", + "file": "cormorant-garamond-300.woff2", + "format": "woff2", + "sourceUrl": "https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYpntKky2F7i6C.woff2", + "bytes": 11264, + "unicodeRange": "U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB" + }, + { + "family": "Cormorant Garamond", + "weight": "400", + "style": "normal", + "file": "cormorant-garamond-400.woff2", + "format": "woff2", + "sourceUrl": "https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYpntKky2F7i6C.woff2", + "bytes": 11264, + "unicodeRange": "U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB" + }, + { + "family": "Cormorant Garamond", + "weight": "600", + "style": "normal", + "file": "cormorant-garamond-600.woff2", + "format": "woff2", + "sourceUrl": "https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYpntKky2F7i6C.woff2", + "bytes": 11264, + "unicodeRange": "U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB" + }, + { + "family": "Tenor Sans", + "weight": "400", + "style": "normal", + "file": "tenor-sans-400.woff2", + "format": "woff2", + "sourceUrl": "https://fonts.gstatic.com/s/tenorsans/v21/bx6ANxqUneKx06UkIXISn3t4Ck-L2qM2VQ.woff2", + "bytes": 6832, + "unicodeRange": "U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF" + } + ] +} \ No newline at end of file diff --git a/.design/fonts/tenor-sans-400.woff2 b/.design/fonts/tenor-sans-400.woff2 new file mode 100644 index 0000000..c408307 Binary files /dev/null and b/.design/fonts/tenor-sans-400.woff2 differ diff --git a/.design/logos/favicon-0.ico b/.design/logos/favicon-0.ico new file mode 100644 index 0000000..05cb6fe Binary files /dev/null and b/.design/logos/favicon-0.ico differ diff --git a/.design/prefetch/material.md b/.design/prefetch/material.md new file mode 100644 index 0000000..e87784d --- /dev/null +++ b/.design/prefetch/material.md @@ -0,0 +1,44 @@ +# Brand material — https://malenia.space/ + +- site name: (unknown) +- title: Malenia — Свобода в сети +- description: (none) + +## Measured colors (frequency-ranked from the site's actual CSS) + +- `#c9a84c` ×2 — css-var:--gold selector::root; css-var:--border selector::root +- `#e8ca7a` ×1 — css-var:--gold-light selector::root +- `#8b6914` ×1 — css-var:--gold-dim selector::root +- `#f5f0e8` ×1 — css-var:--warm-white selector::root +- `#1a1610` ×1 — css-var:--ink selector::root +- `#3d3428` ×1 — css-var:--ink-soft selector::root +- `#7a6e5f` ×1 — css-var:--ink-muted selector::root +- `#faf7f2` ×1 (near-white/black) — css-var:--cream selector::root + +## Measured fonts (frequency-ranked font-family declarations) + +- Cormorant Garamond ×27 +- Tenor Sans ×5 + +@font-face families: Cormorant Garamond, Tenor Sans + +Google Fonts links: https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;1,300;1,400&family=Tenor+Sans&display=swap + +## Self-hosted webfonts (downloaded into ./fonts/) + +- "Cormorant Garamond" 300 italic — fonts/cormorant-garamond-300-italic.woff2 (woff2, 11556 bytes) +- "Cormorant Garamond" 400 italic — fonts/cormorant-garamond-400-italic.woff2 (woff2, 11556 bytes) +- "Cormorant Garamond" 300 normal — fonts/cormorant-garamond-300.woff2 (woff2, 11264 bytes) +- "Cormorant Garamond" 400 normal — fonts/cormorant-garamond-400.woff2 (woff2, 11264 bytes) +- "Cormorant Garamond" 600 normal — fonts/cormorant-garamond-600.woff2 (woff2, 11264 bytes) +- "Tenor Sans" 400 normal — fonts/tenor-sans-400.woff2 (woff2, 6832 bytes) + +These font FILES are already saved locally. In brand.json, keep each +typography `family` spelled EXACTLY as listed above so the self-hosted +@font-face declarations apply to every generated asset. + +## Logo candidates (downloaded into ./logos/) + +- logos/favicon-0.ico — favicon, 4286 bytes, from https://malenia.space/favicon.ico + +## Copy harvested from the site (for voice & tone analysis) diff --git a/.design/prefetch/page.html b/.design/prefetch/page.html new file mode 100644 index 0000000..664e96e --- /dev/null +++ b/.design/prefetch/page.html @@ -0,0 +1,94 @@ + + + + + + Malenia — Свобода в сети + + + + + + + + + +
+
+ +
+ + +
+ +
+ Свобода. Практика. Простота. +
+ + +
+ + + + + +
+

+

malenia.space

+
+ + + + + + +
+ + +
+ © 2026 Malenia + + malenia.space +
+ +
+ + + + \ No newline at end of file diff --git a/.design/prefetch/styles.css b/.design/prefetch/styles.css new file mode 100644 index 0000000..0070722 --- /dev/null +++ b/.design/prefetch/styles.css @@ -0,0 +1,531 @@ +:root { + --gold: #C9A84C; + --gold-light: #E8CA7A; + --gold-dim: #8B6914; + --cream: #FAF7F2; + --warm-white: #F5F0E8; + --ink: #1A1610; + --ink-soft: #3D3428; + --ink-muted: #7A6E5F; + --border: rgba(201,168,76,0.25); +} + +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +html { cursor: none; } + +body { + font-family: 'Tenor Sans', sans-serif; + background: var(--cream); + color: var(--ink); + min-height: 100vh; + overflow-x: hidden; + cursor: none; +} + +/* ── Custom cursor ─────────────────────────────────── */ +#cursor-dot, +#cursor-ring { + position: fixed; + top: 0; left: 0; + pointer-events: none; + z-index: 9999; + transform: translate(-50%, -50%); + transition: opacity .3s; +} +#cursor-dot { + width: 6px; height: 6px; + background: var(--gold); + border-radius: 50%; +} +#cursor-ring { + width: 32px; height: 32px; + border: 1px solid var(--gold); + border-radius: 50%; + transition: width .25s cubic-bezier(.4,0,.2,1), + height .25s cubic-bezier(.4,0,.2,1), + opacity .3s; +} +body.hovering #cursor-ring { + width: 48px; height: 48px; + border-color: var(--gold-light); +} + +/* ── Noise overlay ─────────────────────────────────── */ +body::before { + content: ''; + position: fixed; + inset: 0; + z-index: 0; + pointer-events: none; + opacity: .035; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' 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"); + background-repeat: repeat; + background-size: 180px; +} + +/* ── Layout ────────────────────────────────────────── */ +.page { + position: relative; + z-index: 1; + min-height: 100vh; + display: grid; + grid-template-rows: auto 1fr auto; +} + +/* ── Header ────────────────────────────────────────── */ +header { + padding: 2.5rem 4rem; + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid var(--border); +} + +.logo { + font-family: 'Cormorant Garamond', serif; + font-weight: 300; + font-size: 1.5rem; + letter-spacing: .35em; + text-transform: uppercase; + color: var(--ink); + text-decoration: none; +} +.logo span { color: var(--gold); } + +.header-rule { + flex: 1; + height: 1px; + background: var(--border); + margin: 0 2rem; +} + +.header-tag { + font-size: .65rem; + letter-spacing: .25em; + text-transform: uppercase; + color: var(--ink-muted); +} + +/* ── Hero ──────────────────────────────────────────── */ +.hero { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: 6rem 2rem; + gap: 3.5rem; +} + +.emblem { + position: relative; + width: 90px; + height: 90px; + opacity: 0; + animation: fadeUp .9s .1s forwards; +} +.emblem svg { width: 100%; height: 100%; } + +.quote-block { + max-width: 640px; + opacity: 0; + animation: fadeUp .9s .25s forwards; +} + +.quote-text { + font-family: 'Cormorant Garamond', serif; + font-size: clamp(2rem, 5vw, 3.4rem); + font-weight: 300; + line-height: 1.25; + color: var(--ink); + letter-spacing: .01em; +} +.quote-text em { + font-style: italic; + color: var(--gold-dim); +} + +.quote-author { + margin-top: 1.25rem; + font-size: .7rem; + letter-spacing: .3em; + text-transform: uppercase; + color: var(--ink-muted); +} + +/* ── Divider ───────────────────────────────────────── */ +.divider { + display: flex; + align-items: center; + gap: 1rem; + width: 100%; + max-width: 480px; + opacity: 0; + animation: fadeUp .9s .4s forwards; +} +.divider::before, +.divider::after { + content: ''; + flex: 1; + height: 1px; + background: var(--border); +} +.divider-diamond { + width: 6px; height: 6px; + background: var(--gold); + transform: rotate(45deg); + flex-shrink: 0; +} + +/* ── Buttons ───────────────────────────────────────── */ +.cta-group { + display: flex; + gap: 1.25rem; + flex-wrap: wrap; + justify-content: center; + opacity: 0; + animation: fadeUp .9s .55s forwards; +} + +.btn { + position: relative; + display: inline-flex; + align-items: center; + gap: .75rem; + padding: .85rem 2rem; + font-family: 'Tenor Sans', sans-serif; + font-size: .78rem; + letter-spacing: .18em; + text-transform: uppercase; + text-decoration: none; + border-radius: 0; + cursor: none; + transition: color .25s, background .25s, border-color .25s; + overflow: hidden; +} +.btn::after { + content: ''; + position: absolute; + inset: 0; + background: var(--gold); + transform: scaleX(0); + transform-origin: left; + transition: transform .35s cubic-bezier(.4,0,.2,1); + z-index: 0; +} +.btn:hover::after { transform: scaleX(1); } +.btn > * { position: relative; z-index: 1; } + +.btn-primary { + background: var(--ink); + color: var(--cream); + border: 1px solid var(--ink); +} +.btn-primary:hover { color: var(--ink); border-color: var(--gold); } + +.btn-secondary { + background: transparent; + color: var(--ink); + border: 1px solid var(--gold); +} +.btn-secondary::after { background: var(--ink); } +.btn-secondary:hover { color: var(--cream); } + +.btn-icon { + width: 18px; height: 18px; + fill: currentColor; + flex-shrink: 0; +} + +/* ── Footer ────────────────────────────────────────── */ +footer { + padding: 2rem 4rem; + border-top: 1px solid var(--border); + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + flex-wrap: wrap; +} +.footer-copy { + font-size: .65rem; + letter-spacing: .2em; + text-transform: uppercase; + color: var(--ink-muted); +} +.footer-dot { + width: 4px; height: 4px; + background: var(--gold); + border-radius: 50%; +} + +/* ── Animations ────────────────────────────────────── */ +@keyframes fadeUp { + from { opacity: 0; transform: translateY(22px); } + to { opacity: 1; transform: translateY(0); } +} + +/* ── Responsive ────────────────────────────────────── */ +@media (max-width: 640px) { + header { padding: 1.75rem 1.5rem; } + .header-rule { display: none; } + .header-tag { display: none; } + .hero { padding: 4rem 1.5rem; gap: 2.5rem; } + footer { padding: 1.5rem; flex-direction: column; align-items: flex-start; } + .btn { padding: .8rem 1.5rem; font-size: .72rem; } + .cta-group { flex-direction: column; align-items: stretch; } + .btn { justify-content: center; } +} +/* cyrillic-ext */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtFmSqn7B6DxjY.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtMmSqn7B6DxjY.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtHmSqn7B6DxjY.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtGmSqn7B6DxjY.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtImSqn7B6D.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtFmSqn7B6DxjY.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtMmSqn7B6DxjY.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtHmSqn7B6DxjY.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtGmSqn7B6DxjY.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3ZmX5slCNuHLi8bLeY9MK7whWMhyjYrEtImSqn7B6D.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYpHtKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYrXtKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYpntKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYp3tKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYqXtKky2F7g.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYpHtKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYrXtKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYpntKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYp3tKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYqXtKky2F7g.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYpHtKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYrXtKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYpntKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYp3tKky2F7i6C.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Cormorant Garamond'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/cormorantgaramond/v21/co3bmX5slCNuHLi8bLeY9MK7whWMhyjYqXtKky2F7g.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic */ +@font-face { + font-family: 'Tenor Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/tenorsans/v21/bx6ANxqUneKx06UkIXISn3F4Ck-L2qM2VQ.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* latin-ext */ +@font-face { + font-family: 'Tenor Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/tenorsans/v21/bx6ANxqUneKx06UkIXISn3t4Ck-L2qM2VQ.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Tenor Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/tenorsans/v21/bx6ANxqUneKx06UkIXISn3V4Ck-L2qM.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/.design/system/BRAND-SYSTEM.md b/.design/system/BRAND-SYSTEM.md new file mode 100644 index 0000000..5bcc604 --- /dev/null +++ b/.design/system/BRAND-SYSTEM.md @@ -0,0 +1,53 @@ +# Malenia — brand system + +Generated by the branding-agent engine from a single **seed** (20 fields). +Everything below is *derived* — no token here was hand-authored. + +- **slug:** `malenia` +- **source:** https://malenia.space/ +- **primary seed color:** `#c9a84c` +- **derived tokens per theme:** 218 +- **themes:** default · dark · compact (same seed, different algorithm) + +## Files + +| Path | What it is | +| --- | --- | +| `seed.json` | Generated snapshot of the effective seed; persistent overrides live in `brand.json.seed`. | +| `tokens.default.json` | Full derived DesignTokens (light). | +| `tokens.dark.json` | Same seed, dark algorithm. | +| `tokens.compact.json` | Same seed, compact (dense) algorithm. | +| `variables.css` | `:root{}` + `.dark{}` CSS custom properties (`--brand-*`). | +| `variables.dark.css` | Standalone `:root{}` for the dark theme. | +| `theme.json` | antd `ConfigProvider` theme (token + algorithm). | +| `kit.html` | Themed component showcase (light). | +| `kit.dark.html` | Themed component showcase (dark). | +| `artifacts/landing.html` | Full landing page (hero → features → pricing → FAQ → CTA). | +| `artifacts/deck.html` | 9-slide 16:9 pitch deck with keyboard navigation. | +| `artifacts/poster.html` | 3:4 print-style poster. | +| `artifacts/email.html` | A marketing email. | +| `artifacts/newsletter.html` | Multi-story digest email. | +| `artifacts/form.html` | Split-screen contact / signup page. | +| `index.html` | Gallery linking everything + live component preview. | + +## How to re-theme + +The whole system is regenerated from `brand.json` and optional +`brand.json.seed` overrides. Persist authored overrides there, then run +`od brand finalize ` — every downstream token, component and artifact +follows. Do not edit `system/seed.json` directly; finalize replaces it. + +- **Change the brand color:** edit the accent role or `seed.colorPrimary` in `brand.json`. + The 10-step palette, all interaction states, the primary background/border and + every component that references `var(--brand-color-primary)` update together. +- **Light → dark:** the dark theme is the same seed run through the `"dark"` + algorithm — load `variables.dark.css` (or add the `.dark` class). +- **Density:** the `"compact"` algorithm tightens spacing & control heights + while keeping colors identical. + +## Add a new artifact type + +`renderArtifact(kind, brand, tokens)` already accepts every `AssetKind` +(`landing | deck | poster | email | newsletter | form`). Add the kind to the +build's artifact list to ship it in the bundle; kinds without a bespoke layout +fall back to a sensible card+button page. diff --git a/.design/system/artifacts/deck.html b/.design/system/artifacts/deck.html new file mode 100644 index 0000000..2172915 --- /dev/null +++ b/.design/system/artifacts/deck.html @@ -0,0 +1,782 @@ + + + + + + + Malenia — Pitch deck + + + + + + + +
+
+
+
MaleniaSOPHISTICATED · QUIET · ESSENTIAL
+
+
+ Sophisticated · Quiet · Essential +

Malenia

+

Свобода. Практика. Простота.

+
+
+
malenia.space01 / 11
+
+
+
+
+
MaleniaTHE PROBLEM
+
+
+ The problem +

Getting this category right is still painfully hard.

+

A minimalist, high-aesthetic brand focused on network freedom and simplicity, characterized by a luxury-leaning, archival visual language.

+
+

Tools don't talk

Work scatters across apps that never share a source of truth, so context is lost on every handoff.

+

Every loop costs a day

Iteration stalls in coordination — approvals, exports, re-dos — long before anything ships.

+

Quality is a coin flip

Output depends on whoever happened to do the work, not on a standard you can rely on.

+
+
+
+
malenia.space02 / 11
+
+
+
+
+
MaleniaTHE SOLUTION
+
+
+ The solution +

Malenia is how teams get свобода. Практика. Простота

+
+ Network freedom + Practical simplicity + Aesthetic restraint +
+
+
+
malenia.space03 / 11
+
+
+
+
+
MaleniaWHY NOW
+
+
+ Why now +

The shift toward sophisticated, accountable this category is happening now — and the teams that move first set the standard.

+ +
+
+
malenia.space04 / 11
+
+
+
+
+
MaleniaMARKET
+
+
+ Market +

The opportunity is large and still wide open.

+
+
TAM +
+ $48B total market
+
SAM +
+ $12B reachable today
+
SOM +
+ $1.4B near-term wedge
+
+
+
+
malenia.space05 / 11
+
+
+
+
+
MaleniaPRODUCT
+
+
+ Product +

Malenia is real, shipping, and good to use today.

+
+
+
+ +
+
+
+
+
+
malenia.space06 / 11
+
+
+
+
+
MaleniaBUSINESS MODEL
+
+
+ Business model +

We make money the moment we create value.

+
+
+

Starter

+
$0 / mo
+

Up to 3 projects · Network freedom · Community support

+
+
+

Pro

+
$29 / mo
+

Unlimited projects · Practical simplicity · Aesthetic restraint

+
+
+

Enterprise

+
Custom
+

SSO & audit logs · Dedicated success manager · Custom contracts & SLA

+
+
+
+
+
malenia.space07 / 11
+
+
+
+
+
MaleniaCOMPETITION & MOAT
+
+
+ Competition & moat +

Only Malenia is built sophisticated from the ground up.

+
+
+ Built for teamsFast to valueOn-brand by default +
+
+ Fieldnote + +
+
+ Arcadia + +
+
+ Malenia + +
+
+
+
+
malenia.space08 / 11
+
+
+
+
+
MaleniaTRACTION
+
+
+ Traction +

People already want this — and the line is going up.

+
+
10k+
Teams onboard
+
99.9%
Uptime SLA
+
4.9/5
Average rating
+
120+
Integrations
+
+

Illustrative figures — replace with your live numbers before pitching.

+
+
+
malenia.space09 / 11
+
+
+
+
+
MaleniaTEAM
+
+
+ Team +

The people behind Malenia have done this before.

+
+
+ MC +

Maya Chen

+

Head of Design, Northwind

+
+
+ JW +

Jonas Weber

+

Engineering Lead, Lumen Labs

+
+
+ PN +

Priya Natarajan

+

Founder, Fieldnote

+
+
+
+
+
malenia.space10 / 11
+
+
+
+
+
MaleniaTHE ASK
+
+
+ The ask +

Let's build the future of this category together.

+
+
Partner with us — back the team building the sophisticated standard for this market.
+
Fuel the next phase — scale the product, the go-to-market motion, and the team.
+
Hit the milestone — reach the next tier of customers and revenue within 12 months.
+
+ Talk to us · malenia.space +
+
+
malenia.space11 / 11
+
+
+
+
+
+ + 1 / 11 + +
+ + + \ No newline at end of file diff --git a/.design/system/artifacts/email.html b/.design/system/artifacts/email.html new file mode 100644 index 0000000..fffe109 --- /dev/null +++ b/.design/system/artifacts/email.html @@ -0,0 +1,439 @@ + + + + + + + Свобода. Практика. Простота — from Malenia + + + + + + + + +
A minimalist, high-aesthetic brand focused on network freedom and simplicity, characterized by a luxury-leaning, archival visual language.
+ +
͏‌ ͏‌ ͏‌ ͏‌ ͏‌ ͏‌ ͏‌ 
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Malenia +
+

Sophisticated

+

Свобода. Практика. Простота.

+

A minimalist, high-aesthetic brand focused on network freedom and simplicity, characterized by a luxury-leaning, archival visual language.

+ + + + + +
+ Get started with Malenia +
+
+

Hi there,

+

Here is what Malenia gives your team from the first day — no migration project, no setup tax:

+ + + + + + + + + + + + + + +
+

Network freedom

+

Network freedom is built into Malenia from day one — not bolted on later.

+
+

Practical simplicity

+

Practical simplicity is built into Malenia from day one — not bolted on later.

+
+

Aesthetic restraint

+

Aesthetic restraint is built into Malenia from day one — not bolted on later.

+
+
+ + + + +
+

“Malenia is the first tool here that actually feels Sophisticated. It was part of our daily flow inside a week.”

+

Maya Chen · Head of Design, Northwind

+
+
+ + + + +
+ Get started with Malenia +
+

Questions? Just reply to this email — a real person reads every message.

+
+

You are receiving this because you signed up to hear from Malenia.

+

Update preferences  ·  Unsubscribe

+

Malenia · 100 Market Street, Suite 200 · malenia.space

+
+
+ + + \ No newline at end of file diff --git a/.design/system/artifacts/form.html b/.design/system/artifacts/form.html new file mode 100644 index 0000000..aa1077a --- /dev/null +++ b/.design/system/artifacts/form.html @@ -0,0 +1,442 @@ + + + + + + + Malenia — Get started + + + + + + + +
+
+ +
+
+ + + + Malenia +
+
+

Свобода. Практика. Простота.

+

A minimalist, high-aesthetic brand focused on network freedom and simplicity, characterized by a luxury-leaning, archival visual language.

+
  • + + Network freedom +
  • + + Practical simplicity +
  • + + Aesthetic restraint +
+
+
+ + Restrained, archival, sophisticated, and minimal. +
+
+
+
+
+

Tell us where to start

+

A couple of details and Malenia takes it from there — no account needed yet.

+
+ +
+
+
+
+
+ + + + +
+
+ + + + +
+
+
+ + +

That doesn't look like an email yet — try name@company.com.

+

We'll send your next steps here.

+
+
+ + +

Pick the closest — you can change direction later.

+
+
+ + + +
+ +
+
+ +

+ + No spam, ever. Unsubscribe in one click — your data stays yours. +

+
+
+ +
+ +
+ Свобода. Практика. Простота + malenia.space +
+
+
+
+ + + \ No newline at end of file diff --git a/.design/system/artifacts/landing.html b/.design/system/artifacts/landing.html new file mode 100644 index 0000000..43dc6ee --- /dev/null +++ b/.design/system/artifacts/landing.html @@ -0,0 +1,822 @@ + + + + + + + Malenia — Свобода. Практика. Простота. + + + + + + + +
+
+ Malenia + +
+ Sign in + Get started free +
+
+
+ + +
+
+
+ Sophisticated · Quiet · Essential +

Свобода. Практика. Простота.

+

A minimalist, high-aesthetic brand focused on network freedom and simplicity, characterized by a luxury-leaning, archival visual language.

+ +

Free plan · No credit card · 2-minute setup

+
+
+
+
+ + + + malenia.space +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+ ★★★★★ + Rated 4.9/5 by 12,000+ teams +
+

Trusted by teams at

+
+ Northwind + Lumen Labs + Fieldnote + Arcadia + Helios +
+
+ + +
+
+
+ The problem +

You're not slow. Your setup is.

+

Sound familiar? The longer it goes unfixed, the more it quietly taxes everything Malenia is supposed to make easy.

+
+
+
+
+ +
+

Every deliverable starts from scratch

+

So the same work gets redone, the backlog grows, and shipping slips by days.

+
+
+
+
+
+ +
+

The tools don't talk to each other

+

Context lives in five tabs, hand-offs break, and nobody trusts the source of truth.

+
+
+
+
+
+ +
+

Quality drifts as you scale

+

What looked sharp at ten people looks inconsistent at fifty — and customers notice.

+
+
+
+
+
+
+ + +
+
+
+ Why Malenia +

Here's how that changes

+

Three ways Malenia turns the daily grind into something you actually look forward to.

+
+
+
+
+

Network freedom

+

Sophisticated by design — and built into every surface Malenia ships.

+
+
+
+

Practical simplicity

+

Quiet by design — and built into every surface Malenia ships.

+
+
+
+

Aesthetic restraint

+

Essential by design — and built into every surface Malenia ships.

+
+
+
+
+ + +
+
+
+ How it works +

Up and running in three steps

+

No migration project. No six-week rollout.

+
+
+
+
+
+
+ 1 +

Connect

+
+

Point Malenia at what you already have — no rebuild required.

+
+
+
+
+
+
+ 2 +

Make it yours

+
+

Adjust the defaults until they fit the way your team works.

+
+
+
+
+
+
+ 3 +

Launch

+
+

Go live with confidence, then iterate from real feedback.

+
+
+
+
+
+ + +
+
+
+

See it on your own work in minutes

+

Free plan · No credit card · 2-minute setup

+
+ Get started free +
+
+ + +
+
+
+ A closer look +

Built for the way real teams work

+

Every capability earns its place — and translates to something you can feel.

+
+
+ Capability 01 +

Secure from day one

+

SSO, audit logs and granular permissions are built in, not bolted on.

+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Capability 02 +

Works where you work

+

Integrates with the tools your team already relies on every day.

+ +
+
+ Capability 03 +

Insight you can act on

+

Reporting that reads like a story, not a spreadsheet.

+ +
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
10k+
+
Teams onboard
+
+
+
99.9%
+
Uptime SLA
+
+
+
4.9/5
+
Average rating
+
+
+
120+
+
Integrations
+
+
+
+ +
+
+
+ Proof +

Loved by the teams who use it daily

+

Real results, in their words — not ours.

+
+
+

“Malenia is the first tool in this space that actually feels Sophisticated. It became part of our daily flow within a week.”

+
+ MC +
+
Maya Chen
+
Head of Design, Northwind
+
+
+

“We were skeptical, then we shipped our first project — genuinely Quiet — in a single afternoon. The team never looked back.”

+
+ JW +
+
Jonas Weber
+
Engineering Lead, Lumen Labs
+
+
+

“The quality bar out of the box is what sold us. Свобода. Практика. Простота is not just a slogan here.”

+
+ PN +
+
Priya Natarajan
+
Founder, Fieldnote
+
+
+
+
+
+ + +
+
+
+ Before you ask +

Your questions, answered

+ +
+
+ What is Malenia?+ +
A minimalist, high-aesthetic brand focused on network freedom and simplicity, characterized by a luxury-leaning, archival visual language.
+
+
+ How long does it take to get started?+ +
Most teams are up and running in under an hour. There is nothing to install and no migration to plan — connect, customize, launch.
+
+
+ Can I try it before committing?+ +
Yes. Start on the free plan, invite your team, and upgrade only when you need more. No credit card required.
+
+
+ How does pricing work?+ +
Plans scale with your team. Start free, move to Pro when you need unlimited usage, and talk to us about Enterprise for custom needs.
+
+
+ What about security and privacy?+ +
Your data stays yours. Access is encrypted in transit and at rest, and granular permissions keep the right things with the right people.
+
+
+
+ + +
+
+
+ Pricing +

Plans that scale with you

+

Start free. Upgrade only when it earns it.

+
+
+
+
+ Starter + +
+

For trying things out.

+
+ $0 + / mo +
+
  • ✓Up to 3 projects
  • ✓Network freedom
  • ✓Community support
+ +
+
+
+ Pro + Most popular +
+

For growing teams.

+
+ $29 + / mo +
+
  • ✓Unlimited projects
  • ✓Practical simplicity
  • ✓Aesthetic restraint
  • ✓Priority support
+ +
+
+
+ Enterprise + +
+

For organizations at scale.

+
+ Custom + +
+
  • ✓SSO & audit logs
  • ✓Dedicated success manager
  • ✓Custom contracts & SLA
+ +
+
+

All prices in USD · Cancel anytime · No credit card to start.

+
+
+
+ + +
+
+
+
+
+

Start building with Malenia today

+

Свобода. Практика. Простота.

+ +

2-minute setup · Cancel anytime

+
+
+
+ + + + + + \ No newline at end of file diff --git a/.design/system/artifacts/newsletter.html b/.design/system/artifacts/newsletter.html new file mode 100644 index 0000000..fdfd0f5 --- /dev/null +++ b/.design/system/artifacts/newsletter.html @@ -0,0 +1,427 @@ + + + + + + + Malenia — Newsletter + + + + + + + +
+
+ +
Свобода. Практика. Простота.
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
Malenia
+
Sophisticated reads · Issue 01
+
+

In this issue

+

Network freedom

+

A minimalist, high-aesthetic brand focused on network freedom and simplicity, characterized by a luxury-leaning, archival visual language.

+
+ + +
Read this issue
+
+ + + + + +
+
01
+
+
+

Network freedom

+

Sophisticated by design — and built into every surface Malenia ships.

+ Read the full story → +
+
+ + + + + +
+
02
+
+
+

Practical simplicity

+

Quiet by design — and built into every surface Malenia ships.

+ See how it works → +
+
+ + + + + +
+
03
+
+
+

Aesthetic restraint

+

Essential by design — and built into every surface Malenia ships.

+ Get the details → +
+
+

That's the issue. Malenia lands in your inbox next week.

+ + +
Read this issue
+
+
+

You're receiving this because you follow Malenia.

+

View in browser  ·  Preferences  ·  Unsubscribe

+

© Malenia · malenia.space

+
+
+
+ + + \ No newline at end of file diff --git a/.design/system/artifacts/poster.html b/.design/system/artifacts/poster.html new file mode 100644 index 0000000..8402bb0 --- /dev/null +++ b/.design/system/artifacts/poster.html @@ -0,0 +1,434 @@ + + + + + + + Malenia — Poster + + + + + + + +
+
+
+ Malenia + malenia.space +
+ +
+

SOPHISTICATED · QUIET · ESSENTIAL

+

Свобода. Практика. Простота.

+
+

A minimalist, high-aesthetic brand focused on network freedom and simplicity, characterized by a luxury-leaning, archival visual language.

+
+ +
+ + + Malenia + + Sophisticated · Quiet +
+
+
+ + + \ No newline at end of file diff --git a/.design/system/index.html b/.design/system/index.html new file mode 100644 index 0000000..9a20718 --- /dev/null +++ b/.design/system/index.html @@ -0,0 +1,3769 @@ + + + + + + + Malenia — Artifacts + + + + + + + + +
+

Files in this brand system

+ +

slug: malenia · everything derived from seed.json

+
+
+

Malenia

+

Свобода. Практика. Простота.

+
+
+
+
landing
+
+ +
+
+
+
deck
+
+ +
+
+
+
poster
+
+ +
+
+
+
email
+
+ +
+
+
+
newsletter
+
+ +
+
+
+
form
+
+ +
+
+
+ + + \ No newline at end of file diff --git a/.design/system/kit.dark.html b/.design/system/kit.dark.html new file mode 100644 index 0000000..c6b2968 --- /dev/null +++ b/.design/system/kit.dark.html @@ -0,0 +1,587 @@ + + + + + + +Malenia — component kit (dark) + + + + + + + +
+
+
Malenia · dark theme
+

Malenia — component kit (dark)

+

Every component below is colored only by var(--brand-*) custom properties derived from one seed.

+
+ +
+

Buttons

+

Five types across three sizes.

+ +
+ Small + Medium + Large +
+
+
+

Form controls

+

Inputs, selects, textareas, checkboxes and switches share control height, radius and focus ring.

+
+
+
+
+
+
+
+ + + Notifications + Public profile +
+
+
+

Navigation

+

Tabs, breadcrumbs, pagination and steps for app shells and flows.

+
OverviewAnalyticsReportsSettings
+
+ +
‹12345›
+
+
+
✓
Connect
Point at a source
2
Derive
Seed to tokens
3
Ship
Export everywhere
+
+
+
+

Cards

+

Elevated content surfaces with optional header & footer.

+
+
Overview
Cards group related content on an elevated surface. Radius, border and shadow all read from the derived tokens.
+
Usage
Drop the same component into a dark or compact theme and it re-skins automatically — no per-variant markup.
+
A bodyonly card. live beta
+
+
+
+

Data display

+

Tables, stats, avatars and a no-JS accordion for structured content.

+
TokenRoleValue
colorPrimaryBrand accentseed
fontSizeBody type basederived
borderRadiusCorner roundingderived
+
+
+
10k+
+
Teams onboard
+
+
+
99.9%
+
Uptime SLA
+
+
+
4.9/5
+
Average rating
+
+
+
+ M + AL + TB + design ops +
+
+
+ What is a seed token?+ +
The ~20-field input every other token is derived from. Change one field and the whole system follows.
+
+
+ Can I theme dark mode separately?+ +
No need — dark is the same seed run through a different algorithm, so it can never drift from the light theme.
+
+
+
+
+

Marketing blocks

+

Testimonials and pricing compose the primitives — landing pages are these in the right order.

+
+

“We replaced three hand-maintained style guides with one generated system.”

+
+ AL +
+
Ada Lovelace
+
Design lead
+
+
+
+
+ Pro + Most popular +
+

For growing teams.

+
+ $29 + / mo +
+
  • ✓Unlimited brands
  • ✓Dark & compact themes
  • ✓Priority support
+ +
+
Composable
Marketing blocks (testimonials, pricing, stats) compose the same primitives — so a landing page is just kit pieces in the right order.
+
+
+
+

Tags

+

Compact labels keyed to functional colors.

+
+ Primary + Success + Warning + Error + Info +
+
+
+

Alerts & progress

+

Semantic feedback states.

+
+
✓
Brand system generated
All design tokens were derived from a single seed color.
+
ℹ
Tokens map 1:1 onto CSS custom properties.
+
⚠
Wireframe mode is off
Filled surfaces are in use for this theme.
+
✕
Could not reach the source URL.
+
+
+
+
+ 72% +
+
+
+ ✓ +
+
+
+
+

Color

+

The full derived palette and neutrals.

+
+
Primary palette
+
+
+ 50 +
+
+ 200 +
+
+ 300 +
+
+ 400 +
+
+ 500 +
+
+ 600 +
+
+ 700 +
+
+ 800 +
+
+ 900 +
+
+ 1050 +
+
+
Functional
+
+
+ primary +
+
+ success +
+
+ warning +
+
+ error +
+
+ info +
+
+
Neutral text
+
+
+ text +
+
+ text/2 +
+
+ text/3 +
+
+ text/4 +
+
+
Surfaces & borders
+
+
+ layout +
+
+ container +
+
+ elevated +
+
+ border +
+
+ border/2 +
+
+
+
+

Type scale

+

A modular ramp derived from the base font size.

+
+ Heading 1 · 38px + The quick brown fox +
+ Heading 2 · 32px + The quick brown fox +
+ Heading 3 · 26px + The quick brown fox +
+ Heading 4 · 22px + The quick brown fox +
+ Heading 5 · 18px + The quick brown fox +
+ Large · 18px + The quick brown fox +
+ Body · 14px + The quick brown fox +
+ Small · 12px + The quick brown fox +
+
+
+ + \ No newline at end of file diff --git a/.design/system/kit.html b/.design/system/kit.html new file mode 100644 index 0000000..2798746 --- /dev/null +++ b/.design/system/kit.html @@ -0,0 +1,587 @@ + + + + + + +Malenia — component kit + + + + + + + +
+
+
Malenia · default theme
+

Malenia — component kit

+

Every component below is colored only by var(--brand-*) custom properties derived from one seed.

+
+ +
+

Buttons

+

Five types across three sizes.

+ +
+ Small + Medium + Large +
+
+
+

Form controls

+

Inputs, selects, textareas, checkboxes and switches share control height, radius and focus ring.

+
+
+
+
+
+
+
+ + + Notifications + Public profile +
+
+
+

Navigation

+

Tabs, breadcrumbs, pagination and steps for app shells and flows.

+
OverviewAnalyticsReportsSettings
+
+ +
‹12345›
+
+
+
✓
Connect
Point at a source
2
Derive
Seed to tokens
3
Ship
Export everywhere
+
+
+
+

Cards

+

Elevated content surfaces with optional header & footer.

+
+
Overview
Cards group related content on an elevated surface. Radius, border and shadow all read from the derived tokens.
+
Usage
Drop the same component into a dark or compact theme and it re-skins automatically — no per-variant markup.
+
A bodyonly card. live beta
+
+
+
+

Data display

+

Tables, stats, avatars and a no-JS accordion for structured content.

+
TokenRoleValue
colorPrimaryBrand accentseed
fontSizeBody type basederived
borderRadiusCorner roundingderived
+
+
+
10k+
+
Teams onboard
+
+
+
99.9%
+
Uptime SLA
+
+
+
4.9/5
+
Average rating
+
+
+
+ M + AL + TB + design ops +
+
+
+ What is a seed token?+ +
The ~20-field input every other token is derived from. Change one field and the whole system follows.
+
+
+ Can I theme dark mode separately?+ +
No need — dark is the same seed run through a different algorithm, so it can never drift from the light theme.
+
+
+
+
+

Marketing blocks

+

Testimonials and pricing compose the primitives — landing pages are these in the right order.

+
+

“We replaced three hand-maintained style guides with one generated system.”

+
+ AL +
+
Ada Lovelace
+
Design lead
+
+
+
+
+ Pro + Most popular +
+

For growing teams.

+
+ $29 + / mo +
+
  • ✓Unlimited brands
  • ✓Dark & compact themes
  • ✓Priority support
+ +
+
Composable
Marketing blocks (testimonials, pricing, stats) compose the same primitives — so a landing page is just kit pieces in the right order.
+
+
+
+

Tags

+

Compact labels keyed to functional colors.

+
+ Primary + Success + Warning + Error + Info +
+
+
+

Alerts & progress

+

Semantic feedback states.

+
+
✓
Brand system generated
All design tokens were derived from a single seed color.
+
ℹ
Tokens map 1:1 onto CSS custom properties.
+
⚠
Wireframe mode is off
Filled surfaces are in use for this theme.
+
✕
Could not reach the source URL.
+
+
+
+
+ 72% +
+
+
+ ✓ +
+
+
+
+

Color

+

The full derived palette and neutrals.

+
+
Primary palette
+
+
+ 50 +
+
+ 200 +
+
+ 300 +
+
+ 400 +
+
+ 500 +
+
+ 600 +
+
+ 700 +
+
+ 800 +
+
+ 900 +
+
+ 1050 +
+
+
Functional
+
+
+ primary +
+
+ success +
+
+ warning +
+
+ error +
+
+ info +
+
+
Neutral text
+
+
+ text +
+
+ text/2 +
+
+ text/3 +
+
+ text/4 +
+
+
Surfaces & borders
+
+
+ layout +
+
+ container +
+
+ elevated +
+
+ border +
+
+ border/2 +
+
+
+
+

Type scale

+

A modular ramp derived from the base font size.

+
+ Heading 1 · 38px + The quick brown fox +
+ Heading 2 · 32px + The quick brown fox +
+ Heading 3 · 26px + The quick brown fox +
+ Heading 4 · 22px + The quick brown fox +
+ Heading 5 · 18px + The quick brown fox +
+ Large · 18px + The quick brown fox +
+ Body · 14px + The quick brown fox +
+ Small · 12px + The quick brown fox +
+
+
+ + \ No newline at end of file diff --git a/.design/system/scripts/apply-design-tokens.mjs b/.design/system/scripts/apply-design-tokens.mjs new file mode 100644 index 0000000..2c92238 --- /dev/null +++ b/.design/system/scripts/apply-design-tokens.mjs @@ -0,0 +1,17 @@ +#!/usr/bin/env node +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const target = process.argv[2]; +if (!target) { + console.error('Usage: node scripts/apply-design-tokens.mjs '); + process.exit(1); +} + +const here = path.dirname(fileURLToPath(import.meta.url)); +const source = path.resolve(here, '..', 'variables.css'); +const destination = path.resolve(process.cwd(), target); +fs.mkdirSync(path.dirname(destination), { recursive: true }); +fs.copyFileSync(source, destination); +console.log(`Copied design tokens to ${destination}`); diff --git a/.design/system/seed.json b/.design/system/seed.json new file mode 100644 index 0000000..da0471f --- /dev/null +++ b/.design/system/seed.json @@ -0,0 +1,22 @@ +{ + "colorPrimary": "#c9a84c", + "colorSuccess": "#52c41a", + "colorWarning": "#faad14", + "colorError": "#ff4d4f", + "colorInfo": "#c9a84c", + "colorLink": "", + "colorTextBase": "#1a1610", + "colorBgBase": "#faf7f2", + "fontFamily": "'Tenor Sans', sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + "fontFamilyCode": "'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace", + "fontSize": 14, + "borderRadius": 8, + "sizeUnit": 4, + "sizeStep": 4, + "controlHeight": 32, + "lineWidth": 1, + "motionUnit": 0.1, + "motionBase": 0, + "wireframe": false, + "motion": true +} \ No newline at end of file diff --git a/.design/system/theme.json b/.design/system/theme.json new file mode 100644 index 0000000..7c2f59b --- /dev/null +++ b/.design/system/theme.json @@ -0,0 +1,24 @@ +{ + "token": { + "colorPrimary": "#c9a84c", + "colorSuccess": "#52c41a", + "colorWarning": "#faad14", + "colorError": "#ff4d4f", + "colorInfo": "#c9a84c", + "colorTextBase": "#1a1610", + "colorBgBase": "#faf7f2", + "fontFamily": "'Tenor Sans', sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + "fontFamilyCode": "'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace", + "fontSize": 14, + "borderRadius": 8, + "sizeUnit": 4, + "sizeStep": 4, + "controlHeight": 32, + "lineWidth": 1, + "motionUnit": 0.1, + "motionBase": 0, + "wireframe": false, + "motion": true + }, + "algorithm": "default" +} \ No newline at end of file diff --git a/.design/system/tokens.compact.json b/.design/system/tokens.compact.json new file mode 100644 index 0000000..f543300 --- /dev/null +++ b/.design/system/tokens.compact.json @@ -0,0 +1,251 @@ +{ + "algorithm": "compact", + "colorPrimary": "#c9a84c", + "colorPrimaryBg": "#fffef0", + "colorPrimaryBgHover": "#fcfaed", + "colorPrimaryBorder": "#f0eace", + "colorPrimaryBorderHover": "#e3d69f", + "colorPrimaryHover": "#d6bf74", + "colorPrimaryActive": "#a38336", + "colorPrimaryText": "#573e14", + "colorSuccess": "#52c41a", + "colorSuccessBg": "#f6ffed", + "colorSuccessBorder": "#b6eb8f", + "colorSuccessHover": "#72d13d", + "colorSuccessActive": "#389e0d", + "colorWarning": "#faad14", + "colorWarningBg": "#fffbe6", + "colorWarningBorder": "#ffe58f", + "colorWarningHover": "#ffc53d", + "colorWarningActive": "#d48806", + "colorError": "#ff4d4f", + "colorErrorBg": "#fff2f0", + "colorErrorBorder": "#ffccc7", + "colorErrorHover": "#ff7875", + "colorErrorActive": "#d9363d", + "colorInfo": "#c9a84c", + "colorInfoBg": "#fffef0", + "colorInfoBorder": "#f0eace", + "colorLink": "#c9a84c", + "colorLinkHover": "#d6bf74", + "colorLinkActive": "#a38336", + "colorText": "#35312b", + "colorTextSecondary": "#68655f", + "colorTextTertiary": "#95928c", + "colorTextQuaternary": "#c2bfba", + "colorFill": "#d8d5d0", + "colorFillSecondary": "#ede9e4", + "colorFillTertiary": "#f1eee9", + "colorFillQuaternary": "#f6f3ed", + "colorBgLayout": "#f1eee9", + "colorBgContainer": "#faf7f2", + "colorBgElevated": "#faf7f2", + "colorBorder": "#d8d5d0", + "colorBorderSecondary": "#ede9e4", + "fontFamily": "'Tenor Sans', sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + "fontFamilyCode": "'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace", + "fontSize": 14, + "fontSizeSM": 12, + "fontSizeLG": 18, + "fontSizeXL": 22, + "fontSizeHeading1": 38, + "fontSizeHeading2": 32, + "fontSizeHeading3": 26, + "fontSizeHeading4": 22, + "fontSizeHeading5": 18, + "lineHeight": 1.5714285714285714, + "lineHeightHeading": 1.25, + "fontWeightStrong": 600, + "sizeXXS": 4, + "sizeXS": 8, + "sizeSM": 8, + "size": 12, + "sizeMD": 16, + "sizeLG": 16, + "sizeXL": 24, + "sizeXXL": 32, + "borderRadiusXS": 3, + "borderRadiusSM": 5, + "borderRadius": 8, + "borderRadiusLG": 10, + "lineWidth": 1, + "controlHeightXS": 14, + "controlHeightSM": 21, + "controlHeight": 28, + "controlHeightLG": 35, + "motionDurationFast": "0.1s", + "motionDurationMid": "0.2s", + "motionDurationSlow": "0.3s", + "motionEaseInOut": "cubic-bezier(0.645, 0.045, 0.355, 1)", + "motionEaseOut": "cubic-bezier(0.215, 0.61, 0.355, 1)", + "primaryPalette": [ + "#fffef0", + "#fcfaed", + "#f0eace", + "#e3d69f", + "#d6bf74", + "#c9a84c", + "#a38336", + "#7d5f23", + "#573e14", + "#30210b" + ], + "presets": { + "red": [ + "#fff1f0", + "#ffcbc7", + "#ffa39e", + "#ff7775", + "#ff4d50", + "#f5222d", + "#cf1323", + "#a8071a", + "#820014", + "#5c0011" + ], + "volcano": [ + "#fff2e8", + "#ffd8bf", + "#ffbb96", + "#ff9c6e", + "#ff7a45", + "#fa541c", + "#d4380d", + "#ad2202", + "#871500", + "#610c00" + ], + "orange": [ + "#fff7e6", + "#ffe7ba", + "#ffd591", + "#ffc069", + "#ffa940", + "#fa8c16", + "#d46b08", + "#ad4e00", + "#873800", + "#612500" + ], + "gold": [ + "#fffbe6", + "#fff1b8", + "#ffe58f", + "#ffd666", + "#ffc53d", + "#faad14", + "#d48806", + "#ad6800", + "#874c00", + "#613400" + ], + "yellow": [ + "#feffe6", + "#ffffb8", + "#fffb8f", + "#fff566", + "#ffeb3d", + "#fadb14", + "#d4b106", + "#ad8a00", + "#876700", + "#614700" + ], + "lime": [ + "#fcffe6", + "#f4ffb8", + "#eaff8f", + "#d3f261", + "#bae637", + "#a0d911", + "#7bb305", + "#5b8c00", + "#3f6600", + "#254000" + ], + "green": [ + "#f6ffed", + "#d9f7be", + "#b6eb8f", + "#94de64", + "#72d13d", + "#52c41a", + "#389e0d", + "#227804", + "#135200", + "#092b00" + ], + "cyan": [ + "#e6fffb", + "#b5f5ec", + "#87e8de", + "#5cdbd3", + "#36cfc9", + "#13c2c2", + "#08979c", + "#006d75", + "#00474f", + "#002329" + ], + "blue": [ + "#e6f4ff", + "#bae0ff", + "#91caff", + "#69b1ff", + "#4096ff", + "#1677ff", + "#0958d9", + "#003eb3", + "#002c8c", + "#001d66" + ], + "geekblue": [ + "#f0f5ff", + "#d6e4ff", + "#adc6ff", + "#85a5ff", + "#597df7", + "#2f54eb", + "#1d39c4", + "#10229e", + "#061178", + "#030852" + ], + "purple": [ + "#f9f0ff", + "#efdbff", + "#d4adf7", + "#b37feb", + "#9254de", + "#722ed1", + "#531dab", + "#391085", + "#22075e", + "#120338" + ], + "magenta": [ + "#fff0f6", + "#ffd6e7", + "#ffadd2", + "#ff85bf", + "#f759aa", + "#eb2f96", + "#c41d7e", + "#9e1067", + "#780650", + "#520339" + ], + "grey": [ + "#a6a6a6", + "#999999", + "#8c8c8c", + "#808080", + "#737373", + "#666666", + "#404040", + "#1a1a1a", + "#000000", + "#000000" + ] + } +} \ No newline at end of file diff --git a/.design/system/tokens.dark.json b/.design/system/tokens.dark.json new file mode 100644 index 0000000..3f58e1c --- /dev/null +++ b/.design/system/tokens.dark.json @@ -0,0 +1,251 @@ +{ + "algorithm": "dark", + "colorPrimary": "#b9a566", + "colorPrimaryBg": "#292519", + "colorPrimaryBgHover": "#413922", + "colorPrimaryBorder": "#4e4731", + "colorPrimaryBorderHover": "#6b613f", + "colorPrimaryHover": "#cec391", + "colorPrimaryActive": "#928352", + "colorPrimaryText": "#f5f3e6", + "colorSuccess": "#64b537", + "colorSuccessBg": "#192913", + "colorSuccessBorder": "#304d20", + "colorSuccessHover": "#87ca5c", + "colorSuccessActive": "#518f2f", + "colorWarning": "#dcaa37", + "colorWarningBg": "#312512", + "colorWarningBorder": "#5b4920", + "colorWarningHover": "#e8c35e", + "colorWarningActive": "#ad872f", + "colorError": "#dc6966", + "colorErrorBg": "#32191a", + "colorErrorBorder": "#5b3231", + "colorErrorHover": "#e89590", + "colorErrorActive": "#ad5553", + "colorInfo": "#b9a566", + "colorInfoBg": "#292519", + "colorInfoBorder": "#4e4731", + "colorLink": "#b9a566", + "colorLinkHover": "#cec391", + "colorLinkActive": "#928352", + "colorText": "#dcdcdc", + "colorTextSecondary": "#adadad", + "colorTextTertiary": "#7e7e7e", + "colorTextQuaternary": "#4f4f4f", + "colorFill": "#3e3e3e", + "colorFillSecondary": "#303030", + "colorFillTertiary": "#272727", + "colorFillQuaternary": "#1d1d1d", + "colorBgLayout": "#1d1d1d", + "colorBgContainer": "#141414", + "colorBgElevated": "#272727", + "colorBorder": "#3e3e3e", + "colorBorderSecondary": "#303030", + "fontFamily": "'Tenor Sans', sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + "fontFamilyCode": "'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace", + "fontSize": 14, + "fontSizeSM": 12, + "fontSizeLG": 18, + "fontSizeXL": 22, + "fontSizeHeading1": 38, + "fontSizeHeading2": 32, + "fontSizeHeading3": 26, + "fontSizeHeading4": 22, + "fontSizeHeading5": 18, + "lineHeight": 1.5714285714285714, + "lineHeightHeading": 1.25, + "fontWeightStrong": 600, + "sizeXXS": 4, + "sizeXS": 8, + "sizeSM": 12, + "size": 16, + "sizeMD": 20, + "sizeLG": 24, + "sizeXL": 32, + "sizeXXL": 48, + "borderRadiusXS": 3, + "borderRadiusSM": 5, + "borderRadius": 8, + "borderRadiusLG": 10, + "lineWidth": 1, + "controlHeightXS": 16, + "controlHeightSM": 24, + "controlHeight": 32, + "controlHeightLG": 40, + "motionDurationFast": "0.1s", + "motionDurationMid": "0.2s", + "motionDurationSlow": "0.3s", + "motionEaseInOut": "cubic-bezier(0.645, 0.045, 0.355, 1)", + "motionEaseOut": "cubic-bezier(0.215, 0.61, 0.355, 1)", + "primaryPalette": [ + "#292519", + "#413922", + "#4e4731", + "#6b613f", + "#928352", + "#b9a566", + "#cec391", + "#e5dfc5", + "#f5f3e6", + "#faf9ec" + ], + "presets": { + "red": [ + "#fff1f0", + "#ffcbc7", + "#ffa39e", + "#ff7775", + "#ff4d50", + "#f5222d", + "#cf1323", + "#a8071a", + "#820014", + "#5c0011" + ], + "volcano": [ + "#fff2e8", + "#ffd8bf", + "#ffbb96", + "#ff9c6e", + "#ff7a45", + "#fa541c", + "#d4380d", + "#ad2202", + "#871500", + "#610c00" + ], + "orange": [ + "#fff7e6", + "#ffe7ba", + "#ffd591", + "#ffc069", + "#ffa940", + "#fa8c16", + "#d46b08", + "#ad4e00", + "#873800", + "#612500" + ], + "gold": [ + "#fffbe6", + "#fff1b8", + "#ffe58f", + "#ffd666", + "#ffc53d", + "#faad14", + "#d48806", + "#ad6800", + "#874c00", + "#613400" + ], + "yellow": [ + "#feffe6", + "#ffffb8", + "#fffb8f", + "#fff566", + "#ffeb3d", + "#fadb14", + "#d4b106", + "#ad8a00", + "#876700", + "#614700" + ], + "lime": [ + "#fcffe6", + "#f4ffb8", + "#eaff8f", + "#d3f261", + "#bae637", + "#a0d911", + "#7bb305", + "#5b8c00", + "#3f6600", + "#254000" + ], + "green": [ + "#f6ffed", + "#d9f7be", + "#b6eb8f", + "#94de64", + "#72d13d", + "#52c41a", + "#389e0d", + "#227804", + "#135200", + "#092b00" + ], + "cyan": [ + "#e6fffb", + "#b5f5ec", + "#87e8de", + "#5cdbd3", + "#36cfc9", + "#13c2c2", + "#08979c", + "#006d75", + "#00474f", + "#002329" + ], + "blue": [ + "#e6f4ff", + "#bae0ff", + "#91caff", + "#69b1ff", + "#4096ff", + "#1677ff", + "#0958d9", + "#003eb3", + "#002c8c", + "#001d66" + ], + "geekblue": [ + "#f0f5ff", + "#d6e4ff", + "#adc6ff", + "#85a5ff", + "#597df7", + "#2f54eb", + "#1d39c4", + "#10229e", + "#061178", + "#030852" + ], + "purple": [ + "#f9f0ff", + "#efdbff", + "#d4adf7", + "#b37feb", + "#9254de", + "#722ed1", + "#531dab", + "#391085", + "#22075e", + "#120338" + ], + "magenta": [ + "#fff0f6", + "#ffd6e7", + "#ffadd2", + "#ff85bf", + "#f759aa", + "#eb2f96", + "#c41d7e", + "#9e1067", + "#780650", + "#520339" + ], + "grey": [ + "#a6a6a6", + "#999999", + "#8c8c8c", + "#808080", + "#737373", + "#666666", + "#404040", + "#1a1a1a", + "#000000", + "#000000" + ] + } +} \ No newline at end of file diff --git a/.design/system/tokens.default.json b/.design/system/tokens.default.json new file mode 100644 index 0000000..add9285 --- /dev/null +++ b/.design/system/tokens.default.json @@ -0,0 +1,251 @@ +{ + "algorithm": "default", + "colorPrimary": "#c9a84c", + "colorPrimaryBg": "#fffef0", + "colorPrimaryBgHover": "#fcfaed", + "colorPrimaryBorder": "#f0eace", + "colorPrimaryBorderHover": "#e3d69f", + "colorPrimaryHover": "#d6bf74", + "colorPrimaryActive": "#a38336", + "colorPrimaryText": "#573e14", + "colorSuccess": "#52c41a", + "colorSuccessBg": "#f6ffed", + "colorSuccessBorder": "#b6eb8f", + "colorSuccessHover": "#72d13d", + "colorSuccessActive": "#389e0d", + "colorWarning": "#faad14", + "colorWarningBg": "#fffbe6", + "colorWarningBorder": "#ffe58f", + "colorWarningHover": "#ffc53d", + "colorWarningActive": "#d48806", + "colorError": "#ff4d4f", + "colorErrorBg": "#fff2f0", + "colorErrorBorder": "#ffccc7", + "colorErrorHover": "#ff7875", + "colorErrorActive": "#d9363d", + "colorInfo": "#c9a84c", + "colorInfoBg": "#fffef0", + "colorInfoBorder": "#f0eace", + "colorLink": "#c9a84c", + "colorLinkHover": "#d6bf74", + "colorLinkActive": "#a38336", + "colorText": "#35312b", + "colorTextSecondary": "#68655f", + "colorTextTertiary": "#95928c", + "colorTextQuaternary": "#c2bfba", + "colorFill": "#d8d5d0", + "colorFillSecondary": "#ede9e4", + "colorFillTertiary": "#f1eee9", + "colorFillQuaternary": "#f6f3ed", + "colorBgLayout": "#f1eee9", + "colorBgContainer": "#faf7f2", + "colorBgElevated": "#faf7f2", + "colorBorder": "#d8d5d0", + "colorBorderSecondary": "#ede9e4", + "fontFamily": "'Tenor Sans', sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + "fontFamilyCode": "'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace", + "fontSize": 14, + "fontSizeSM": 12, + "fontSizeLG": 18, + "fontSizeXL": 22, + "fontSizeHeading1": 38, + "fontSizeHeading2": 32, + "fontSizeHeading3": 26, + "fontSizeHeading4": 22, + "fontSizeHeading5": 18, + "lineHeight": 1.5714285714285714, + "lineHeightHeading": 1.25, + "fontWeightStrong": 600, + "sizeXXS": 4, + "sizeXS": 8, + "sizeSM": 12, + "size": 16, + "sizeMD": 20, + "sizeLG": 24, + "sizeXL": 32, + "sizeXXL": 48, + "borderRadiusXS": 3, + "borderRadiusSM": 5, + "borderRadius": 8, + "borderRadiusLG": 10, + "lineWidth": 1, + "controlHeightXS": 16, + "controlHeightSM": 24, + "controlHeight": 32, + "controlHeightLG": 40, + "motionDurationFast": "0.1s", + "motionDurationMid": "0.2s", + "motionDurationSlow": "0.3s", + "motionEaseInOut": "cubic-bezier(0.645, 0.045, 0.355, 1)", + "motionEaseOut": "cubic-bezier(0.215, 0.61, 0.355, 1)", + "primaryPalette": [ + "#fffef0", + "#fcfaed", + "#f0eace", + "#e3d69f", + "#d6bf74", + "#c9a84c", + "#a38336", + "#7d5f23", + "#573e14", + "#30210b" + ], + "presets": { + "red": [ + "#fff1f0", + "#ffcbc7", + "#ffa39e", + "#ff7775", + "#ff4d50", + "#f5222d", + "#cf1323", + "#a8071a", + "#820014", + "#5c0011" + ], + "volcano": [ + "#fff2e8", + "#ffd8bf", + "#ffbb96", + "#ff9c6e", + "#ff7a45", + "#fa541c", + "#d4380d", + "#ad2202", + "#871500", + "#610c00" + ], + "orange": [ + "#fff7e6", + "#ffe7ba", + "#ffd591", + "#ffc069", + "#ffa940", + "#fa8c16", + "#d46b08", + "#ad4e00", + "#873800", + "#612500" + ], + "gold": [ + "#fffbe6", + "#fff1b8", + "#ffe58f", + "#ffd666", + "#ffc53d", + "#faad14", + "#d48806", + "#ad6800", + "#874c00", + "#613400" + ], + "yellow": [ + "#feffe6", + "#ffffb8", + "#fffb8f", + "#fff566", + "#ffeb3d", + "#fadb14", + "#d4b106", + "#ad8a00", + "#876700", + "#614700" + ], + "lime": [ + "#fcffe6", + "#f4ffb8", + "#eaff8f", + "#d3f261", + "#bae637", + "#a0d911", + "#7bb305", + "#5b8c00", + "#3f6600", + "#254000" + ], + "green": [ + "#f6ffed", + "#d9f7be", + "#b6eb8f", + "#94de64", + "#72d13d", + "#52c41a", + "#389e0d", + "#227804", + "#135200", + "#092b00" + ], + "cyan": [ + "#e6fffb", + "#b5f5ec", + "#87e8de", + "#5cdbd3", + "#36cfc9", + "#13c2c2", + "#08979c", + "#006d75", + "#00474f", + "#002329" + ], + "blue": [ + "#e6f4ff", + "#bae0ff", + "#91caff", + "#69b1ff", + "#4096ff", + "#1677ff", + "#0958d9", + "#003eb3", + "#002c8c", + "#001d66" + ], + "geekblue": [ + "#f0f5ff", + "#d6e4ff", + "#adc6ff", + "#85a5ff", + "#597df7", + "#2f54eb", + "#1d39c4", + "#10229e", + "#061178", + "#030852" + ], + "purple": [ + "#f9f0ff", + "#efdbff", + "#d4adf7", + "#b37feb", + "#9254de", + "#722ed1", + "#531dab", + "#391085", + "#22075e", + "#120338" + ], + "magenta": [ + "#fff0f6", + "#ffd6e7", + "#ffadd2", + "#ff85bf", + "#f759aa", + "#eb2f96", + "#c41d7e", + "#9e1067", + "#780650", + "#520339" + ], + "grey": [ + "#a6a6a6", + "#999999", + "#8c8c8c", + "#808080", + "#737373", + "#666666", + "#404040", + "#1a1a1a", + "#000000", + "#000000" + ] + } +} \ No newline at end of file diff --git a/.design/system/variables.css b/.design/system/variables.css new file mode 100644 index 0000000..6094369 --- /dev/null +++ b/.design/system/variables.css @@ -0,0 +1,441 @@ +:root { + --brand-color-primary: #c9a84c; + --brand-color-primary-bg: #fffef0; + --brand-color-primary-bg-hover: #fcfaed; + --brand-color-primary-border: #f0eace; + --brand-color-primary-border-hover: #e3d69f; + --brand-color-primary-hover: #d6bf74; + --brand-color-primary-active: #a38336; + --brand-color-primary-text: #573e14; + --brand-color-success: #52c41a; + --brand-color-success-bg: #f6ffed; + --brand-color-success-border: #b6eb8f; + --brand-color-success-hover: #72d13d; + --brand-color-success-active: #389e0d; + --brand-color-warning: #faad14; + --brand-color-warning-bg: #fffbe6; + --brand-color-warning-border: #ffe58f; + --brand-color-warning-hover: #ffc53d; + --brand-color-warning-active: #d48806; + --brand-color-error: #ff4d4f; + --brand-color-error-bg: #fff2f0; + --brand-color-error-border: #ffccc7; + --brand-color-error-hover: #ff7875; + --brand-color-error-active: #d9363d; + --brand-color-info: #c9a84c; + --brand-color-info-bg: #fffef0; + --brand-color-info-border: #f0eace; + --brand-color-link: #c9a84c; + --brand-color-link-hover: #d6bf74; + --brand-color-link-active: #a38336; + --brand-color-text: #35312b; + --brand-color-text-secondary: #68655f; + --brand-color-text-tertiary: #95928c; + --brand-color-text-quaternary: #c2bfba; + --brand-color-fill: #d8d5d0; + --brand-color-fill-secondary: #ede9e4; + --brand-color-fill-tertiary: #f1eee9; + --brand-color-fill-quaternary: #f6f3ed; + --brand-color-bg-layout: #f1eee9; + --brand-color-bg-container: #faf7f2; + --brand-color-bg-elevated: #faf7f2; + --brand-color-border: #d8d5d0; + --brand-color-border-secondary: #ede9e4; + --brand-font-family: 'Tenor Sans', sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --brand-font-family-code: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; + --brand-font-size: 14px; + --brand-font-size-sm: 12px; + --brand-font-size-lg: 18px; + --brand-font-size-xl: 22px; + --brand-font-size-heading-1: 38px; + --brand-font-size-heading-2: 32px; + --brand-font-size-heading-3: 26px; + --brand-font-size-heading-4: 22px; + --brand-font-size-heading-5: 18px; + --brand-line-height: 1.5714285714285714; + --brand-line-height-heading: 1.25; + --brand-font-weight-strong: 600; + --brand-size-xxs: 4px; + --brand-size-xs: 8px; + --brand-size-sm: 12px; + --brand-size: 16px; + --brand-size-md: 20px; + --brand-size-lg: 24px; + --brand-size-xl: 32px; + --brand-size-xxl: 48px; + --brand-border-radius-xs: 3px; + --brand-border-radius-sm: 5px; + --brand-border-radius: 8px; + --brand-border-radius-lg: 10px; + --brand-line-width: 1px; + --brand-control-height-xs: 16px; + --brand-control-height-sm: 24px; + --brand-control-height: 32px; + --brand-control-height-lg: 40px; + --brand-motion-duration-fast: 0.1s; + --brand-motion-duration-mid: 0.2s; + --brand-motion-duration-slow: 0.3s; + --brand-motion-ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); + --brand-motion-ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); + --brand-primary-palette-1: #fffef0; + --brand-primary-palette-2: #fcfaed; + --brand-primary-palette-3: #f0eace; + --brand-primary-palette-4: #e3d69f; + --brand-primary-palette-5: #d6bf74; + --brand-primary-palette-6: #c9a84c; + --brand-primary-palette-7: #a38336; + --brand-primary-palette-8: #7d5f23; + --brand-primary-palette-9: #573e14; + --brand-primary-palette-10: #30210b; + --brand-presets-red-1: #fff1f0; + --brand-presets-red-2: #ffcbc7; + --brand-presets-red-3: #ffa39e; + --brand-presets-red-4: #ff7775; + --brand-presets-red-5: #ff4d50; + --brand-presets-red-6: #f5222d; + --brand-presets-red-7: #cf1323; + --brand-presets-red-8: #a8071a; + --brand-presets-red-9: #820014; + --brand-presets-red-10: #5c0011; + --brand-presets-volcano-1: #fff2e8; + --brand-presets-volcano-2: #ffd8bf; + --brand-presets-volcano-3: #ffbb96; + --brand-presets-volcano-4: #ff9c6e; + --brand-presets-volcano-5: #ff7a45; + --brand-presets-volcano-6: #fa541c; + --brand-presets-volcano-7: #d4380d; + --brand-presets-volcano-8: #ad2202; + --brand-presets-volcano-9: #871500; + --brand-presets-volcano-10: #610c00; + --brand-presets-orange-1: #fff7e6; + --brand-presets-orange-2: #ffe7ba; + --brand-presets-orange-3: #ffd591; + --brand-presets-orange-4: #ffc069; + --brand-presets-orange-5: #ffa940; + --brand-presets-orange-6: #fa8c16; + --brand-presets-orange-7: #d46b08; + --brand-presets-orange-8: #ad4e00; + --brand-presets-orange-9: #873800; + --brand-presets-orange-10: #612500; + --brand-presets-gold-1: #fffbe6; + --brand-presets-gold-2: #fff1b8; + --brand-presets-gold-3: #ffe58f; + --brand-presets-gold-4: #ffd666; + --brand-presets-gold-5: #ffc53d; + --brand-presets-gold-6: #faad14; + --brand-presets-gold-7: #d48806; + --brand-presets-gold-8: #ad6800; + --brand-presets-gold-9: #874c00; + --brand-presets-gold-10: #613400; + --brand-presets-yellow-1: #feffe6; + --brand-presets-yellow-2: #ffffb8; + --brand-presets-yellow-3: #fffb8f; + --brand-presets-yellow-4: #fff566; + --brand-presets-yellow-5: #ffeb3d; + --brand-presets-yellow-6: #fadb14; + --brand-presets-yellow-7: #d4b106; + --brand-presets-yellow-8: #ad8a00; + --brand-presets-yellow-9: #876700; + --brand-presets-yellow-10: #614700; + --brand-presets-lime-1: #fcffe6; + --brand-presets-lime-2: #f4ffb8; + --brand-presets-lime-3: #eaff8f; + --brand-presets-lime-4: #d3f261; + --brand-presets-lime-5: #bae637; + --brand-presets-lime-6: #a0d911; + --brand-presets-lime-7: #7bb305; + --brand-presets-lime-8: #5b8c00; + --brand-presets-lime-9: #3f6600; + --brand-presets-lime-10: #254000; + --brand-presets-green-1: #f6ffed; + --brand-presets-green-2: #d9f7be; + --brand-presets-green-3: #b6eb8f; + --brand-presets-green-4: #94de64; + --brand-presets-green-5: #72d13d; + --brand-presets-green-6: #52c41a; + --brand-presets-green-7: #389e0d; + --brand-presets-green-8: #227804; + --brand-presets-green-9: #135200; + --brand-presets-green-10: #092b00; + --brand-presets-cyan-1: #e6fffb; + --brand-presets-cyan-2: #b5f5ec; + --brand-presets-cyan-3: #87e8de; + --brand-presets-cyan-4: #5cdbd3; + --brand-presets-cyan-5: #36cfc9; + --brand-presets-cyan-6: #13c2c2; + --brand-presets-cyan-7: #08979c; + --brand-presets-cyan-8: #006d75; + --brand-presets-cyan-9: #00474f; + --brand-presets-cyan-10: #002329; + --brand-presets-blue-1: #e6f4ff; + --brand-presets-blue-2: #bae0ff; + --brand-presets-blue-3: #91caff; + --brand-presets-blue-4: #69b1ff; + --brand-presets-blue-5: #4096ff; + --brand-presets-blue-6: #1677ff; + --brand-presets-blue-7: #0958d9; + --brand-presets-blue-8: #003eb3; + --brand-presets-blue-9: #002c8c; + --brand-presets-blue-10: #001d66; + --brand-presets-geekblue-1: #f0f5ff; + --brand-presets-geekblue-2: #d6e4ff; + --brand-presets-geekblue-3: #adc6ff; + --brand-presets-geekblue-4: #85a5ff; + --brand-presets-geekblue-5: #597df7; + --brand-presets-geekblue-6: #2f54eb; + --brand-presets-geekblue-7: #1d39c4; + --brand-presets-geekblue-8: #10229e; + --brand-presets-geekblue-9: #061178; + --brand-presets-geekblue-10: #030852; + --brand-presets-purple-1: #f9f0ff; + --brand-presets-purple-2: #efdbff; + --brand-presets-purple-3: #d4adf7; + --brand-presets-purple-4: #b37feb; + --brand-presets-purple-5: #9254de; + --brand-presets-purple-6: #722ed1; + --brand-presets-purple-7: #531dab; + --brand-presets-purple-8: #391085; + --brand-presets-purple-9: #22075e; + --brand-presets-purple-10: #120338; + --brand-presets-magenta-1: #fff0f6; + --brand-presets-magenta-2: #ffd6e7; + --brand-presets-magenta-3: #ffadd2; + --brand-presets-magenta-4: #ff85bf; + --brand-presets-magenta-5: #f759aa; + --brand-presets-magenta-6: #eb2f96; + --brand-presets-magenta-7: #c41d7e; + --brand-presets-magenta-8: #9e1067; + --brand-presets-magenta-9: #780650; + --brand-presets-magenta-10: #520339; + --brand-presets-grey-1: #a6a6a6; + --brand-presets-grey-2: #999999; + --brand-presets-grey-3: #8c8c8c; + --brand-presets-grey-4: #808080; + --brand-presets-grey-5: #737373; + --brand-presets-grey-6: #666666; + --brand-presets-grey-7: #404040; + --brand-presets-grey-8: #1a1a1a; + --brand-presets-grey-9: #000000; + --brand-presets-grey-10: #000000; +} + +.dark { + --brand-color-primary: #b9a566; + --brand-color-primary-bg: #292519; + --brand-color-primary-bg-hover: #413922; + --brand-color-primary-border: #4e4731; + --brand-color-primary-border-hover: #6b613f; + --brand-color-primary-hover: #cec391; + --brand-color-primary-active: #928352; + --brand-color-primary-text: #f5f3e6; + --brand-color-success: #64b537; + --brand-color-success-bg: #192913; + --brand-color-success-border: #304d20; + --brand-color-success-hover: #87ca5c; + --brand-color-success-active: #518f2f; + --brand-color-warning: #dcaa37; + --brand-color-warning-bg: #312512; + --brand-color-warning-border: #5b4920; + --brand-color-warning-hover: #e8c35e; + --brand-color-warning-active: #ad872f; + --brand-color-error: #dc6966; + --brand-color-error-bg: #32191a; + --brand-color-error-border: #5b3231; + --brand-color-error-hover: #e89590; + --brand-color-error-active: #ad5553; + --brand-color-info: #b9a566; + --brand-color-info-bg: #292519; + --brand-color-info-border: #4e4731; + --brand-color-link: #b9a566; + --brand-color-link-hover: #cec391; + --brand-color-link-active: #928352; + --brand-color-text: #dcdcdc; + --brand-color-text-secondary: #adadad; + --brand-color-text-tertiary: #7e7e7e; + --brand-color-text-quaternary: #4f4f4f; + --brand-color-fill: #3e3e3e; + --brand-color-fill-secondary: #303030; + --brand-color-fill-tertiary: #272727; + --brand-color-fill-quaternary: #1d1d1d; + --brand-color-bg-layout: #1d1d1d; + --brand-color-bg-container: #141414; + --brand-color-bg-elevated: #272727; + --brand-color-border: #3e3e3e; + --brand-color-border-secondary: #303030; + --brand-font-family: 'Tenor Sans', sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --brand-font-family-code: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; + --brand-font-size: 14px; + --brand-font-size-sm: 12px; + --brand-font-size-lg: 18px; + --brand-font-size-xl: 22px; + --brand-font-size-heading-1: 38px; + --brand-font-size-heading-2: 32px; + --brand-font-size-heading-3: 26px; + --brand-font-size-heading-4: 22px; + --brand-font-size-heading-5: 18px; + --brand-line-height: 1.5714285714285714; + --brand-line-height-heading: 1.25; + --brand-font-weight-strong: 600; + --brand-size-xxs: 4px; + --brand-size-xs: 8px; + --brand-size-sm: 12px; + --brand-size: 16px; + --brand-size-md: 20px; + --brand-size-lg: 24px; + --brand-size-xl: 32px; + --brand-size-xxl: 48px; + --brand-border-radius-xs: 3px; + --brand-border-radius-sm: 5px; + --brand-border-radius: 8px; + --brand-border-radius-lg: 10px; + --brand-line-width: 1px; + --brand-control-height-xs: 16px; + --brand-control-height-sm: 24px; + --brand-control-height: 32px; + --brand-control-height-lg: 40px; + --brand-motion-duration-fast: 0.1s; + --brand-motion-duration-mid: 0.2s; + --brand-motion-duration-slow: 0.3s; + --brand-motion-ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); + --brand-motion-ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); + --brand-primary-palette-1: #292519; + --brand-primary-palette-2: #413922; + --brand-primary-palette-3: #4e4731; + --brand-primary-palette-4: #6b613f; + --brand-primary-palette-5: #928352; + --brand-primary-palette-6: #b9a566; + --brand-primary-palette-7: #cec391; + --brand-primary-palette-8: #e5dfc5; + --brand-primary-palette-9: #f5f3e6; + --brand-primary-palette-10: #faf9ec; + --brand-presets-red-1: #fff1f0; + --brand-presets-red-2: #ffcbc7; + --brand-presets-red-3: #ffa39e; + --brand-presets-red-4: #ff7775; + --brand-presets-red-5: #ff4d50; + --brand-presets-red-6: #f5222d; + --brand-presets-red-7: #cf1323; + --brand-presets-red-8: #a8071a; + --brand-presets-red-9: #820014; + --brand-presets-red-10: #5c0011; + --brand-presets-volcano-1: #fff2e8; + --brand-presets-volcano-2: #ffd8bf; + --brand-presets-volcano-3: #ffbb96; + --brand-presets-volcano-4: #ff9c6e; + --brand-presets-volcano-5: #ff7a45; + --brand-presets-volcano-6: #fa541c; + --brand-presets-volcano-7: #d4380d; + --brand-presets-volcano-8: #ad2202; + --brand-presets-volcano-9: #871500; + --brand-presets-volcano-10: #610c00; + --brand-presets-orange-1: #fff7e6; + --brand-presets-orange-2: #ffe7ba; + --brand-presets-orange-3: #ffd591; + --brand-presets-orange-4: #ffc069; + --brand-presets-orange-5: #ffa940; + --brand-presets-orange-6: #fa8c16; + --brand-presets-orange-7: #d46b08; + --brand-presets-orange-8: #ad4e00; + --brand-presets-orange-9: #873800; + --brand-presets-orange-10: #612500; + --brand-presets-gold-1: #fffbe6; + --brand-presets-gold-2: #fff1b8; + --brand-presets-gold-3: #ffe58f; + --brand-presets-gold-4: #ffd666; + --brand-presets-gold-5: #ffc53d; + --brand-presets-gold-6: #faad14; + --brand-presets-gold-7: #d48806; + --brand-presets-gold-8: #ad6800; + --brand-presets-gold-9: #874c00; + --brand-presets-gold-10: #613400; + --brand-presets-yellow-1: #feffe6; + --brand-presets-yellow-2: #ffffb8; + --brand-presets-yellow-3: #fffb8f; + --brand-presets-yellow-4: #fff566; + --brand-presets-yellow-5: #ffeb3d; + --brand-presets-yellow-6: #fadb14; + --brand-presets-yellow-7: #d4b106; + --brand-presets-yellow-8: #ad8a00; + --brand-presets-yellow-9: #876700; + --brand-presets-yellow-10: #614700; + --brand-presets-lime-1: #fcffe6; + --brand-presets-lime-2: #f4ffb8; + --brand-presets-lime-3: #eaff8f; + --brand-presets-lime-4: #d3f261; + --brand-presets-lime-5: #bae637; + --brand-presets-lime-6: #a0d911; + --brand-presets-lime-7: #7bb305; + --brand-presets-lime-8: #5b8c00; + --brand-presets-lime-9: #3f6600; + --brand-presets-lime-10: #254000; + --brand-presets-green-1: #f6ffed; + --brand-presets-green-2: #d9f7be; + --brand-presets-green-3: #b6eb8f; + --brand-presets-green-4: #94de64; + --brand-presets-green-5: #72d13d; + --brand-presets-green-6: #52c41a; + --brand-presets-green-7: #389e0d; + --brand-presets-green-8: #227804; + --brand-presets-green-9: #135200; + --brand-presets-green-10: #092b00; + --brand-presets-cyan-1: #e6fffb; + --brand-presets-cyan-2: #b5f5ec; + --brand-presets-cyan-3: #87e8de; + --brand-presets-cyan-4: #5cdbd3; + --brand-presets-cyan-5: #36cfc9; + --brand-presets-cyan-6: #13c2c2; + --brand-presets-cyan-7: #08979c; + --brand-presets-cyan-8: #006d75; + --brand-presets-cyan-9: #00474f; + --brand-presets-cyan-10: #002329; + --brand-presets-blue-1: #e6f4ff; + --brand-presets-blue-2: #bae0ff; + --brand-presets-blue-3: #91caff; + --brand-presets-blue-4: #69b1ff; + --brand-presets-blue-5: #4096ff; + --brand-presets-blue-6: #1677ff; + --brand-presets-blue-7: #0958d9; + --brand-presets-blue-8: #003eb3; + --brand-presets-blue-9: #002c8c; + --brand-presets-blue-10: #001d66; + --brand-presets-geekblue-1: #f0f5ff; + --brand-presets-geekblue-2: #d6e4ff; + --brand-presets-geekblue-3: #adc6ff; + --brand-presets-geekblue-4: #85a5ff; + --brand-presets-geekblue-5: #597df7; + --brand-presets-geekblue-6: #2f54eb; + --brand-presets-geekblue-7: #1d39c4; + --brand-presets-geekblue-8: #10229e; + --brand-presets-geekblue-9: #061178; + --brand-presets-geekblue-10: #030852; + --brand-presets-purple-1: #f9f0ff; + --brand-presets-purple-2: #efdbff; + --brand-presets-purple-3: #d4adf7; + --brand-presets-purple-4: #b37feb; + --brand-presets-purple-5: #9254de; + --brand-presets-purple-6: #722ed1; + --brand-presets-purple-7: #531dab; + --brand-presets-purple-8: #391085; + --brand-presets-purple-9: #22075e; + --brand-presets-purple-10: #120338; + --brand-presets-magenta-1: #fff0f6; + --brand-presets-magenta-2: #ffd6e7; + --brand-presets-magenta-3: #ffadd2; + --brand-presets-magenta-4: #ff85bf; + --brand-presets-magenta-5: #f759aa; + --brand-presets-magenta-6: #eb2f96; + --brand-presets-magenta-7: #c41d7e; + --brand-presets-magenta-8: #9e1067; + --brand-presets-magenta-9: #780650; + --brand-presets-magenta-10: #520339; + --brand-presets-grey-1: #a6a6a6; + --brand-presets-grey-2: #999999; + --brand-presets-grey-3: #8c8c8c; + --brand-presets-grey-4: #808080; + --brand-presets-grey-5: #737373; + --brand-presets-grey-6: #666666; + --brand-presets-grey-7: #404040; + --brand-presets-grey-8: #1a1a1a; + --brand-presets-grey-9: #000000; + --brand-presets-grey-10: #000000; +} diff --git a/.design/system/variables.dark.css b/.design/system/variables.dark.css new file mode 100644 index 0000000..a55a098 --- /dev/null +++ b/.design/system/variables.dark.css @@ -0,0 +1,220 @@ +:root { + --brand-color-primary: #b9a566; + --brand-color-primary-bg: #292519; + --brand-color-primary-bg-hover: #413922; + --brand-color-primary-border: #4e4731; + --brand-color-primary-border-hover: #6b613f; + --brand-color-primary-hover: #cec391; + --brand-color-primary-active: #928352; + --brand-color-primary-text: #f5f3e6; + --brand-color-success: #64b537; + --brand-color-success-bg: #192913; + --brand-color-success-border: #304d20; + --brand-color-success-hover: #87ca5c; + --brand-color-success-active: #518f2f; + --brand-color-warning: #dcaa37; + --brand-color-warning-bg: #312512; + --brand-color-warning-border: #5b4920; + --brand-color-warning-hover: #e8c35e; + --brand-color-warning-active: #ad872f; + --brand-color-error: #dc6966; + --brand-color-error-bg: #32191a; + --brand-color-error-border: #5b3231; + --brand-color-error-hover: #e89590; + --brand-color-error-active: #ad5553; + --brand-color-info: #b9a566; + --brand-color-info-bg: #292519; + --brand-color-info-border: #4e4731; + --brand-color-link: #b9a566; + --brand-color-link-hover: #cec391; + --brand-color-link-active: #928352; + --brand-color-text: #dcdcdc; + --brand-color-text-secondary: #adadad; + --brand-color-text-tertiary: #7e7e7e; + --brand-color-text-quaternary: #4f4f4f; + --brand-color-fill: #3e3e3e; + --brand-color-fill-secondary: #303030; + --brand-color-fill-tertiary: #272727; + --brand-color-fill-quaternary: #1d1d1d; + --brand-color-bg-layout: #1d1d1d; + --brand-color-bg-container: #141414; + --brand-color-bg-elevated: #272727; + --brand-color-border: #3e3e3e; + --brand-color-border-secondary: #303030; + --brand-font-family: 'Tenor Sans', sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --brand-font-family-code: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; + --brand-font-size: 14px; + --brand-font-size-sm: 12px; + --brand-font-size-lg: 18px; + --brand-font-size-xl: 22px; + --brand-font-size-heading-1: 38px; + --brand-font-size-heading-2: 32px; + --brand-font-size-heading-3: 26px; + --brand-font-size-heading-4: 22px; + --brand-font-size-heading-5: 18px; + --brand-line-height: 1.5714285714285714; + --brand-line-height-heading: 1.25; + --brand-font-weight-strong: 600; + --brand-size-xxs: 4px; + --brand-size-xs: 8px; + --brand-size-sm: 12px; + --brand-size: 16px; + --brand-size-md: 20px; + --brand-size-lg: 24px; + --brand-size-xl: 32px; + --brand-size-xxl: 48px; + --brand-border-radius-xs: 3px; + --brand-border-radius-sm: 5px; + --brand-border-radius: 8px; + --brand-border-radius-lg: 10px; + --brand-line-width: 1px; + --brand-control-height-xs: 16px; + --brand-control-height-sm: 24px; + --brand-control-height: 32px; + --brand-control-height-lg: 40px; + --brand-motion-duration-fast: 0.1s; + --brand-motion-duration-mid: 0.2s; + --brand-motion-duration-slow: 0.3s; + --brand-motion-ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); + --brand-motion-ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); + --brand-primary-palette-1: #292519; + --brand-primary-palette-2: #413922; + --brand-primary-palette-3: #4e4731; + --brand-primary-palette-4: #6b613f; + --brand-primary-palette-5: #928352; + --brand-primary-palette-6: #b9a566; + --brand-primary-palette-7: #cec391; + --brand-primary-palette-8: #e5dfc5; + --brand-primary-palette-9: #f5f3e6; + --brand-primary-palette-10: #faf9ec; + --brand-presets-red-1: #fff1f0; + --brand-presets-red-2: #ffcbc7; + --brand-presets-red-3: #ffa39e; + --brand-presets-red-4: #ff7775; + --brand-presets-red-5: #ff4d50; + --brand-presets-red-6: #f5222d; + --brand-presets-red-7: #cf1323; + --brand-presets-red-8: #a8071a; + --brand-presets-red-9: #820014; + --brand-presets-red-10: #5c0011; + --brand-presets-volcano-1: #fff2e8; + --brand-presets-volcano-2: #ffd8bf; + --brand-presets-volcano-3: #ffbb96; + --brand-presets-volcano-4: #ff9c6e; + --brand-presets-volcano-5: #ff7a45; + --brand-presets-volcano-6: #fa541c; + --brand-presets-volcano-7: #d4380d; + --brand-presets-volcano-8: #ad2202; + --brand-presets-volcano-9: #871500; + --brand-presets-volcano-10: #610c00; + --brand-presets-orange-1: #fff7e6; + --brand-presets-orange-2: #ffe7ba; + --brand-presets-orange-3: #ffd591; + --brand-presets-orange-4: #ffc069; + --brand-presets-orange-5: #ffa940; + --brand-presets-orange-6: #fa8c16; + --brand-presets-orange-7: #d46b08; + --brand-presets-orange-8: #ad4e00; + --brand-presets-orange-9: #873800; + --brand-presets-orange-10: #612500; + --brand-presets-gold-1: #fffbe6; + --brand-presets-gold-2: #fff1b8; + --brand-presets-gold-3: #ffe58f; + --brand-presets-gold-4: #ffd666; + --brand-presets-gold-5: #ffc53d; + --brand-presets-gold-6: #faad14; + --brand-presets-gold-7: #d48806; + --brand-presets-gold-8: #ad6800; + --brand-presets-gold-9: #874c00; + --brand-presets-gold-10: #613400; + --brand-presets-yellow-1: #feffe6; + --brand-presets-yellow-2: #ffffb8; + --brand-presets-yellow-3: #fffb8f; + --brand-presets-yellow-4: #fff566; + --brand-presets-yellow-5: #ffeb3d; + --brand-presets-yellow-6: #fadb14; + --brand-presets-yellow-7: #d4b106; + --brand-presets-yellow-8: #ad8a00; + --brand-presets-yellow-9: #876700; + --brand-presets-yellow-10: #614700; + --brand-presets-lime-1: #fcffe6; + --brand-presets-lime-2: #f4ffb8; + --brand-presets-lime-3: #eaff8f; + --brand-presets-lime-4: #d3f261; + --brand-presets-lime-5: #bae637; + --brand-presets-lime-6: #a0d911; + --brand-presets-lime-7: #7bb305; + --brand-presets-lime-8: #5b8c00; + --brand-presets-lime-9: #3f6600; + --brand-presets-lime-10: #254000; + --brand-presets-green-1: #f6ffed; + --brand-presets-green-2: #d9f7be; + --brand-presets-green-3: #b6eb8f; + --brand-presets-green-4: #94de64; + --brand-presets-green-5: #72d13d; + --brand-presets-green-6: #52c41a; + --brand-presets-green-7: #389e0d; + --brand-presets-green-8: #227804; + --brand-presets-green-9: #135200; + --brand-presets-green-10: #092b00; + --brand-presets-cyan-1: #e6fffb; + --brand-presets-cyan-2: #b5f5ec; + --brand-presets-cyan-3: #87e8de; + --brand-presets-cyan-4: #5cdbd3; + --brand-presets-cyan-5: #36cfc9; + --brand-presets-cyan-6: #13c2c2; + --brand-presets-cyan-7: #08979c; + --brand-presets-cyan-8: #006d75; + --brand-presets-cyan-9: #00474f; + --brand-presets-cyan-10: #002329; + --brand-presets-blue-1: #e6f4ff; + --brand-presets-blue-2: #bae0ff; + --brand-presets-blue-3: #91caff; + --brand-presets-blue-4: #69b1ff; + --brand-presets-blue-5: #4096ff; + --brand-presets-blue-6: #1677ff; + --brand-presets-blue-7: #0958d9; + --brand-presets-blue-8: #003eb3; + --brand-presets-blue-9: #002c8c; + --brand-presets-blue-10: #001d66; + --brand-presets-geekblue-1: #f0f5ff; + --brand-presets-geekblue-2: #d6e4ff; + --brand-presets-geekblue-3: #adc6ff; + --brand-presets-geekblue-4: #85a5ff; + --brand-presets-geekblue-5: #597df7; + --brand-presets-geekblue-6: #2f54eb; + --brand-presets-geekblue-7: #1d39c4; + --brand-presets-geekblue-8: #10229e; + --brand-presets-geekblue-9: #061178; + --brand-presets-geekblue-10: #030852; + --brand-presets-purple-1: #f9f0ff; + --brand-presets-purple-2: #efdbff; + --brand-presets-purple-3: #d4adf7; + --brand-presets-purple-4: #b37feb; + --brand-presets-purple-5: #9254de; + --brand-presets-purple-6: #722ed1; + --brand-presets-purple-7: #531dab; + --brand-presets-purple-8: #391085; + --brand-presets-purple-9: #22075e; + --brand-presets-purple-10: #120338; + --brand-presets-magenta-1: #fff0f6; + --brand-presets-magenta-2: #ffd6e7; + --brand-presets-magenta-3: #ffadd2; + --brand-presets-magenta-4: #ff85bf; + --brand-presets-magenta-5: #f759aa; + --brand-presets-magenta-6: #eb2f96; + --brand-presets-magenta-7: #c41d7e; + --brand-presets-magenta-8: #9e1067; + --brand-presets-magenta-9: #780650; + --brand-presets-magenta-10: #520339; + --brand-presets-grey-1: #a6a6a6; + --brand-presets-grey-2: #999999; + --brand-presets-grey-3: #8c8c8c; + --brand-presets-grey-4: #808080; + --brand-presets-grey-5: #737373; + --brand-presets-grey-6: #666666; + --brand-presets-grey-7: #404040; + --brand-presets-grey-8: #1a1a1a; + --brand-presets-grey-9: #000000; + --brand-presets-grey-10: #000000; +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ff4c919 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +node_modules +dist +*.local +.DS_Store +*.log +.vite +coverage diff --git a/.info/ToV.md b/.info/ToV.md new file mode 100644 index 0000000..44b5468 --- /dev/null +++ b/.info/ToV.md @@ -0,0 +1,18 @@ +# Malenia + +## Основная информация + +MaleniaVPN (malenia, маления) — маленькая студия из двух, разрабатывающая VPN решения. Наш имидж строится на критичной насмешке над неспособностью цензоров внедрить серьезные меры против свободного доступа в интернет. + +## Ценности + +Мы ценим честность, и именно поэтому мы ведём максимально честный диалог с нашими пользователями. Инциденты, недочёты, ошибки и совершенствование — мы выносим в свет, так как отказываемся считать, что зрители являются просто потребителями. +Мы ценим надёжность, из-за чего стремимся к максимальной простоте и устойчивости для наших клиентов. Принцип включил и забыл стоит в основе нашей деятельности. +Мы ценим свободу слова, поэтому мы продолжаем работать, даже когда блокировки становятся сложнее и моральная давка становится сильнее. +Для нас это больше чем сервис. Для нас Malenia — это способ борьбы с несправедливыми репрессиями. Мы будем стоять против, не смотря ни на что. + +## Сторонний отзыв об имидже компании + +Бренд Malenia строится вокруг образа независимой, небольшой, но технически компетентной команды, которая противопоставляет себя крупным игрокам рынка и бюрократическим структурам. В коммуникации постоянно подчеркивается происхождение проекта: «два программиста-самоучки», отсутствие маркетингового отдела, работа руками инженеров, а не продавцов. Центральные ценности бренда — свобода доступа к информации, прозрачность, инженерный подход и практическая польза для пользователя. Malenia продаёт не просто VPN, а идею «возвращения интернета пользователю», где технологии должны работать незаметно и без сложной настройки. Компания стремится выглядеть союзником аудитории, регулярно вовлекает пользователей в принятие решений через голосования, признаёт ошибки публично и демонстрирует открытость даже в кризисных ситуациях. Имидж бренда — это сочетание технического андеграунда, цифрового активизма и честного сервиса без корпоративного лоска. + +Tone of Voice построен на разговорном, ироничном и местами дерзком стиле. Malenia не говорит языком пресс-релизов: в текстах много сарказма, мемов, бытовых сравнений и намеренно простых формулировок, которые делают сложные сетевые темы понятными широкой аудитории. При этом за шутками всегда прослеживается позиция эксперта, который готов спорить с конкурентами и публично разбирать их заявления. Отношение к оппонентам критическое и даже насмешливое: компания активно высмеивает маркетинговые манипуляции, драматизацию и попытки играть на страхах пользователей. Однако главным объектом критики становятся не конкретные конкуренты, а некомпетентность, непрозрачность и искусственное нагнетание паники. В отношении к работе прослеживается принцип «сначала решаем проблему, потом рассказываем о ней»: команда демонстрирует готовность быстро адаптироваться к изменениям, экспериментировать, исправлять собственные ошибки и честно признавать просчёты. В результате бренд воспринимается как «свои люди в индустрии» — немного хулиганы, немного инженеры, но прежде всего защитники открытого интернета и интересов своих пользователей. diff --git a/.info/index.html b/.info/index.html new file mode 100644 index 0000000..96454e6 --- /dev/null +++ b/.info/index.html @@ -0,0 +1,366 @@ + + + + + + Malenia — Свобода в сети + + + + + + + + + + +
+
+ +
+ + +
+ +
+ Свобода. Практика. Простота. +
+ + +
+ + + + + +
+

Тишина в сети —
это тоже выбор.

+

malenia.space

+
+ + + + + + +
+ + +
+ © 2026 Malenia + + malenia.space +
+ +
+ + + + + diff --git a/.info/openapi.json b/.info/openapi.json new file mode 100644 index 0000000..0c5cbe7 --- /dev/null +++ b/.info/openapi.json @@ -0,0 +1 @@ +{"openapi":"3.1.0","info":{"title":"FastAPI","version":"0.1.0"},"paths":{"/auth/signup":{"post":{"summary":"Signup","operationId":"signup_auth_signup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRegistration"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/login":{"post":{"summary":"Login","operationId":"login_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLoginData"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLogin"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/refresh":{"post":{"summary":"Refresh","operationId":"refresh_auth_refresh_post","parameters":[{"name":"refresh_token","in":"query","required":true,"schema":{"type":"string","title":"Refresh Token"}},{"name":"iss","in":"query","required":true,"schema":{"enum":["credentials","telegram","api"],"type":"string","title":"Iss"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserTokens"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/plans/":{"get":{"summary":"Get Plans","operationId":"get_plans_plans__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingPlans"}}}}}}},"/orders/checkout":{"post":{"summary":"Checkout","operationId":"checkout_orders_checkout_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderDetails"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/users/me":{"get":{"summary":"Get Me","operationId":"get_me_users_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfo"}}}}}}},"/users/subscription":{"get":{"summary":"Get Subscription","operationId":"get_subscription_users_subscription_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/users/subscription/hwid":{"get":{"summary":"Get Hwid","operationId":"get_hwid_users_subscription_hwid_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Device"},"title":"Response Get Hwid Users Subscription Hwid Get"}}}}}},"delete":{"summary":"Delete Hwid Endpoint","operationId":"delete_hwid_endpoint_users_subscription_hwid_delete","parameters":[{"name":"hwid","in":"query","required":true,"schema":{"type":"string","title":"Hwid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/payments/pally/result":{"post":{"summary":"Pally Callback","operationId":"pally_callback_payments_pally_result_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_pally_callback_payments_pally_result_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AddonData":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"price":{"type":"number","title":"Price"},"free_threshold":{"type":"integer","title":"Free Threshold"}},"type":"object","required":["id","name","price","free_threshold"],"title":"AddonData"},"Body_pally_callback_payments_pally_result_post":{"properties":{"InvId":{"type":"string","title":"Invid"},"OutSum":{"type":"string","title":"Outsum"},"Commission":{"type":"string","title":"Commission"},"TrsId":{"type":"string","title":"Trsid"},"Status":{"type":"string","title":"Status"},"CurrencyIn":{"type":"string","title":"Currencyin"},"custom":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom"},"SignatureValue":{"type":"string","title":"Signaturevalue"},"AccountType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accounttype"},"AccountNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accountnumber"},"BalanceAmount":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Balanceamount"},"BalanceCurrency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Balancecurrency"},"PayerPhone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payerphone"},"PayerEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payeremail"},"PayerName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payername"},"PayerComment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payercomment"},"ErrorCode":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Errorcode"},"ErrorMessage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Errormessage"}},"type":"object","required":["InvId","OutSum","Commission","TrsId","Status","CurrencyIn","SignatureValue"],"title":"Body_pally_callback_payments_pally_result_post"},"CheckoutResponse":{"properties":{"order_id":{"type":"string","title":"Order Id"},"total_amount":{"type":"number","title":"Total Amount"},"bonus_paid":{"type":"number","title":"Bonus Paid"},"amount_to_pay":{"type":"number","title":"Amount To Pay"},"payment_link":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Link"}},"type":"object","required":["order_id","total_amount","bonus_paid","amount_to_pay"],"title":"CheckoutResponse"},"Device":{"properties":{"os":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Os"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"client":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client"},"hwid":{"type":"string","title":"Hwid"}},"type":"object","required":["hwid"],"title":"Device"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"OrderDetails":{"properties":{"devices":{"type":"integer","title":"Devices"},"addons":{"items":{"type":"string"},"type":"array","title":"Addons","description":"List of addons ids"},"duration_days":{"type":"integer","title":"Duration Days"}},"type":"object","required":["devices","addons","duration_days"],"title":"OrderDetails"},"PricingPlans":{"properties":{"device_price":{"type":"integer","title":"Device Price"},"addons":{"items":{"$ref":"#/components/schemas/AddonData"},"type":"array","title":"Addons"}},"type":"object","required":["device_price","addons"],"title":"PricingPlans"},"TelegramData":{"properties":{},"type":"object","title":"TelegramData"},"UserInfo":{"properties":{"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"},"telegram_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Telegram Id"},"referal_code":{"type":"string","title":"Referal Code"}},"type":"object","required":["referal_code"],"title":"UserInfo"},"UserLogin":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"expires_at":{"type":"number","title":"Expires At"},"user":{"$ref":"#/components/schemas/UserInfo"}},"type":"object","required":["access_token","refresh_token","expires_at","user"],"title":"UserLogin"},"UserLoginData":{"properties":{"provider":{"type":"string","enum":["credentials","telegram","api"],"title":"Provider"},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"telegram":{"anyOf":[{"$ref":"#/components/schemas/TelegramData"},{"type":"null"}]}},"type":"object","required":["provider"],"title":"UserLoginData"},"UserRegistration":{"properties":{"telegram_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Telegram Id"},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"referal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Referal Code"},"provider":{"type":"string","enum":["credentials","telegram","api"],"title":"Provider"}},"type":"object","required":["provider"],"title":"UserRegistration"},"UserTokens":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"expires_at":{"type":"number","title":"Expires At"}},"type":"object","required":["access_token","refresh_token","expires_at"],"title":"UserTokens"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}} \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..9f66c31 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "printWidth": 100, + "singleQuote": true, + "trailingComma": "all", + "semi": true, + "tabWidth": 2, + "bracketSpacing": true, + "arrowParens": "always" +} diff --git a/.ref/account.html b/.ref/account.html new file mode 100644 index 0000000..1e8b9b8 --- /dev/null +++ b/.ref/account.html @@ -0,0 +1,921 @@ + + + + + +MaleniaVPN · Account + + + + + + + + + +
+ +
+ + +
+ + +
+
Your account
+

Eleanor Ashworth

+

Member since March 2023 · Plan: Solitude

+
+ + +
+ +
+ +
Username
+
e.ashworth
+
+ + +
+ +
Telegram ID
+
@eashworth
+
+ + +
+ +
Devices linked
+
4 / of 6
+
+ + +
+ +
Renews
+
14 Mar 2026
+
+
+ + + + +
+
+

Connected devices

+
4active
+
+ +
+ +
+
+ + +
+ MaleniaVPN · Solitude plan + Sign out +
+
+ + + + +
+ + + + diff --git a/.ref/calculator.html b/.ref/calculator.html new file mode 100644 index 0000000..c465e78 --- /dev/null +++ b/.ref/calculator.html @@ -0,0 +1,1212 @@ + + + + +MaleniaVPN · Compose your plan + + + + + + + + + +
+ +
+ + +
+ + +
+
Compose your plan
+

A circle, sized to you.

+

Choose how many devices share your freedom. The price scales quietly — one rate per seat, no tiers, no surcharges.

+
+ + +
+
+ +
+
Estimated price · monthly
+
+ $18 + USD / mo +
+
For 6 devices · $3.00 per seat
+
+ + +
+
+ Devices + 6  seats +
+
+
+
+
+ + +
+
+
+
+ + + Drag the rhombus · arrow keys to fine-tune + + Range 3 – 12 +
+
+
+ + +
+
+ Commitment + Billed monthly +
+
+
+ + +
+
+
Devices 6
+
$3.00/ seat
+
+ + + + +
+ + +
+
+
Refine your circle
+
Optional add-ons · placeholder
+
+
+
+ + +
+ +
Plan adjusts at next renewal · No lock-in
+
+
+ + +
+ MaleniaVPN · Solitude plan + Estimate only +
+
+ + + + + \ No newline at end of file diff --git a/.ref/landing.html b/.ref/landing.html new file mode 100644 index 0000000..7232d4d --- /dev/null +++ b/.ref/landing.html @@ -0,0 +1,467 @@ + + + + Malenia — Свобода в сети + + + + + + + + + + +
+
+ +
+ + +
+ +
+ Свобода. Практика. Простота. +
+ + +
+ + + + + +
+

Верните себе
свободный интернет.

+

malenia.space

+
+ + + + + + +
+ + +
+ © 2026 Malenia + + malenia.space +
+ +
+ + + + \ No newline at end of file diff --git a/.ref/login.html b/.ref/login.html new file mode 100644 index 0000000..2a599b4 --- /dev/null +++ b/.ref/login.html @@ -0,0 +1,561 @@ + + + + +MaleniaVPN · Sign In + + + + + + +
+
+ +
+
+ +
Private access
+
+ +
+

Sign in

+

Enter your credentials to resume your session.

+ +
+
+ + + +
+ +
+ + + + +
+ +
+ + Forgot password? +
+ + + +
+
+ + + + + + +
+ +
+ Protected by MaleniaVPN +
+
+ + + + + \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8e13d4c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,423 @@ +# MaleniaVPN — Frontend Agent Guidance + +## Project Overview + +MaleniaVPN (malenia) is a VPN purchase service built around a **pay-for-device** model: +one flat rate per device ("seat"), no tiers. The frontend is a **Russian-language** web +app living in `frontend/` on top of a FastAPI backend. This file is the canonical +guidance for AI assistants working on it. + +The service is run by a two-person studio. The brand is minimalist and archival +(cream/ink/gold, extreme whitespace), but the *voice* is honest, ironic and sometimes +snarky. Keep the UI elegant; keep the copy human. + +### Screens + +| Screen | Route | Access | Source of truth | +|---|---|---|---| +| Landing | `/` | Public | `.ref/landing.html` (existing hosted page) | +| Plan calculator | `/plan` | Public (auth needed only to confirm an order) | `.ref/calculator.html` | +| Login / Signup | `/login` | Public | `.ref/login.html` | +| Account | `/account` | Protected (auth required) | `.ref/account.html` | + +## Authoritative Source Directories (read-only) + +Never edit these; they are reference material. + +| Path | What it is | +| --- | --- | +| `.info/openapi.json` | **The** backend API contract. All types below mirror it. | +| `.info/ToV.md` | Company values and tone of voice (Russian). | +| `.design/DESIGN.md`, `.design/brand.json` | Visual identity: palette, typography, layout posture. | +| `.design/fonts/` | Self-hosted `.woff2` + `fonts.css`. **Latin-only subsets — see Typography.** | +| `.design/logos/` | `favicon-0.ico` — the favicon. | +| `.ref/*.html` | Ready-made page references: full markup, styles and behaviors. Refactor into React, do not copy verbatim. | + +The `.design/system/` folder (tokens, `kit.html`, artifacts) is brand-system material; +at page build time use the **canonical tokens below** rather than the `--brand-*` +derived tokens. + +## Tech Stack + +- Vite + React 19 + TypeScript (`"strict": true`) +- React Router v6 +- Zustand — **auth tokens and UI state only**, never server-fetched data +- Native `fetch` API client (no axios) +- Vanilla CSS with custom properties (no Tailwind, no CSS-in-JS, no CSS frameworks) +- Vitest + React Testing Library for tests +- ESLint (typescript/react/hooks) + Prettier (print width 100, single quotes, trailing commas, semicolons) + +## Design System + +### Canonical CSS tokens (`src/styles/tokens.css`) + +| Token | Value | Usage | +| --- | --- | --- | +| `--bg` | `#faf7f2` | Page background (cream) | +| `--surface` | `#f5f0e8` | Cards, raised blocks (warm white) | +| `--fg` | `#1a1610` | Primary text, primary buttons (ink) | +| `--muted` | `#3d3428` | Secondary text (ink-soft) | +| `--fg-muted` | `#7a6e5f` | Tertiary text, captions (ink-muted) | +| `--accent` | `#c9a84c` | Highlights, active states, emblems (gold) | +| `--accent-light` | `#e8ca7a` | Hover glow, gold-light | +| `--accent-dim` | `#8b6914` | Emphasis inside quote text | +| `--hairline` | `rgba(26, 22, 16, 0.10)` | Faint structural rules, grid gaps | +| `--hairline-strong` | `rgba(26, 22, 16, 0.18)` | Input underlines, card borders | +| `--border` | `rgba(201, 168, 76, 0.25)` | Landing header/footer rules | +| `--font-display` | `'Cormorant Garamond', Georgia, serif` | Headings, numerals | +| `--font-body` | `'Tenor Sans', 'Helvetica Neue', Arial, sans-serif` | Body, labels, buttons | +| `--radius` | `8px` | All corners | +| `--baseline` | `8px` | Spacing unit | + +### Layout rules + +- **8px baseline grid** for spacing and padding; generous padding everywhere. +- **Extreme whitespace + centered alignment**. One primary purpose per screen. +- **1px hairlines** for structural division (horizontal rules, stat strips divided by + grid `gap: 1px` over a hairline background). +- Buttons: uppercase, letterspacing `0.16–0.22em`, 10px font-size, `--radius` corners. + Primary = `--fg` background / `--bg` text; hover → `--accent`. Secondary = transparent, + `1px solid var(--hairline-strong)`. +- Inputs: underline style (`border-bottom: 1px solid var(--hairline-strong)`), + transparent background, gold animated focus line (`scaleX`), no boxed inputs. + +### Signature UI details (all screens) + +- **Custom cursor**: gold dot (6px) + trailing ring (32px) that grows to 48px over + interactive elements. Hide on touch devices (`@media (hover: none), (pointer: coarse)`) + — these also need `* { cursor: auto !important; }`. +- **Grain overlay**: fixed `body::before` with the fractal-noise SVG data-URI, `opacity: 0.035`, `mix-blend-mode: multiply`. +- **Fade-up reveals**: `.reveal { opacity: 0; transform: translateY(14px); }` → `.is-in`; + staggered `transition-delay` via IntersectionObserver. +- **Logo**: `Malenia` — Cormorant Garamond, uppercase, + `letter-spacing: 0.35em`; the `e` is `var(--accent)`. +- **Emblem**: the 90×90 geometric SVG (ring + diamond + cardinal marks), gold stroke. +- Respect `prefers-reduced-motion`: disable cursor animation, grain is fine (static), + use plain opacity transitions without translate. + +### Typography + +- **Display/headings:** Cormorant Garamond (weights 400, 500, 600 + italics). Large + sizes with `line-height 1.1–1.25` and slight negative `letter-spacing`. +- **Body:** Tenor Sans. +- **CRITICAL — Cyrillic fonts:** the self-hosted `.design/fonts/*.woff2` subsets have + `unicode-range` for **Latin Extended only** (no `U+0400–04FF`) and will render Russian + text with fallback glyphs. The interface is Russian, so load fonts from **Google Fonts** + exactly as the `.ref` pages do: + `https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@400;500;600&family=Tenor+Sans&display=swap` + (with `preconnect` links). Self-hosting is only acceptable after adding Cyrillic subsets. + +## Brand Voice & Copy (from `.info/ToV.md`) + +- All interface copy is **Russian**. No placeholders left in English. +- Tone: restrained, archival and minimal on the surface; honest, ironic, occasionally + snarky underneath. Plain wording, no corporate clichés, no hype ("revolutionize", + "unleash the power", "best-in-class" are banned). +- Service attitude: "включил и забыл" (set-and-forget), transparency about incidents, + engineering-first, anti-censorship. +- Tagline: **«Свобода. Практика. Простота.»** +- Landing quote block: rotate randomly through the Russian quotes array from + `.ref/landing.html`; render the second line as an italic ``. + +## Routing (`src/App.tsx`) + +| Path | Element | Notes | +| --- | --- | --- | +| `/` | `Landing` | Existing marketing page | +| `/login` | `LoginPage` | Credentials only. `?returnTo=` preserved for post-auth redirect | +| `/plan` | `PlanPage` | Calculator + confirm → checkout | +| `/account` | `AccountPage` | Protected: redirect to `/login` when unauthenticated | + +## Backend API (mirrors `.info/openapi.json` — the only source of truth) + +Base: backend routes have **no `/api/` prefix**. In dev, `vite.config.ts` proxies +`/auth`, `/plans`, `/orders`, `/users`, `/payments` to `http://127.0.0.1:8000`. +In prod the reverse proxy serves same-origin. Never hardcode absolute URLs. + +### Types (`src/types.ts`) + +```ts +type Provider = 'credentials' | 'telegram' | 'api'; + +interface UserInfo { + username: string | null; + telegram_id: string | null; + referal_code: string; +} + +interface LoginResponse { // POST /auth/login + access_token: string; + refresh_token: string; + expires_at: number; // epoch seconds + user: UserInfo; +} + +interface Tokens { // POST /auth/refresh + access_token: string; + refresh_token: string; + expires_at: number; +} + +interface AddonData { // inside GET /plans/ + id: string; + name: string; + price: number; + free_threshold: number; +} + +interface PricingPlans { // GET /plans/ + device_price: number; + addons: AddonData[]; +} + +interface OrderDetails { // POST /orders/checkout body + devices: number; + addons: string[]; // addon ids + duration_days: number; +} + +interface CheckoutResponse { // POST /orders/checkout → 201 + order_id: string; + total_amount: number; + bonus_paid: number; + amount_to_pay: number; + payment_link: string | null; +} + +interface Device { // GET /users/subscription/hwid + os: string | null; + model: string | null; + client: string | null; + hwid: string; +} +``` + +### Endpoint table + +| Method | Path | Auth | Purpose | +|---|---|---|---| +| POST | `/auth/signup` | – | Register, body `{provider, username?, password?, telegram_id?, referal_code?}` | +| POST | `/auth/login` | – | Login, body `{provider:'credentials', username, password}` | +| POST | `/auth/refresh?refresh_token=&iss=` | – | New token pair; `iss` is the provider | +| GET | `/plans/` | – | Pricing: `device_price` + addons | +| POST | `/orders/checkout` | yes | Create order → `payment_link` | +| GET | `/users/me` | yes | `UserInfo` | +| GET | `/users/subscription` | yes | Subscription state (schema is `{}` — shape to be confirmed at implementation) | +| GET | `/users/subscription/hwid` | yes | `Device[]` | +| DELETE | `/users/subscription/hwid?hwid=` | yes | Unlink a device | +| POST | `/payments/pally/result` | – | Payment callback — backend-internal, frontend never calls it | + +### Auth flow + +- **Credentials only.** Sign up / sign in are username + password. Telegram auth is + explicitly **out of scope** for now (linking ships later). The API *accepts* + `provider: telegram`, but the frontend must only use `credentials`. +- Tokens stored via a `useLocalStorage`-style hook under keys + `malenia.access`, `malenia.refresh`, `malenia.expires_at` (epoch seconds). +- The API client injects `Authorization: Bearer ` on every request. +- On **401**: try `POST /auth/refresh?refresh_token=…&iss=credentials` once; on success + retry the original request, on failure clear tokens and redirect to `/login`. + Guard against refresh loops. +- **Signup** may include `referal_code` — expose an optional field on the signup form + and pass it through. + +### API client conventions + +- Generic `request()` helper; throws `Error` with the backend `detail` for non-2xx. +- 201 responses return parsed JSON; no 204s in this API. +- Errors surface as **toast notifications** (inline errors only for form validation). + +## Pages — implementation notes (from `.ref/`) + +### Landing (`/`) — `.ref/landing.html` + +Keep the overall structure and design. **Apply the existing page's corrections:** + +- **Header** gains navigation links (`