# Novelia, agence web SaaS

> **Branding** : nom **Novelia**, domaine actuel **agence-novelia.fr** (acquis chez Ionos, DNS géré par Cloudflare). Domaine cible visé : **novelia.fr** (à acquérir plus tard). Les constantes `BRAND_NAME` et `BRAND_DOMAIN` dans [lib/brand.ts](lib/brand.ts) restent le point unique de changement. Le dossier physique du projet sur disque s'appelle encore `Corelia/` (historique), ainsi que le `"name"` du `package.json`, sans impact UI.

## Vision

Novelia est une **agence web française** qui vend des **sites sur-mesure haute performance en abonnement mensuel tout-inclus**. Pas de WordPress, pas de CMS bricolé, pas de page builder. Chaque site est codé proprement (stack moderne) pour la performance, la sécurité et la maintenance long terme.

L'argument central : **« un site pro, sans budget pro »**. Le client paie un abonnement mensuel qui couvre **tout** : conception, développement, hébergement, protection (Cloudflare), maintenance, suivi analytique. Pas de devis à 5 chiffres, pas de surprise, pas de frais cachés.

La francité reste un atout (RGPD natif, support en français, hébergement sur dédié européen) mais le différenciateur n°1 est **le modèle économique + la qualité technique**, pas le pavillon français.

## État actuel — maquette visuelle aboutie

Le travail réalisé est une **maquette navigable** avec données 100 % mockées (aucun backend, aucune persistance). Le but était de visualiser produit + charte avant la phase technique. La refonte UI majeure du 2026-05-13 a porté le projet à un niveau quasi production sur le rendu visuel et le responsive.

**Ce qui est en place** :
- Site vitrine multi-pages : Accueil, L'essentiel (`/essentiel`), Contact, Connexion, Tarifs (`/tarifs`), 3 pages Expertises (`/expertises/site-internet`, `/expertises/seo-geo`, `/expertises/e-commerce`), Réalisations (`/realisations` + `/realisations/[slug]`)
- Accueil : hero épuré + intro avec H2 « Avoir un site ne suffit plus » + mockup PageSpeed Insights animé (4 jauges 93/100/100/100) + 4 piliers + Process scroll-linked (boule lumineuse qui suit le scroll) + section « Pourquoi Novelia ? » split asymétrique
- Pages Expertises premium : hero centré + featurette avec mockup smartphone + cards + sections « Pour qui » / « Au quotidien » / « Ce qu'on ne fait pas » + FAQ + CTA. Triptyque éditorial : **site-internet** = générer des clients, **seo-geo** = être trouvé, **e-commerce** = transformer en ventes. Composants partagés dans [components/marketing/expertise-blocks.tsx](components/marketing/expertise-blocks.tsx).
- Page Tarifs : 3 plans (Présence 49,99 € / Développement à partir de 99 € highlight / E-commerce à partir de 199 €) + pills réassurance + section « Tout est inclus » + comparatif « Ailleurs / Avec nous » + FAQ + JSON-LD OfferCatalog
- Portail client (`/portail`) : tableau de bord analytics, abonnement multi-sites, factures, support (liste + détail + nouveau ticket), paramètres (profil + 2FA + sessions / équipe avec rôles / confidentialité RGPD)
- Espace agence (`/atelier-novelia`, renommé depuis `/admin` le 2026-05-23 pour réduire le scan automatisé · `noindex` au niveau metadata + robots.ts) : tableau de bord MRR/CA, clients, factures, tickets (liste + détail), réalisations (manager avec IA Anthropic), paramètres (profil / équipe agence / intégrations / facturation)
- Page 404 custom ([app/not-found.tsx](app/not-found.tsx)) avec CTA accueil + contact + pages utiles
- Switcher de site multi-sites (URL searchParam) côté portail
- Animations sobres (Reveal sur intersection observer) sur les pages marketing uniquement
- SEO/sécurité : headers HSTS / COOP / Permissions-Policy / X-Powered-By retiré dans [next.config.ts](next.config.ts), [app/sitemap.ts](app/sitemap.ts) + [app/robots.ts](app/robots.ts), métadonnées propres par page, JSON-LD Organization + FAQPage + OfferCatalog. Connexion en `noindex`. Skip-to-content link dans le root layout.
- Footer aligné navbar : 4 colonnes + drapeau bleu-blanc-rouge + « Entreprise française »
- Build Next.js 16 + Tailwind v4 propre

**Dev server, mémoire** : Turbopack 16 + Tailwind v4 ont tendance à exploser en RAM. Le script `dev` plafonne Node à 4 GB via `cross-env NODE_OPTIONS=--max-old-space-size=4096`. Si crash quand même, vider `.next/` ou basculer sur webpack avec `next dev --turbopack=false`.

**Ce qui n'est pas encore là** : authentification réelle, base de données, intégrations API (Google, Stripe), génération d'aperçus prospects, déploiement. Les visuels des mockups Expertises (`/visuals/atelier-menuiserie.jpg`, `/visuals/vase-calanque.png`) sont référencés dans le code mais à fournir manuellement.

