# artsunami — Charte graphique & Design System

Référence unique, portable, à déposer dans n'importe quelle app pour reproduire
l'identité **artsunami**. Toutes les valeurs correspondent au produit en
production (Tailwind + CSS variables). Les blocs de code sont **prêts à copier**.

- **Tokens machine** : `artsunami-tokens.json` (W3C DTCG) · `artsunami-tokens.tokens-studio.json` (Figma / Tokens Studio)
- **Logos** : `artsunami-logo-{icon,full}-{black,white,spectrum}.{svg,png}`
- **Guide imprimable** : `artsunami-design-system.pdf` (paysage) · `…-a4-portrait.pdf`

---

## 1. Marque

| | |
|---|---|
| **Nom / wordmark** | `artsunami` — **toujours en minuscules**, jamais capitalisé, jamais dans une autre police que celle du wordmark (Outfit Bold). |
| **Tagline** | The studio for generative art |
| **Positionnement** | Create, collect and sell generative & interactive art, fully on-chain |
| **URL** | https://artsunami.com |

**Boilerplate (presse, prêt à citer)**
> artsunami is the studio for generative art. Creators release code-driven collections — generative art, games, trading cards and PFPs — where every token is a unique seed rendered live in the browser rather than a stored image. There is no subscription and no custody: keys and funds stay with the creator, and every release carries a public authenticity certificate. Collectors mint and own directly, with creator royalties honoured on resale.

**Voix** : confiante, précise, maker-to-maker. On dit *generative*, *seed*,
*authenticity certificate*, *self-custody*. On évite le hype et le jargon gratuit.

---

## 2. Logo

Le **wave mark** (la vague) + le wordmark `artsunami`.

- **Déclinaisons** : spectrum (primaire), noir (mono), blanc (sur fond sombre).
- **Clear space** : au moins la hauteur de la boucle interne de la marque, sur les 4 côtés.
- **Lockup horizontal** : marque + wordmark (Outfit Bold, minuscules), écart ≈ 20 % de la hauteur de la marque.

**À ne pas faire** : recolorer hors noir/blanc/spectrum · pivoter, étirer, ombrer, contourner · changer la police du wordmark ou le capitaliser · poser la marque spectrum sur un fond chargé ou peu contrasté.

---

## 3. Couleur

### Ink — rampe neutre
| Token | Hex | Usage |
|---|---|---|
| `ink.900` | `#0B0B0F` | Texte principal · fill CTA (light) |
| `ink.800` | `#15151C` | |
| `ink.750` | `#1E1E29` | Surface carte (dark) |
| `ink.700` | `#1F1F29` | |
| `ink.600` | `#2A2A35` | |
| `ink.500` | `#5B5B6B` | Texte atténué |
| `ink.400` | `#7B7B8A` | |
| `ink.300` | `#A6A6B3` | Placeholder |
| `ink.200` | `#D2D2DC` | |
| `ink.100` | `#F4F4F7` | Filets · fonds doux |
| `ink.50`  | `#FAFAFB` | Fond de page (light) |

### Accent & sémantique
| Token | Hex | Usage |
|---|---|---|
| `accent` | `#7C5CFF` | Violet de marque — liens, focus, CTA accent (dark) |
| `accent.soft` (light) | `#E8E1FF` | Teinte de panneau accent, thème clair |
| `accent.soft` (dark) | `#1F1938` | Teinte de panneau accent, thème sombre |
| `text-accent` (dark) | `#A996FF` | Texte accent relevé pour le contraste sur sombre |
| `success` | `#22C55E` | |
| `warn` | `#F59E0B` | |
| `danger` | `#EF4444` | |

### Surfaces / fondations
| Rôle | Light | Dark |
|---|---|---|
| Fond de page | `#FAFAFB` | `#0B0B0F` |
| Texte | `#0B0B0F` | `#F5F5F7` |
| Halos radiaux (fond) | `#EDE7FF` (lavande) + `#DCEBFF` (bleu) | `#1F1A35` + `#131826` |

### Brand spectrum
Le dégradé animé qui traverse le logo, les contours de carte et les anneaux de CTA.

```
#FF2D5C 0% · #FF1F8A 12% · #D81BD3 25% · #7C5CFF 37% · #00D4FF 50% · #00FF9B 62% · #FFC700 75% · #FF8A00 87% · #FF2D5C 100%
```

```css
--brand-spectrum: linear-gradient(90deg,
  #FF2D5C 0%, #FF1F8A 12%, #D81BD3 25%, #7C5CFF 37%,
  #00D4FF 50%, #00FF9B 62%, #FFC700 75%, #FF8A00 87%, #FF2D5C 100%);
```

---

## 4. Typographie

| Rôle | Police | Détails |
|---|---|---|
| **Display** | Mozilla Headline | Titres H1–H3. Variable (axe 200–700), la marque utilise 800–900. `--font-display` |
| **Texte / UI / wordmark** | Outfit | Corps, UI, adresses & token IDs (le mono reste sur Outfit pour ne pas casser le rythme). Poids 400 / 500 / 700. `--font-sans` |
| **Partenaire (only)** | Silkscreen | Réservé au wordmark partenaire Beatsnack. **Hors** échelle artsunami. |

- **Racine** : `font-size: 17px`, `line-height: 1.6`, `font-feature-settings: "ss01","cv11"`, `-webkit-font-smoothing: antialiased`.
- Les titres utilisent un `clamp()` fluide ; les tailles ci-dessous sont le **plafond desktop**.

| Style | Police · poids | Taille (clamp) | Interligne | Tracking |
|---|---|---|---|---|
| H1 | Mozilla Headline · 900 | `clamp(1.75rem, 6vw, 3.5rem)` | 1.08 | −0.02em |
| H2 | Mozilla Headline · 900 | `clamp(1.35rem, 4vw, 2.25rem)` | 1.18 | −0.02em |
| H3 | Mozilla Headline · 800 | `clamp(1.15rem, 3vw, 1.5rem)` | 1.25 | −0.01em |
| Body | Outfit · 400 | `1rem` (17px) | 1.6 | 0 |
| Body medium | Outfit · 500 | `1rem` | 1.6 | 0 |
| Label / eyebrow | Outfit · 700 · UPPERCASE | `0.75rem` | 1.2 | 0.06em |

---

## 5. Fondations

| Token | Valeur | Note |
|---|---|---|
| **Radius** | `2px` | Coin net **global** sur toutes les surfaces (cartes, boutons, inputs, pills). |
| Radius avatar | `9999px` | **Seule** exception : les avatars sont ronds. |
| Racine | `17px` | Base typographique. |
| Easing | `cubic-bezier(0.22, 1, 0.36, 1)` | L'unique courbe de marque (`ease-swift`). |
| Durées | `300ms` / `500ms` | Transitions courtes / longues. |
| Ring-slide | `3500ms` | Balayage du spectrum au survol. |
| Story-spin | `3000ms` | Rotation de l'anneau « stories ». |

Le mouvement respecte `prefers-reduced-motion` (animations coupées).

### Élévation (ombres)
```css
--shadow-soft:     0 10px 40px -10px rgba(20,20,40,.10), 0 4px 16px -8px rgba(20,20,40,.06);
--shadow-card:     0 24px 60px -20px rgba(60,60,120,.18), 0 8px 24px -12px rgba(60,60,120,.10);
--shadow-cardHover:0 36px 90px -24px rgba(80,80,160,.28), 0 12px 32px -10px rgba(80,80,160,.14);
--shadow-glow:     0 0 0 6px rgba(124,92,255,.10), 0 18px 60px -10px rgba(124,92,255,.30);
```
> ⚠️ Pour un **PDF / export image**, remplacer ces grandes ombres floues par des bordures fines : certains moteurs les rastérisent en blocs.

---

## 6. Composants (classes)

Classes `@layer components` réutilisables (voir le bloc Tailwind au §8).