## Refonte UI 2026-05-13 (récapitulatif)

Cette refonte a tout aligné sur un design system rigoureux et corrigé les patterns AI génériques. Détails complets dans la memory `project_refonte_ui_2026-05-13`. Synthèse :

- **Design system étendu** : palettes complètes `stone-50→950` et `amber-50→900`, échelles typo strictes (xxs 11 → 7xl 72), radius (xs→2xl), shadows (xs→xl) **teintées warm** (rgba(12, 6, 0, …) au lieu de noir neutre), focus ring stratifié, `--touch-min: 44px`. Cf. [app/globals.css](app/globals.css).
- **Primitives partagées** : `Button` (touch ≥ 44 px mobile, loading, focus ring), `Input`, `Textarea`, `Select` (chevron custom), `Field` (label + hint + erreur + aria-describedby), `Avatar` (variantes `corelia`/`client`, aplat sans gradient), `Skeleton`. Cf. [components/ui/](components/ui/).
- **Mobile shell portail/admin** : `MobileNavProvider` + `MobileNavTrigger` ([components/shell/mobile-nav.tsx](components/shell/mobile-nav.tsx)) avec sheet drawer plein hauteur. Burger auto-injecté dans `Topbar` via context. Sidebar et Topbar passés en aplat opaque (glass retiré sauf surfaces flottantes : navbar pill marketing, dropdowns, sheets).
- **Tables responsives** : 6 tables refondues avec `<table>` desktop ≥ md et stack de cards en dessous (factures portail/admin, clients, tickets, équipes, factures récentes dashboard admin).
- **Marketing responsive renforcé** : padding mobile `px-4 sm:px-6 md:px-10` partout, hero compactés mobile (pt/pb adaptatifs), titres responsifs (text-3xl sm:text-4xl md:text-7xl sur les h1), grilles adaptées (plus de `grid-cols-3` qui écrasent sous 360 px).
- **Avatars sans gradient** : composant [components/ui/avatar.tsx](components/ui/avatar.tsx) à aplat. Variante `corelia` (ambre signé, agents support) vs `client` (warm neutre).
- **Qualité UI** : skip-to-content link, custom 404, `min-h-dvh` partout (fix iOS Safari), smooth scroll global, `text-wrap: balance` automatique sur h1-h4, `text-wrap: pretty` sur body, tabular nums automatique sur tables, favicon `app/icon.png` + apple-icon, logo image PNG avec contour ambre signature sur navbar.

Maquettes HTML de référence dans [mockups/](mockups/) et servies aussi en [public/mockups/](public/mockups/). Note : les mockups HTML statiques sont restés sur la palette dark d'origine, ils ne sont plus représentatifs du rendu actuel mais servent encore de référence structurelle.

## Bascule palette claire 2026-05-21 (récapitulatif)

Pivot direction art : abandon du dark au profit d'une palette **papier crème + bronze profond** pour porter le positionnement « pro, abordable, naturel, rassurant ». Le dark connotait trop « tech-luxe », le clair ouvre l'éditorial et la confiance.

- **Tokens inversés** dans [app/globals.css](app/globals.css) : `--color-background: #faf7f2`, `--color-surface: #ffffff`, `--color-text: #1c1917`, `--color-accent: #92400e` (bronze amber-800, dense, lisible AA). Détails dans la section Charte graphique ci-dessous.
- **Ombres** réécrites en `rgba(28, 25, 23, X)` allégées (le clair ne pardonne pas les drop-shadows lourdes).
- **Grain overlay** passé en `mix-blend-mode: multiply` warm avec opacité remontée à 5 % pour conserver la texture papier.
- **Logo** : le N PNG ayant un fond noir, il est désormais **toujours posé dans un cartouche stone-900** qui devient une signature visuelle « sceau d'atelier » réutilisable (badges, numéros de section, witness « Made in France »).
- **Refactor mécanique** des composants qui hardcodaient encore `bg-stone-900` etc. pour passer aux tokens sémantiques `bg-surface`, `bg-surface-2`, `text-text`, `text-text-muted`.
- **PageSpeed mockup**, charts Recharts, `LighthousePanel` et toute surface mockup PSI ramenés au fond blanc (cohérent avec la vraie interface PageSpeed Insights).

## Pivot directionnel « signature atelier » (2026-05-21, suite à audit impeccable)

Audit `impeccable critique` réalisé le 2026-05-21, score initial **27/40**. Diagnostic : le projet tombait dans la lane saturée « editorial-typographic AI 2024-2026 » avec 45 occurrences du tic `<span className="italic text-accent-hi">...</span>` sur les titres + 17 halos décoratifs `blur-[120px]` identiques d'une page à l'autre. Verdict : un dev pourrait croire que ça sort de v0.