| Classe | Rôle |
|---|---|
| `.card` | Surface élevée, `shadow-card`, coin 2px, anneau spectrum animé au survol. |
| `.card-flat` | Carte simple `shadow-soft`, bordure fine en dark. |
| `.btn` | Base bouton (pill, gap, ease-swift). |
| `.btn-primary` | CTA noir/texte blanc (s'inverse en blanc/noir en dark), anneau spectrum au survol. |
| `.btn-accent` | CTA noir (violet en dark), halo rose, anneau spectrum au survol. |
| `.btn-soft` | Bouton secondaire sur fond `ink-100`. |
| `.btn-ghost` | Bouton texte, hover `ink-100`. |
| `.pill` | Étiquette arrondie `ink-100`, `text-xs`. |
| `.input` | Champ `shadow-soft`, focus `ring-2 ring-accent/50`. |
| `.label` | Eyebrow `text-xs` bold UPPERCASE `tracking-wider`. |
| `.divider` | Filet dégradé horizontal. |
| `.grid-bg` | Fond quadrillé subtil (violet 6 %). |
| `.avatar` / `.avatar-ring` | Disque rond (exception au coin 2px) + anneau. |

**Perf — art génératif** : ne jamais monter des dizaines d'iframes de rendu live en même temps. Utiliser un poster statique + n'animer qu'à l'écran, et **plafonner** le nombre d'iframes simultanés (≈ 4) pour éviter l'OOM du renderer.

---

## 7. CSS variables (fondation, à copier)

```css
:root {
  color-scheme: light;
  /* Brand */
  --accent: #7C5CFF;
  --accent-soft-rgb: 232 225 255;      /* #E8E1FF */
  /* Ink */
  --ink-900:#0B0B0F; --ink-800:#15151C; --ink-750:#1E1E29; --ink-700:#1F1F29;
  --ink-600:#2A2A35; --ink-500:#5B5B6B; --ink-400:#7B7B8A; --ink-300:#A6A6B3;
  --ink-200:#D2D2DC; --ink-100:#F4F4F7; --ink-50:#FAFAFB;
  /* Semantic */
  --success:#22C55E; --warn:#F59E0B; --danger:#EF4444;
  /* Type */
  --font-sans: "Outfit", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto;
  --font-display: "Mozilla Headline", "Outfit", system-ui, sans-serif;
}
.dark { color-scheme: dark; --accent-soft-rgb: 31 25 56; /* #1F1938 */ }
.dark .text-accent { color:#A996FF; }

html, body {
  background:
    radial-gradient(1200px 600px at 80% -10%, #EDE7FF 0%, transparent 60%),
    radial-gradient(1000px 500px at -10% 20%, #DCEBFF 0%, transparent 55%),
    #FAFAFB;
  color:#0B0B0F;
  font-family: var(--font-sans);
  font-size:17px; line-height:1.6;
  font-feature-settings:"ss01","cv11"; -webkit-font-smoothing:antialiased;
}
.dark html, .dark body {
  background:
    radial-gradient(1200px 600px at 80% -10%, #1F1A35 0%, transparent 60%),
    radial-gradient(1000px 500px at -10% 20%, #131826 0%, transparent 55%),
    #0B0B0F;
  color:#F5F5F7;
}
h1,h2,h3 { font-family: var(--font-display); font-weight:900; letter-spacing:-0.02em; }
h1 { font-size:clamp(1.75rem,6vw,3.5rem); line-height:1.08; }
h2 { font-size:clamp(1.35rem,4vw,2.25rem); line-height:1.18; }
h3 { font-size:clamp(1.15rem,3vw,1.5rem); line-height:1.25; font-weight:800; }
```

**Polices** : Outfit (Google Fonts) · Mozilla Headline (auto-hébergée, woff2 —
https://github.com/mozilla/mozilla-headline).

---

## 8. Tailwind config (à copier dans `tailwind.config.ts`)

```ts
import type { Config } from "tailwindcss";

const config: Config = {
  content: ["./src/**/*.{ts,tsx}"],
  darkMode: "class",
  theme: {
    // Coin net 2px partout (remplace toute l'échelle de radius).
    borderRadius: {
      none: "0px", sm: "2px", DEFAULT: "2px", md: "2px",
      lg: "2px", xl: "2px", "2xl": "2px", "3xl": "2px", full: "2px"
    },
    extend: {
      colors: {
        ink: {
          900:"#0B0B0F",800:"#15151C",750:"#1E1E29",700:"#1F1F29",600:"#2A2A35",
          500:"#5B5B6B",400:"#7B7B8A",300:"#A6A6B3",200:"#D2D2DC",100:"#F4F4F7",50:"#FAFAFB"
        },
        accent: {
          DEFAULT:"#7C5CFF",
          soft:"rgb(var(--accent-soft-rgb) / <alpha-value>)"
        },
        success:"#22C55E", warn:"#F59E0B", danger:"#EF4444"
      },
      fontFamily: {
        sans:["var(--font-sans)","Outfit","ui-sans-serif","system-ui","-apple-system","Segoe UI","Roboto"],
        display:["var(--font-display)","Mozilla Headline","Outfit","system-ui"],
        mono:["var(--font-sans)","Outfit","ui-monospace","SFMono-Regular"]
      },
      boxShadow: {
        soft:"0 10px 40px -10px rgba(20,20,40,0.10), 0 4px 16px -8px rgba(20,20,40,0.06)",
        card:"0 24px 60px -20px rgba(60,60,120,0.18), 0 8px 24px -12px rgba(60,60,120,0.10)",
        cardHover:"0 36px 90px -24px rgba(80,80,160,0.28), 0 12px 32px -10px rgba(80,80,160,0.14)",
        glow:"0 0 0 6px rgba(124,92,255,0.10), 0 18px 60px -10px rgba(124,92,255,0.30)"
      },
      transitionTimingFunction: { swift: "cubic-bezier(0.22, 1, 0.36, 1)" }
    }
  },
  plugins: []
};
export default config;
```

### Bloc composants (à copier dans `globals.css`)

```css
@layer components {
  .card { @apply bg-white/85 dark:bg-ink-750/95 backdrop-blur-md rounded-3xl shadow-card
          transition-[box-shadow,transform] duration-500 ease-swift; }
  .card:hover { @apply shadow-cardHover; transform: translateY(-3px) scale(1.005); }
  .card-flat { @apply bg-white dark:bg-ink-750 rounded-2xl shadow-soft; }

  .btn { @apply inline-flex items-center justify-center gap-2 rounded-full px-6 py-3
         text-base font-medium transition-all duration-300 ease-swift select-none; }
  .btn:hover { transform: translateY(-1px); }
  .btn-primary { background:#0B0B0F; color:#fff; box-shadow:0 8px 24px -10px rgba(0,0,0,.4); }
  .dark .btn-primary { background:#fff; color:#0B0B0F; }
  .btn-accent { background:#0B0B0F; color:#fff; }
  .dark .btn-accent { background:#7C5CFF; color:#fff; }
  .btn-ghost { @apply text-ink-700 dark:text-ink-200 hover:bg-ink-100 dark:hover:bg-ink-700; }
  .btn-soft { @apply bg-ink-100 dark:bg-ink-600 text-ink-900 dark:text-white
              hover:bg-white dark:hover:bg-ink-500 hover:shadow-soft; }

  .pill { @apply inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-medium
          bg-ink-100 dark:bg-ink-700 text-ink-700 dark:text-ink-100; }
  .input { @apply w-full rounded-2xl bg-white dark:bg-ink-800 dark:text-white px-5 py-3.5
           text-base shadow-soft outline-none placeholder:text-ink-300
           focus:shadow-card focus:ring-2 focus:ring-accent/50 transition-shadow; }
  .label { @apply text-xs font-bold text-ink-700 dark:text-ink-200 uppercase tracking-wider; }
  .divider { @apply h-px w-full bg-gradient-to-r from-transparent via-ink-100 dark:via-ink-700 to-transparent; }

  .avatar { border-radius:9999px; overflow:hidden; background:transparent; }
}
```

> Sur Next.js, charger Outfit via `next/font/google` et Mozilla Headline via
> `next/font/local`, en exposant `--font-sans` / `--font-display`.

---

_artsunami — Charte graphique & Design System · reproduit le produit en production._