Décisions prises :
- **Italic-accent réduit à 1 seule occurrence** sur tout le site : `app/(marketing)/page.tsx:32` (« On s'occupe du reste. » du hero accueil = LA signature). Partout ailleurs, le span est supprimé : le `font-editorial` (Fraunces) du h1/h2 parent reste, sans italique ni shift de couleur.
- **Halos blur supprimés** sur 14 pages, gardés uniquement sur l'accueil + footer.
- **Pull-quotes orphelines supprimées** (`tarifs.tsx` « rien à gérer », `Heart` icon du CtaPanel).
- **Signature visuelle atelier** introduite via deux nouveaux composants partagés :
  - [components/marketing/section-stamp.tsx](components/marketing/section-stamp.tsx) : `<SectionStamp number="01" label="Notre méthode" />`. Cartouche stone-900 + bordure bronze qui réplique le langage du logo. À utiliser à la place de `<Badge tone="muted">` sur les ouvertures de section éditoriales.
  - [components/marketing/torn-edge.tsx](components/marketing/torn-edge.tsx) : `<TornEdge side="bottom" />`. Séparateur SVG « papier déchiré » entre sections, suggère qu'on tourne une page d'un cahier d'atelier.
- **Grain papier amplifié** dans [app/globals.css](app/globals.css) : opacity 0.05 → 0.12, baseFrequency 0.85 → 0.65 (grain plus organique), seed différent. Plus une classe utilitaire `.paper-card` pour appliquer une texture papier locale sur un container spécifique.
- **Accent bronze conservé** sur `#92400e` (amber-800) malgré la lecture « bordeaux-luxe » identifiée à l'audit, parce que le contexte « atelier » est désormais porté par la signature visuelle (cartouches, papier déchiré, grain) et plus seulement par la couleur.

## Modèle économique

- **Abonnement mensuel tout-inclus.** Tarifs dans la maquette : **Présence 49,99 €**, **Développement à partir de 99 €** (le plus choisi), **E-commerce à partir de 199 €**.
- **Pas de frais d'installation**.
- **Sans engagement de durée**, résiliable à tout moment.
- **Multi-sites** : un compte client peut avoir plusieurs sites, facturation cumulée sur un seul prélèvement mensuel.
- **Récupération du site** en cas de résiliation : politique non définie, à trancher tôt.

## Surfaces du projet

Le projet couvre **trois surfaces distinctes** hébergées sur le même dédié :

1. **Site vitrine public** (`novelia.fr`), marketing, SEO, démo, tarifs, prise de contact.
2. **Portail client/admin** (`app.novelia.fr` ou similaire), l'application SaaS authentifiée. Pièce la plus technique, priorité de dev.
3. **Sites clients** (sous-domaines ou domaines propres apportés par le client), sites livrés à chaque client, isolés, derrière Cloudflare.

## Portail, fonctionnalités cibles

Côté **client** (l'utilisateur final qui paie l'abonnement) :

- Authentification sécurisée (email + mot de passe, 2FA TOTP, à valider entre Better Auth et Auth.js v5).
- Facturation : historique, factures PDF, statut (payée / en attente / impayée), paiement en ligne (Stripe).
- Suivi du site, pièce centrale et différenciatrice :
  - **Google Search Console API** (clics, impressions, position moyenne, requêtes).
  - **Google Analytics 4 Data API** (sessions, utilisateurs, pages vues, sources, durée).
  - **Google PageSpeed Insights API** (Lighthouse mobile + desktop, Core Web Vitals).
  - Tableau de bord avec graphiques (clics, impressions, sessions sur 30 j, top requêtes, top pages, sources de trafic).
- **Synthèse IA en option** (Claude API), **non prioritaire** : le portail démarre **sans IA**, uniquement chiffres bruts + deltas + top-listes. Phase 2 si retour client le justifie.
- Tickets / support : ouvrir une demande, suivre les échanges, fil de conversation.
- Profil & paramètres : profil personnel, mot de passe, 2FA, équipe avec 3 rôles (Administrateur / Lecteur / Comptable), confidentialité (export RGPD + suppression).

Côté **admin** (Novelia, opérateur) :

- Vue de tous les clients, leurs sites, statuts d'abonnement, MRR.
- Tableau de bord CA avec breakdown Mois (par jour) / Année (par mois) / Tout.
- Gestion des tickets entrants (assignation, statut, note interne vs réponse client).
- Gestion des réalisations avec assistant éditorial IA (Claude) : crawl URL → extraction → génération de tagline, brief, delivered, highlights, sector, type, context.
- Paramètres : profil propriétaire + 2FA, équipe agence avec 4 rôles, intégrations, facturation (raison sociale, SIRET, IBAN, numérotation).
- À venir : provisionnement d'un nouveau client, fiche client détaillée (`/atelier-novelia/clients/[id]`).

## Acquisition, générateur d'aperçus

L'angle de prospection : **envoyer au prospect un aperçu de son futur site avant tout engagement**. Workflow :
1. Identifier le prospect (entreprise locale, artisan, profession libérale).
2. À partir de ses infos publiques (site existant, fiche Google, secteur), générer un site de démonstration personnalisé.
3. Envoyer un lien privé (`preview.novelia.fr/{slug}`) avec le rendu.
4. Discussion commerciale à partir d'un livrable concret.

Implications techniques :
- Système de templates paramétrables côté code (pas un page builder).
- Pipeline de génération assisté par IA pour produire le copy initial à partir d'un brief minimal.
- Page d'aperçu avec watermark/CTA « activer ce site ».

À traiter **après** le portail. L'architecture du portail doit anticiper qu'un « prospect » et un « site en preview » sont des entités du modèle.

## Stratégie d'intégration APIs Google

**Décidé** : un seul **service account Google Cloud** côté Novelia pour interroger Search Console + GA4 + PageSpeed sur tous les sites clients. **Pas d'OAuth par client.** Le client ajoute simplement notre email service account comme utilisateur dans sa Search Console et sa propriété GA4 lors de l'onboarding.

Côté admin, par client on stocke uniquement des **identifiants de propriété**, pas des clés (cf. `/atelier-novelia/parametres/integrations` et memory `project_google_apis_integration`).

## Infrastructure (en place)

Le site est déployé en production sur un VPS Hetzner depuis le 2026-05-17, accessible sur **https://agence-novelia.fr** (+ `www.` et `app.` en sous-domaines, ce dernier sert temporairement le même conteneur en attendant le split du portail).

**Chaîne** :
```
Visiteur → Cloudflare (DNS + WAF + CDN, Full Strict) → Apache 2.4 (reverse proxy, vhosts agence-novelia.fr / app.agence-novelia.fr) → Docker container novelia-web (127.0.0.1:3010 → 3000 interne) → Next.js standalone
```

- **VPS** : Hetzner (IP 188.40.186.181), Debian, projet dans `/var/www/html/novelia`. **Connexion en root** (à migrer vers un user `deploy` dédié quand on aura des données clients réelles).
- **DNS** : Cloudflare (nameservers changés chez Ionos). 3 A records (`agence-novelia.fr`, `www`, `app`) → IP VPS, proxy activé. Mode SSL : **Full (Strict)** avec certificat Cloudflare Origin (15 ans) stocké dans `/etc/cloudflare/agence-novelia.fr.{pem,key}`.
- **Apache** : vhost unique [deploy/apache/novelia.conf](deploy/apache/novelia.conf) avec 3 VirtualHosts (redirect HTTP→HTTPS, apex+www, app), HTTP/2, WebSocket proxy, `mod_remoteip` pour récupérer la vraie IP visiteur via `CF-Connecting-IP`. Le port `3000` du VPS étant déjà occupé par un autre site, le conteneur Novelia est exposé sur **3010** côté host.
- **Docker** : image multi-stage [Dockerfile](Dockerfile) (Next.js 16 standalone, node:22-alpine, user non-root, healthcheck). [docker-compose.yml](docker-compose.yml) bind uniquement sur `127.0.0.1:3010` (jamais d'exposition publique directe). Variables d'env dans `.env.production` (gitignored) sur le VPS.
- **CI/CD** : [.github/workflows/deploy.yml](.github/workflows/deploy.yml) sur push `main` → SSH `appleboy/ssh-action` → `git reset --hard origin/main` → `docker compose up -d --build` → prune dangling images. Secrets GitHub : `SSH_HOST`, `SSH_USER=root`, `SSH_KEY` (clé deploy dédiée `~/.ssh/novelia_deploy`, autorisée dans `/root/.ssh/authorized_keys` sur le VPS et configurée comme deploy key SSH dans le repo GitHub).
- **Repo GitHub** : https://github.com/Zeikoo/Novelia (privé). Le VPS clone via SSH avec une seconde clé `~/.ssh/github_novelia` (deploy key read-only sur le repo).

**Cible long terme** : héberger aussi les sites clients sur ce dédié, isolés en conteneurs Docker derrière le même Apache. Quand la stack PostgreSQL/Auth/Stripe arrivera, ajouter un service `db` au compose et un service `mailer` éventuel.

Doc de déploiement détaillée : [deploy/README.md](deploy/README.md).

## Stack technique installée et validée

- **Front + back** : **Next.js 16** (App Router, Turbopack) + **TypeScript 5.9** + **React 19.2**.
- **UI** : **Tailwind CSS v4** (CSS-first config dans `globals.css` via `@theme`), **Phosphor Icons React 2.x** pour les icônes (via le proxy [components/ui/icons.tsx](components/ui/icons.tsx) qui re-exporte sous les noms historiques Lucide ; utilise le sous-module `@phosphor-icons/react/dist/ssr` pour compatibilité Server Components), **Recharts 3.x** pour les graphiques.
- **Polices** : **Cabinet Grotesk** (UI, body, via Fontshare CDN) + **Fraunces** (titres display + chiffres KPI, via `next/font/google`). Inter reste en fallback de Cabinet Grotesk dans `--font-sans`.
- **IA admin réalisations** : **`@anthropic-ai/sdk` 0.x** pour l'assistant éditorial (crawl URL → Claude → structured output via tool use).
- **Build prod** : `output: "standalone"` dans [next.config.ts](next.config.ts), requis pour l'image Docker minimale (`.next/standalone` + `.next/static` + `public/` copiés sur node:22-alpine).
- **Sécurité** : headers HSTS / X-Frame-Options / X-Content-Type-Options / Referrer-Policy / Permissions-Policy / COOP / suppression de `X-Powered-By` configurés dans [next.config.ts](next.config.ts).

**Stack à valider lors de la phase technique** :
- **Base de données** : PostgreSQL (via Prisma ou Drizzle, à trancher).
- **Auth** : Better Auth ou Auth.js v5, choix selon besoin multi-tenant.
- **Paiement** : Stripe (Checkout + Customer Portal + webhooks).
- **Intégrations Google** : `googleapis` avec service account JSON.
- **Stockage de fichiers** : Cloudflare R2 probable.
- **IA (phase 2 si activée pour client)** : `@anthropic-ai/sdk`, Claude Sonnet 4.6 par défaut.

## Envoi d'emails transactionnels (SMTP Ionos)

Module dédié [lib/email/](lib/email/) avec `nodemailer` + SMTP Ionos. Pas de Resend/Postmark : on utilise l'infra Ionos déjà payée avec le domaine.

**Architecture** :
- [lib/email/client.ts](lib/email/client.ts) : transporter singleton lazy-init lit `SMTP_HOST`/`SMTP_PORT`/`SMTP_SECURE`/`SMTP_USER`/`SMTP_PASSWORD`/`SMTP_FROM_EMAIL`/`SMTP_FROM_NAME` depuis l'env. Pool 3 connexions / 50 messages pour limiter le throttle Ionos. Exporte aussi `verifySmtp()` pour healthcheck.
- [lib/email/send.ts](lib/email/send.ts) : `sendMail({to, subject, html, text, replyTo?})` retourne `{ ok: true, messageId } | { ok: false, error }`. **Seul point d'entrée** pour envoyer un email depuis le projet.
- [lib/email/templates.ts](lib/email/templates.ts) : templates HTML email-safe (table-based, inline styles, palette warm dupliquée des tokens). Actuellement : notification interne + confirmation prospect pour le form contact.

**Reglages Ionos** : `smtp.ionos.fr` port 465 SSL (ou 587 STARTTLS). Variables dans [.env.production.example](.env.production.example).

**Usage** :
```ts
import { sendMail } from "@/lib/email/send";
const r = await sendMail({ to: "x@y.fr", subject: "...", html: "...", text: "..." });
if (!r.ok) console.error(r.error);
```

**Form `/contact` (Server Action)** : [app/(marketing)/contact/actions.ts](app/(marketing)/contact/actions.ts). Validation Zod, honeypot anti-bot (champ `website` caché en `aria-hidden + left:-10000px`), rate limit en mémoire (5 submits / 1 h / IP via CF-Connecting-IP), envoi parallèle de 2 emails (notification interne à `CONTACT_NOTIFY_TO` avec `replyTo: prospect.email` + confirmation au prospect). Côté client, [contact-form.tsx](app/(marketing)/contact/contact-form.tsx) utilise `useActionState` + `useFormStatus` pour les états submit/error/success avec field-level error display via `Field.error`.

**Next.js standalone** : `nodemailer` est ajouté à `outputFileTracingIncludes` dans [next.config.ts](next.config.ts) pour être embarqué dans l'image Docker prod.

**Consommateurs actifs** du module email :
- Form `/contact` (notification interne + confirmation prospect)
- Welcome email envoyé automatiquement lors du provisioning client dans [app/atelier-novelia/clients/actions.ts](app/atelier-novelia/clients/actions.ts) `createClient` (envoi non bloquant : si fail, le compte est créé quand même et l'admin voit le mot de passe dans l'UI pour le partager manuellement)
- Password reset Better Auth via `sendResetPassword` callback dans [lib/auth/index.ts](lib/auth/index.ts), flow complet : `/mot-de-passe-oublie` (saisie email) → email avec lien `/reset-password?token=...` → page set new password

**Consommateurs prévus** (à brancher quand les surfaces seront réelles) : notifications tickets support, factures Stripe, alertes intégrations Google.

## Anti-bot : Cloudflare Turnstile sur form contact

[lib/security/turnstile.ts](lib/security/turnstile.ts) + [components/ui/turnstile.tsx](components/ui/turnstile.tsx).

Challenge invisible (mode Managed côté Cloudflare = decide tout seul si le challenge est nécessaire selon le score de risque). Le widget client populate un champ `cf-turnstile-response` dans le form, vérifié serveur via POST à `challenges.cloudflare.com/turnstile/v0/siteverify`.

**Dégradation gracieuse** : si `NEXT_PUBLIC_TURNSTILE_SITE_KEY` ou `TURNSTILE_SECRET_KEY` ne sont pas configurées (dev local), le widget se rend `null` et la vérification serveur retourne `ok: true` automatiquement. Aucun crash, aucun message d'erreur.

Setup : créer un widget sur https://dash.cloudflare.com/?to=/:account/turnstile, mode Managed, ajouter domaines `agence-novelia.fr` + `localhost` (pour tests). Mettre les 2 clés dans `.env.production`. En complément du honeypot existant, double protection sur le form `/contact`.

## Charte graphique — direction « Atelier français, papier crème » (validée 2026-05-21)

Bascule du dark vers une palette claire le 2026-05-21 pour porter le positionnement « pro et abordable, naturel, rassurant ». Plus de lecture éditoriale, plus de confiance perçue, moins de connotation « tech-luxe ». Tokens définis dans [app/globals.css](app/globals.css) via `@theme`.

**Palette** (papier crème + bronze profond, jamais blanc pur ni noir pur) :
- `--color-background` : `#faf7f2` (papier crème, fond global légèrement chaud)
- `--color-surface` : `#ffffff` (cards, contraste subtil sur le crème, hiérarchie sans ombre lourde)
- `--color-surface-2` : `#f3ede2` (zones secondaires, sidebars portail/admin, footers)
- `--color-surface-3` : `#e8e0d1` (états hover, sections appuyées)
- `--color-text` : `#1c1917` (stone-900, titres + body principal, AAA sur le crème)
- `--color-text-muted` : `#44403c` (stone-700, sous-titres, labels)
- `--color-text-dim` : `#78716c` (stone-500, texte secondaire)
- `--color-text-faint` : `#6b6560` (placeholders, meta)
- `--color-border` : `rgba(28, 25, 23, 0.08)` (hairline warm, jamais gris froid)
- `--color-border-strong` : `rgba(28, 25, 23, 0.14)`
- `--color-accent` : `#92400e` (amber-800, **bronze profond** — version dense de l'amber dark, lisible AA sur crème, garde la continuité avec le logo doré)
- `--color-accent-hi` : `#b45309` (amber-700, hover)
- `--color-accent-lo` : `#78350f` (amber-900, active/pressed)
- `--color-accent-fg` : `#ffffff` (texte sur accent bronze)
- États (sémantiques, ajustés pour fond clair) : `success` `#15803d`, `warning` `#b45309`, `danger` `#b91c1c`, `info` `#1d4ed8`. Variantes `-soft` à 10 % d'opacité.
- Charts densifiés pour fond clair : `amber-800`, terracotta `#c2410c`, bronze `#92400e`, sage `#4d7c5f`, rose foncé `#9f1239`. Le bleu vif et le violet restent bannis.

**Typographie** :
- **Cabinet Grotesk** pour body, UI, labels (font-sans par défaut, chargée via Fontshare CDN). Donne plus de caractère qu'Inter (perçu comme AI default).
- **Fraunces** (variable, axes SOFT + opsz) pour les éléments display, accessible via la classe utilitaire `.font-editorial`. **Réservée aux gros titres (≥ 3xl) et aux chiffres KPI**, jamais en petit. Sur fond clair, Fraunces gagne du territoire (sections numérotées, drop caps éditoriaux, numerals KPI).
- Échelle typo stricte : `--text-xxs` 11 / `xs` 12 / `sm` 14 / `base` 16 / `lg` 18 / `xl` 20 / `2xl` 24 / `3xl` 30 / `4xl` 36 / `5xl` 48 / `6xl` 60 / `7xl` 72.

**Style** :
- Pas de gradients colorés. Pas de glassmorphism agressif (la navbar pill marketing reste légèrement translucide sur `bg-white/70`, dropdowns/sheets idem). Pas de gradient text. Pas d'ombres lourdes (le clair ne pardonne pas).
- Bordures hairline (1 px stone-900 à 8 % d'opacité), border-radius `0.75rem` standard pour les cards.
- Shadows teintées warm très allégées (rgba(28, 25, 23, 0.04 à 0.16)) pour suggérer l'épaisseur sans crier.
- Grain noise overlay SVG (5 % d'opacité, `mix-blend-mode: multiply` warm) sur le marketing uniquement, via la classe `.grain-overlay` dans [app/(marketing)/layout.tsx](app/(marketing)/layout.tsx). Sur fond clair, il fonce très légèrement les pixels et donne la texture papier.
- Animations : `Reveal` (fade + translateY 12 px sur 700 ms ease-out cubic-bezier) sur les pages marketing, respecte `prefers-reduced-motion`. **Pas d'animation sur portail/admin**.
- Boutons primary : background bronze (`bg-accent`), texte blanc, soulèvement léger au hover (`-translate-y-0.5`) + glow accent bronze renforcé, scale-down au click, état `loading` avec spinner overlay.

**Logo** : image PNG du N doré métallisé ([public/logo.png](public/logo.png)) rendue via le composant [components/brand/logo.tsx](components/brand/logo.tsx). Le PNG ayant un fond noir, le N doré est **systématiquement posé dans un cartouche stone-900** (petit chip sombre) avec bordure bronze, ce qui devient une signature « sceau d'atelier » récurrente du produit. Le `mix-blend-mode: screen` fonctionne car le chip est foncé. La variante `<Logo bordered />` (navbar marketing) renforce la bordure et ajoute un glow bronze. Si un jour le PNG est exporté en transparent, retirer la dépendance au chip.

## Préférences d'écriture (importantes)

À respecter dans tout le code et tout le copy :

- **Pas d'emojis** dans le code, le copy, les commits.
- **Pas de cadratins (em-dash `—`)** dans les textes affichés ni dans les commentaires de code. Utiliser virgules, points, deux-points, ou middle-dot `·` selon le contexte. C'est une marque caractéristique du texte généré par IA.
- **Pas de chiffres précis dans les promesses marketing** (vitrine + footer). Au lieu de « réponse en moins de 4 h », écrire « rapidement ». Les SLAs internes (portail support, admin) peuvent rester précis.
- **Tech-agnostique côté vitrine** : ne **pas** mentionner « Next.js », « React », « Tailwind » dans le copy public. Parler de « technologie la plus adaptée », « code sur-mesure », etc.
- **Marque centralisée** : ne jamais hard-coder « Novelia » dans le copy, toujours utiliser `BRAND_NAME` importé depuis [lib/brand.ts](lib/brand.ts). Idem pour le domaine via `BRAND_DOMAIN`.
- **Icônes** : importer depuis [@/components/ui/icons](components/ui/icons.tsx), jamais directement depuis `@phosphor-icons/react` ou `lucide-react`. Le proxy garantit la cohérence et permet un swap futur sans réécrire le code.
- **Vouvoiement** systématique côté client.
- **Ton** : précis, technique mais accessible, pas commercial bavard.
- **Devises** : euros (€), espace insécable comme séparateur de milliers (`1 420 €`).
- **Dates** : format français (`15 sept. 2026` ou `15/09/2026`).
- Lexique technique tolérable (`API`, `SSL`, `CDN`, `CI/CD`, `ms`, `GB`).

## Architecture des routes (état actuel)

```
app/
  layout.tsx                              (fonts, métadonnées globales, JSON-LD Organization, skip-link)
  not-found.tsx                           (404 custom stylée)
  icon.png                                (favicon Novelia)
  apple-icon.png                          (touch icon iOS)
  sitemap.ts                              (routes publiques, /portail et /atelier-novelia exclus)
  robots.ts                               (allow / · disallow /portail /atelier-novelia /api)
  globals.css                             (tokens charte + Cabinet Grotesk import + grain overlay + skip-link)
  (marketing)/
    layout.tsx                            (Navbar pill + Footer + grain noise + main id="main-content")
    page.tsx                              (accueil)
    essentiel/page.tsx
    contact/page.tsx                      (primitives Field/Input/Select/Textarea)
    tarifs/page.tsx                       (3 plans + comparatif + FAQ + JSON-LD OfferCatalog)
    expertises/
      site-internet/page.tsx
      seo-geo/page.tsx
      e-commerce/page.tsx
    realisations/
      page.tsx                            (grille cards)
      [slug]/page.tsx                     (détail, generateStaticParams)
  connexion/page.tsx                      (login avec primitives + main id + noindex)
  portail/
    layout.tsx                            (MobileNavProvider + Sidebar + Shell)
    page.tsx                              (dashboard analytics, ?site=ID)
    abonnement/page.tsx
    factures/page.tsx                     (table desktop + cards mobile)
    support/page.tsx
    support/[ref]/page.tsx
    support/nouveau/page.tsx              (formulaire avec primitives)
    parametres/layout.tsx
    parametres/page.tsx                   (profil + 2FA + sessions)
    parametres/equipe/page.tsx            (table desktop + cards mobile)
    parametres/confidentialite/page.tsx
  apres-connexion/page.tsx                (route de rebond serveur : redirige vers /atelier-novelia ou /portail selon role)
  atelier-novelia/                        (espace agence, renommé depuis /admin le 2026-05-23, noindex)
    layout.tsx                            (MobileNavProvider + Sidebar + Shell + metadata noindex)
    page.tsx                              (KPIs + RevenuePanel + clients actifs + factures récentes responsive)
    clients/page.tsx                      (table desktop + cards mobile)
    factures/page.tsx                     (table desktop + cards mobile)
    tickets/page.tsx                      (table desktop + cards mobile + KPI bar)
    tickets/[ref]/page.tsx
    realisations/page.tsx
    realisations/realisations-manager.tsx (client component, manager IA)
    realisations/actions.ts               (server actions : crawl URL + génération Claude)
    parametres/layout.tsx
    parametres/page.tsx                   (profil)
    parametres/equipe/page.tsx            (table desktop + cards mobile)
    parametres/integrations/page.tsx
    parametres/facturation/page.tsx       (raison sociale, RIB, numérotation, primitives)
components/
  brand/logo.tsx                          (Logo image PNG + variante bordered pour navbar)
  ui/                                     (primitives : Button, Input, Textarea, Select, Field, Avatar, Skeleton, Badge, Panel, Delta, StatCard, Reveal, icons proxy)
  shell/                                  (Sidebar, Topbar, Shell, MobileNav avec sheet drawer)
  marketing/                              (Navbar, Footer, Process, PageSpeedMockup, ExpertiseBlocks, RealisationCard, etc.)
  portail/                                (SiteSwitcher, LighthousePanel, AnalyticsChart, SitePreview, AiSummary, SettingsTabs)
  admin/                                  (RevenuePanel, SettingsTabs)
  charts/                                 (AreaChart, BarChart wrappers Recharts)
mockups/                                  (4 fichiers HTML autonomes : index, marketing, portail, admin)
deploy/
  README.md                               (procédure complète de déploiement VPS)
  apache/novelia.conf                     (vhosts Apache 2.4, Cloudflare Full Strict, proxy vers :3010)
public/
  logo.png                                (logo Novelia source, fond noir, neutralisé via mix-blend)
  mockups/                                (copie des mockups servis via dev server)
  phone-mockup.png                        (mockup smartphone accueil)
  visuals/                                (à fournir : atelier-menuiserie.jpg, vase-calanque.png)
Dockerfile                                (multi-stage Next 16 standalone, node:22-alpine)
docker-compose.yml                        (service web, bind 127.0.0.1:3010 → 3000)
.dockerignore
.env.production.example                   (template variables prod, à copier en .env.production sur le VPS)
.github/workflows/deploy.yml              (CI/CD SSH sur push main)
```

## Skills Claude Code installés

Les skills tiers utilisés pour la refonte sont documentés dans [SKILLS_SETUP.md](SKILLS_SETUP.md) avec leurs commandes d'installation pour réutilisation sur d'autres machines/projets. Les principaux : `emil-design-eng`, `redesign-skill`, `taste-skill`, `soft-skill`, `minimalist-skill`, `brandkit`, et 7 autres skills design via le repo `taste-skill`.

## Pistes à attaquer ensuite

- **Acquérir `novelia.fr`** quand il sera disponible et basculer le domaine principal (changer `BRAND_DOMAIN` dans [lib/brand.ts](lib/brand.ts) + ajouter `ServerAlias novelia.fr www.novelia.fr` dans [deploy/apache/novelia.conf](deploy/apache/novelia.conf) + créer les A records Cloudflare + régénérer le cert Origin).
- **Migrer le déploiement du user `root` vers un user `deploy`** dédié (geste 10 min : créer le user, l'ajouter à `docker`, `chown` le projet, remplacer le secret `SSH_USER` GitHub). À faire avant d'avoir des données clients réelles sur le VPS.
- **Visuels Expertises à fournir** : `public/visuals/atelier-menuiserie.jpg` et `public/visuals/vase-calanque.png`. Code les référence déjà.
- **Logo PNG transparent** : le PNG actuel a un fond noir, neutralisé via `mix-blend-mode: screen`. Si tu peux fournir une version vraiment transparente, on retirera le `mixBlendMode` du composant Logo.
- **Fiche client détaillée admin** (`/atelier-novelia/clients/[id]`) avec onglets Aperçu / Facturation / Intégrations / Activité.
- **Phase technique** : démarrer la couche réelle (Postgres + auth + Stripe + intégrations Google). Préalable : décider l'ORM (Prisma vs Drizzle) et la lib auth (Better Auth vs Auth.js v5). Ajouter les services `db` (et `mailer` si Postmark/Resend self-hosted) au [docker-compose.yml](docker-compose.yml).
- **Génération d'aperçus prospects** (`/preview/[slug]`) : phase 2, après portail stable.
- **Chantiers reportés audit sécurité/SEO** : Content-Security-Policy, anti-bot sur formulaire `/contact` (Turnstile/honeypot + rate-limit), Authenticated Origin Pulls Cloudflare → Apache pour bloquer l'accès direct au VPS hors CF.
- **Régénérer les assets `charte-graphique/logos/` et `charte-graphique/banners/`** qui contiennent encore le wordmark « Corelia ». Pas affichés sur le site (le composant `<Logo>` utilise le PNG Novelia), mais à régénérer pour OG image / press kit.

## Règles générales

- **Pas de WordPress, pas de CMS clé-en-main, pas de page builder.** Anti-positionnement assumé.
- **Palette claire uniquement** (papier crème + bronze). Le dark a été abandonné le 2026-05-21 au profit d'une direction « atelier français » plus pro/rassurante. Pas de toggle dark/light prévu pour l'instant.
- **Multi-tenant safety** : dès qu'on touche au modèle de données du portail, penser cloisonnement par client.
- **Performance et accessibilité** sont des contraintes produit, pas des nice-to-have.
- **RGPD** : données utilisateur minimales, durée de conservation explicite, export/suppression à la demande.
- **Pas d'animation** sur portail/admin. Animations réservées aux surfaces marketing.
- **Icônes** : importer depuis [@/components/ui/icons](components/ui/icons.tsx), jamais directement depuis Phosphor ou Lucide.
- **Marque** : utiliser `BRAND_NAME` et `BRAND_DOMAIN` depuis [lib/brand.ts](lib/brand.ts), jamais hard-coder « Novelia » ni « novelia.fr ».
