Harmonisation Groupe KA : socle ka-ui, badge, KaFooter, page /contact
- Vendorisation du package ka-ui dans frontend/src/ka/ (tokens.css, ecosystem.json, KaFooter, GroupeKaBadge) ; tokens importés AVANT le CSS local dans main.tsx - styles.css allégé : le :root ne garde que l accent orange brûlé d Auto-Ka (--accent/--accent-soft/--accent-deep/--on-accent + alias --lime), socle dédupliqué, couleurs en dur pointées vers les tokens, cibles tactiles 44 px - Header : badge « Un service Groupe KA » à côté du logo (desktop) + barre mobile sous le ticker ; nav défilante sans débordement - Footer : remplacé par le KaFooter commun (siteId auto-ka) - Nouvelle page /contact (ecosystem.json : 3 courriels + rôles, avertissement agrégateur, lien hub, liste des sites) + rendu serveur SEO + sitemap - Profil déconnecté : lien « Créer un compte » vers groupe-ka.com/connexion - index.html : titre « Auto-Ka — Un service Groupe KA » Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
11 changed files +587 −111
modified
autoka/seo.py
+14 −1
@@ -952,6 +952,18 @@ def page_profil(): | ||
| 952 | 952 | description="Votre profil Auto-Ka.", robots="noindex, nofollow") |
| 953 | 953 | |
| 954 | 954 | |
| 955 | +@router.get("/contact", response_model=None, include_in_schema=False) | |
| 956 | +def page_contact(): | |
| 957 | + """Page contact — coordonnées officielles du Groupe KA (rendu React).""" | |
| 958 | + return render_page( | |
| 959 | + path="/contact", | |
| 960 | + title="Contact — Auto-Ka, un service Groupe KA", | |
| 961 | + description="Joindre le Groupe KA : contact@groupe-ka.com (projets, " | |
| 962 | + "partenariats et données), info@groupe-ka.com (médias) et " | |
| 963 | + "admin@groupe-ka.com (légal, vie privée et Loi 25). Auto-Ka est un " | |
| 964 | + "service Groupe KA.") | |
| 965 | + | |
| 966 | + | |
| 955 | 967 | # --- robots.txt et sitemaps ----------------------------------------------------------- |
| 956 | 968 | |
| 957 | 969 | @router.get("/robots.txt", response_model=None, include_in_schema=False) |
@@ -992,7 +1004,8 @@ def sitemap_pages(): | ||
| 992 | 1004 | m = _maps() |
| 993 | 1005 | today = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d") |
| 994 | 1006 | urls: list[tuple[str, str]] = [("/", today), ("/motos", today), ("/scooters", today), |
| 995 | − ("/stats", today), ("/sources", today)] | |
| 1007 | + ("/stats", today), ("/sources", today), | |
| 1008 | + ("/contact", today)] | |
| 996 | 1009 | for kind, prefix in (("auto", "/usagees/"), ("moto", "/motos/"), ("scooter", "/scooters/")): |
| 997 | 1010 | for slug, info in m["make"].get(kind, {}).items(): |
| 998 | 1011 | urls.append((prefix + slug, _date(info["lm"]))) |
modified
frontend/index.html
+1 −1
@@ -5,7 +5,7 @@ | ||
| 5 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" /> |
| 6 | 6 | <meta name="description" content="Auto-Ka — toutes les voitures usagées à vendre au Québec, agrégées directement depuis les sites des concessionnaires. Un seul endroit, toujours à jour." /> |
| 7 | 7 | <meta name="theme-color" content="#17181c" /> |
| 8 | − <title>Auto·Ka — Voitures usagées à vendre au Québec</title> | |
| 8 | + <title>Auto-Ka — Un service Groupe KA</title> | |
| 9 | 9 | <link rel="preconnect" href="https://fonts.googleapis.com" /> |
| 10 | 10 | <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> |
| 11 | 11 | <link |
modified
frontend/src/App.tsx
+13 −23
@@ -9,7 +9,10 @@ import { | ||
| 9 | 9 | fetchFacets, fetchSources, fetchStats, logout, registerSourceNames, |
| 10 | 10 | } from "./api"; |
| 11 | 11 | import { AccountProvider, useAccount } from "./account"; |
| 12 | +import GroupeKaBadge from "./ka/GroupeKaBadge"; | |
| 13 | +import KaFooter from "./ka/KaFooter"; | |
| 12 | 14 | import Home from "./pages/Home"; |
| 15 | +import ContactPage from "./pages/Contact"; | |
| 13 | 16 | import VehiclePage from "./pages/Vehicle"; |
| 14 | 17 | import SourcesPage from "./pages/Sources"; |
| 15 | 18 | import StatsPage from "./pages/Stats"; |
@@ -138,6 +141,7 @@ function Header() { | ||
| 138 | 141 | Auto<span className="ka">Ka</span> |
| 139 | 142 | <span className="brand-tag">Voitures usagées · tout le Québec · toujours à jour</span> |
| 140 | 143 | </NavLink> |
| 144 | + <GroupeKaBadge /> | |
| 141 | 145 | <nav className="nav" aria-label="Navigation principale"> |
| 142 | 146 | <NavLink to="/" end className={({ isActive }) => (isActive ? "active" : "")}> |
| 143 | 147 | Autos |
@@ -154,34 +158,19 @@ function Header() { | ||
| 154 | 158 | <NavLink to="/sources" className={({ isActive }) => (isActive ? "active" : "")}> |
| 155 | 159 | Sources |
| 156 | 160 | </NavLink> |
| 161 | + <NavLink to="/contact" className={({ isActive }) => (isActive ? "active" : "")}> | |
| 162 | + Contact | |
| 163 | + </NavLink> | |
| 157 | 164 | </nav> |
| 158 | 165 | <AccountMenu /> |
| 159 | 166 | </div> |
| 160 | 167 | </header> |
| 161 | 168 | <Ticker /> |
| 162 | − </> | |
| 163 | − ); | |
| 164 | −} | |
| 165 | − | |
| 166 | −function Footer() { | |
| 167 | − return ( | |
| 168 | − <footer className="footer"> | |
| 169 | − <div className="container"> | |
| 170 | − <div className="fbrand"> | |
| 171 | − Auto<span className="ka">Ka</span> | |
| 172 | − </div> | |
| 173 | − <div className="frow"> | |
| 174 | − <b>Agrégateur indépendant</b> de voitures usagées à vendre dans la | |
| 175 | − province de Québec. Les annonces proviennent directement des sites | |
| 176 | − publics des concessionnaires — pas des plateformes d'annonces — et | |
| 177 | − sont rafraîchies automatiquement. Chaque fiche renvoie vers l'annonce | |
| 178 | − originale du commerçant. | |
| 179 | − </div> | |
| 180 | − <div className="fmono"> | |
| 181 | − © {new Date().getFullYear()} Simon-Pierre Boucher — contact@spboucher.ai | |
| 182 | − </div> | |
| 169 | + {/* variante mobile du badge (le badge du header est masqué < 1024 px) */} | |
| 170 | + <div className="gk-mobile"> | |
| 171 | + <GroupeKaBadge /> | |
| 183 | 172 | </div> |
| 184 | − </footer> | |
| 173 | + </> | |
| 185 | 174 | ); |
| 186 | 175 | } |
| 187 | 176 | |
@@ -206,6 +195,7 @@ export default function App() { | ||
| 206 | 195 | <Route path="/vehicule/:uid/:slug" element={<VehiclePage />} /> |
| 207 | 196 | <Route path="/stats" element={<StatsPage />} /> |
| 208 | 197 | <Route path="/sources" element={<SourcesPage />} /> |
| 198 | + <Route path="/contact" element={<ContactPage />} /> | |
| 209 | 199 | <Route path="/profil" element={<ProfilPage />} /> |
| 210 | 200 | <Route |
| 211 | 201 | path="*" |
@@ -219,7 +209,7 @@ export default function App() { | ||
| 219 | 209 | /> |
| 220 | 210 | </Routes> |
| 221 | 211 | </main> |
| 222 | − <Footer /> | |
| 212 | + <KaFooter siteId="auto-ka" /> | |
| 223 | 213 | </AccountProvider> |
| 224 | 214 | ); |
| 225 | 215 | } |
added
frontend/src/ka/GroupeKaBadge.tsx
+21 −0
@@ -0,0 +1,21 @@ | ||
| 1 | +// Auteur : Simon-Pierre Boucher — contact@spboucher.ai | |
| 2 | +// ka-ui/react/GroupeKaBadge.tsx — badge « Un service Groupe KA », cliquable | |
| 3 | +// vers le hub. À placer dans le header de chaque site (à côté du logo de la | |
| 4 | +// marque). Variante dark pour les surfaces encre. Zone de protection : le | |
| 5 | +// padding interne du badge suffit ; ne rien coller à moins de 8 px du badge. | |
| 6 | +export default function GroupeKaBadge({ dark = false }: { dark?: boolean }) { | |
| 7 | + return ( | |
| 8 | + <a | |
| 9 | + className={`gk-badge${dark ? " gk-badge--dark" : ""}`} | |
| 10 | + href="https://www.groupe-ka.com" | |
| 11 | + target="_blank" | |
| 12 | + rel="noopener noreferrer" | |
| 13 | + aria-label="Un service Groupe KA — visiter le portail de l'écosystème" | |
| 14 | + > | |
| 15 | + Un service | |
| 16 | + <b> | |
| 17 | + Groupe<span className="ka">KA</span> | |
| 18 | + </b> | |
| 19 | + </a> | |
| 20 | + ); | |
| 21 | +} | |
added
frontend/src/ka/KaFooter.tsx
+91 −0
@@ -0,0 +1,91 @@ | ||
| 1 | +// Auteur : Simon-Pierre Boucher — contact@spboucher.ai | |
| 2 | +// ka-ui/react/KaFooter.tsx — footer commun Groupe KA (fond encre), à vendorer | |
| 3 | +// dans chaque app Vite/React sous frontend/src/ka/. Consomme ecosystem.json : | |
| 4 | +// toute modification des infos de contact se fait dans ka-ui/ecosystem.json | |
| 5 | +// puis se resynchronise sur les 12 sites (voir ka-ui/README.md). | |
| 6 | +import eco from "./ecosystem.json"; | |
| 7 | + | |
| 8 | +type LocalLink = { label: string; href: string }; | |
| 9 | + | |
| 10 | +export default function KaFooter({ | |
| 11 | + siteId, | |
| 12 | + localLegal = [], | |
| 13 | +}: { | |
| 14 | + /** id du site courant dans ecosystem.json (ex. "resto-ka") */ | |
| 15 | + siteId: string; | |
| 16 | + /** pages légales PROPRES au site (ex. /conditions), affichées avant celles du hub */ | |
| 17 | + localLegal?: LocalLink[]; | |
| 18 | +}) { | |
| 19 | + const year = new Date().getFullYear(); | |
| 20 | + const site = eco.sites.find((s) => s.id === siteId); | |
| 21 | + const others = eco.sites.filter((s) => s.id !== siteId); | |
| 22 | + return ( | |
| 23 | + <footer className="ka-footer" id="contact"> | |
| 24 | + <div className="container"> | |
| 25 | + <a | |
| 26 | + className="wordmark" | |
| 27 | + href={eco.hub.url} | |
| 28 | + target={siteId === "groupe-ka" ? undefined : "_blank"} | |
| 29 | + rel="noopener noreferrer" | |
| 30 | + aria-label="Groupe KA — le portail de l'écosystème" | |
| 31 | + > | |
| 32 | + Groupe <span className="ka">KA</span> | |
| 33 | + </a> | |
| 34 | + <p className="desc"> | |
| 35 | + {eco.org.tagline} Des centaines de connecteurs lisent les sites à la | |
| 36 | + source, normalisent la donnée et se resynchronisent seuls.{" "} | |
| 37 | + {site ? ( | |
| 38 | + <> | |
| 39 | + <b style={{ color: "var(--paper)" }}>{site.wordmark}</b> —{" "} | |
| 40 | + {site.tagline} — est un service Groupe KA. | |
| 41 | + </> | |
| 42 | + ) : null} | |
| 43 | + </p> | |
| 44 | + <p className="notice"> | |
| 45 | + <b>{eco.org.disclaimer}</b> | |
| 46 | + </p> | |
| 47 | + <ul className="sites"> | |
| 48 | + {others.map((s) => ( | |
| 49 | + <li key={s.id}> | |
| 50 | + <a href={`https://${s.domain}`} target="_blank" rel="noopener noreferrer"> | |
| 51 | + {s.wordmark} | |
| 52 | + </a> | |
| 53 | + </li> | |
| 54 | + ))} | |
| 55 | + {eco.extraFooterLinks.map((l) => ( | |
| 56 | + <li key={l.href}> | |
| 57 | + <a href={l.href} target="_blank" rel="noopener noreferrer"> | |
| 58 | + {l.label} | |
| 59 | + </a> | |
| 60 | + </li> | |
| 61 | + ))} | |
| 62 | + </ul> | |
| 63 | + <div className="contacts"> | |
| 64 | + {eco.contacts.map((c) => ( | |
| 65 | + <p key={c.email} style={{ margin: 0 }}> | |
| 66 | + <a href={`mailto:${c.email}`}>{c.email}</a> | |
| 67 | + <span>{c.role}</span> | |
| 68 | + </p> | |
| 69 | + ))} | |
| 70 | + </div> | |
| 71 | + <p className="legal"> | |
| 72 | + © {year} {eco.org.copyrightHolder} | |
| 73 | + {localLegal.map((l) => ( | |
| 74 | + <span key={l.href}> | |
| 75 | + {" · "} | |
| 76 | + <a href={l.href}>{l.label}</a> | |
| 77 | + </span> | |
| 78 | + ))} | |
| 79 | + {eco.legal.map((l) => ( | |
| 80 | + <span key={l.href}> | |
| 81 | + {" · "} | |
| 82 | + <a href={l.href} target="_blank" rel="noopener noreferrer"> | |
| 83 | + {l.label} | |
| 84 | + </a> | |
| 85 | + </span> | |
| 86 | + ))} | |
| 87 | + </p> | |
| 88 | + </div> | |
| 89 | + </footer> | |
| 90 | + ); | |
| 91 | +} | |
added
frontend/src/ka/ecosystem.json
+45 −0
@@ -0,0 +1,45 @@ | ||
| 1 | +{ | |
| 2 | + "org": { | |
| 3 | + "name": "Groupe KA", | |
| 4 | + "legalName": "Groupe KA — Simon-Pierre Boucher", | |
| 5 | + "tagline": "Holding québécois d'agrégateurs de produits et services entièrement automatisés.", | |
| 6 | + "disclaimer": "Groupe KA est un agrégateur de contenu : nous ne vendons rien, ne louons rien et ne sommes partie à aucune transaction.", | |
| 7 | + "copyrightHolder": "Groupe KA — Simon-Pierre Boucher" | |
| 8 | + }, | |
| 9 | + "hub": { | |
| 10 | + "url": "https://www.groupe-ka.com", | |
| 11 | + "loginPath": "/connexion", | |
| 12 | + "signupNote": "La création de compte KA ID se fait sur le hub groupe-ka.com ; chaque site délègue sa connexion via /api/auth/ka/login." | |
| 13 | + }, | |
| 14 | + "contacts": [ | |
| 15 | + { "email": "contact@groupe-ka.com", "role": "Projets, partenariats & données" }, | |
| 16 | + { "email": "info@groupe-ka.com", "role": "Médias & questions générales" }, | |
| 17 | + { "email": "admin@groupe-ka.com", "role": "Légal, vie privée & Loi 25" } | |
| 18 | + ], | |
| 19 | + "legal": [ | |
| 20 | + { "label": "Conditions d'utilisation", "href": "https://www.groupe-ka.com/conditions" }, | |
| 21 | + { "label": "Politique de confidentialité", "href": "https://www.groupe-ka.com/confidentialite" }, | |
| 22 | + { "label": "Protection des renseignements personnels (Loi 25)", "href": "https://www.groupe-ka.com/loi-25" }, | |
| 23 | + { "label": "Transparence des robots d'indexation", "href": "https://www.groupe-ka.com/bots" } | |
| 24 | + ], | |
| 25 | + "sites": [ | |
| 26 | + { "id": "groupe-ka", "wordmark": "Groupe KA", "domain": "www.groupe-ka.com", "accent": "#d9f26b", "accentSoft": "#f0f9d2", "accentDeep": "#123f2e", "onAccent": "#141814", "tagline": "Le portail de l'écosystème ·Ka" }, | |
| 27 | + { "id": "trouve-ka", "wordmark": "Trouve·Ka", "domain": "www.trouve-ka.com", "accent": "#1c7ed6", "accentSoft": "#e7f2fd", "accentDeep": "#14508f", "onAccent": "#ffffff", "tagline": "Le moteur de recherche du web québécois" }, | |
| 28 | + { "id": "lou-ka", "wordmark": "Lou·Ka", "domain": "www.lou-ka.com", "accent": "#ff6a00", "accentSoft": "#fff1e6", "accentDeep": "#cc5500", "onAccent": "#ffffff", "tagline": "Tous les logements à louer" }, | |
| 29 | + { "id": "immo-ka", "wordmark": "Immo·Ka", "domain": "www.immo-ka.com", "accent": "#e23744", "accentSoft": "#fbe0e2", "accentDeep": "#a8232e", "onAccent": "#ffffff", "tagline": "Toutes les propriétés à vendre" }, | |
| 30 | + { "id": "vrai-prix", "wordmark": "Vrai-Prix", "domain": "www.vrai-prix.com", "accent": "#ff5148", "accentSoft": "#ffe3e0", "accentDeep": "#9e2a25", "onAccent": "#ffffff", "tagline": "La valeur réelle de chaque propriété" }, | |
| 31 | + { "id": "auto-ka", "wordmark": "Auto·Ka", "domain": "www.auto-ka.com", "accent": "#ff5a2a", "accentSoft": "#ffe8de", "accentDeep": "#cc3f16", "onAccent": "#ffffff", "tagline": "Les voitures usagées du Québec" }, | |
| 32 | + { "id": "fabri-ka", "wordmark": "Fabri·Ka", "domain": "www.fabri-ka.com", "accent": "#c4532e", "accentSoft": "#f7e3da", "accentDeep": "#a94525", "onAccent": "#ffffff", "tagline": "Les produits fabriqués au Québec" }, | |
| 33 | + { "id": "food-ka", "wordmark": "Food·Ka", "domain": "www.food-ka.com", "accent": "#1f9d55", "accentSoft": "#e2f5ea", "accentDeep": "#157a40", "onAccent": "#ffffff", "tagline": "Les prix d'épicerie, suivis à la source" }, | |
| 34 | + { "id": "resto-ka", "wordmark": "Resto·Ka", "domain": "www.resto-ka.com", "accent": "#f08c00", "accentSoft": "#fdeed7", "accentDeep": "#b96a00", "onAccent": "#141814", "tagline": "Chaque resto, chaque plat, chaque prix" }, | |
| 35 | + { "id": "sorti-ka", "wordmark": "Sorti·Ka", "domain": "www.sorti-ka.com", "accent": "#d6336c", "accentSoft": "#fbe0eb", "accentDeep": "#a12551", "onAccent": "#ffffff", "tagline": "Toutes les sorties, dans les 17 régions" }, | |
| 36 | + { "id": "crea-ka", "wordmark": "Créa·Ka", "domain": "www.crea-ka.com", "accent": "#7048e8", "accentSoft": "#ece5fc", "accentDeep": "#5433b8", "onAccent": "#ffffff", "tagline": "Les créateurs d'ici, tous leurs liens" }, | |
| 37 | + { "id": "api-ka", "wordmark": "API·Ka", "domain": "www.api-ka.com", "accent": "#3b5bdb", "accentSoft": "#e4eafb", "accentDeep": "#2b44a8", "onAccent": "#ffffff", "tagline": "La donnée de l'écosystème, par API" } | |
| 38 | + ], | |
| 39 | + "extraFooterLinks": [ | |
| 40 | + { "label": "ValoPlex", "href": "https://www.valoplex.com" }, | |
| 41 | + { "label": "Ka2", "href": "https://www.ka2.bot" }, | |
| 42 | + { "label": "Ka4", "href": "https://www.ka4.bot" }, | |
| 43 | + { "label": "Ka6", "href": "https://www.ka6.bot" } | |
| 44 | + ] | |
| 45 | +} | |
added
frontend/src/ka/tokens.css
+229 −0
@@ -0,0 +1,229 @@ | ||
| 1 | +/* ----------------------------------------------------------------------------- | |
| 2 | + Auteur : Simon-Pierre Boucher — contact@spboucher.ai | |
| 3 | + Fichier : ka-ui/tokens.css — SOURCE CANONIQUE (repo ka-ui sur spbgit) | |
| 4 | + Desc. : Design system commun GROUPE KA « éditorial sharp » — tokens + socle | |
| 5 | + de composants partagés par les 12 plateformes. Chaque site importe ce | |
| 6 | + fichier PUIS surcharge uniquement son accent (voir accents.css). | |
| 7 | + | |
| 8 | + · Typo : display Space Grotesk / texte Inter / micro-étiquettes JetBrains Mono | |
| 9 | + · Palette: papier #f5f3ee · encre #141814 · vert profond #1c5c41 + ACCENT du site | |
| 10 | + · Signature : bordures encre 1,5–2 px + ombres décalées dures, grain de film, | |
| 11 | + surlignés d'accent inclinés (néo-brutalisme raffiné) | |
| 12 | + · Breakpoints communs : 360 / 768 / 1024 / 1440 px (mobile-first) | |
| 13 | + · Zones tactiles ≥ 44×44 px, safe-areas iOS, typographie fluide (clamp) | |
| 14 | +----------------------------------------------------------------------------- */ | |
| 15 | + | |
| 16 | +:root { | |
| 17 | + /* ---- Palette fixe Groupe KA (identique sur les 12 sites) ---- */ | |
| 18 | + --paper: #f5f3ee; | |
| 19 | + --surface: #ffffff; | |
| 20 | + --surface-2: #faf9f5; | |
| 21 | + --ink: #141814; | |
| 22 | + --ink-2: #4d5551; | |
| 23 | + --ink-3: #8b928c; | |
| 24 | + --line: rgba(20, 24, 20, 0.14); | |
| 25 | + --line-strong: rgba(20, 24, 20, 0.85); | |
| 26 | + --green: #1c5c41; | |
| 27 | + --green-deep: #123f2e; | |
| 28 | + --amber: #e8a33d; | |
| 29 | + --amber-soft: #fdf3e2; | |
| 30 | + --danger: #b3423a; | |
| 31 | + --danger-soft: #fbe9e7; | |
| 32 | + | |
| 33 | + /* ---- ACCENT du site — SEULES variables surchargées par marque ---- */ | |
| 34 | + --accent: #d9f26b; /* défaut : lime Groupe KA */ | |
| 35 | + --accent-soft: #f0f9d2; | |
| 36 | + --accent-deep: #123f2e; | |
| 37 | + --on-accent: var(--ink); /* couleur du texte posé SUR l'accent */ | |
| 38 | + | |
| 39 | + /* alias rétro-compatibles (les satellites historiques utilisent --lime) */ | |
| 40 | + --lime: var(--accent); | |
| 41 | + --lime-soft: var(--accent-soft); | |
| 42 | + | |
| 43 | + /* ---- Géométrie sharp ---- */ | |
| 44 | + --r-card: 10px; | |
| 45 | + --r-ctl: 6px; | |
| 46 | + --r-pill: 999px; | |
| 47 | + | |
| 48 | + /* ---- Ombres décalées — la signature du groupe ---- */ | |
| 49 | + --shadow-flat: 0 1px 2px rgba(20, 24, 20, 0.05); | |
| 50 | + --shadow-off: 6px 6px 0 var(--ink); | |
| 51 | + --shadow-off-soft: 8px 8px 0 rgba(20, 24, 20, 0.08); | |
| 52 | + --shadow-off-mid: 4px 4px 0 rgba(20, 24, 20, 0.18); | |
| 53 | + | |
| 54 | + /* ---- Typographie ---- */ | |
| 55 | + --font-display: "Space Grotesk", system-ui, sans-serif; | |
| 56 | + --font-body: "Inter", system-ui, sans-serif; | |
| 57 | + --font-mono: "JetBrains Mono", ui-monospace, monospace; | |
| 58 | + | |
| 59 | + /* Échelle fluide (mobile-first, clamp) */ | |
| 60 | + --fs-h1: clamp(30px, 3.2vw + 18px, 54px); | |
| 61 | + --fs-h2: clamp(23px, 1.8vw + 14px, 34px); | |
| 62 | + --fs-h3: clamp(17px, 0.9vw + 12px, 22px); | |
| 63 | + --fs-body: 15px; | |
| 64 | + --fs-small: 13px; | |
| 65 | + | |
| 66 | + /* Espacements */ | |
| 67 | + --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; | |
| 68 | + --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px; | |
| 69 | + | |
| 70 | + /* Cible tactile minimale */ | |
| 71 | + --touch: 44px; | |
| 72 | +} | |
| 73 | + | |
| 74 | +/* ---- Socle ---- */ | |
| 75 | +* { box-sizing: border-box; } | |
| 76 | +html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; } | |
| 77 | +body { | |
| 78 | + margin: 0; | |
| 79 | + background: var(--paper); | |
| 80 | + color: var(--ink); | |
| 81 | + font-family: var(--font-body); | |
| 82 | + font-size: var(--fs-body); | |
| 83 | + line-height: 1.55; | |
| 84 | + -webkit-font-smoothing: antialiased; | |
| 85 | + padding-bottom: env(safe-area-inset-bottom); | |
| 86 | + overflow-x: clip; /* jamais de débordement horizontal */ | |
| 87 | +} | |
| 88 | +img, svg, video { max-width: 100%; height: auto; display: block; } | |
| 89 | +h1, h2, h3, h4 { font-family: var(--font-display); letter-spacing: -0.03em; margin: 0 0 0.5em; } | |
| 90 | +h1 { font-size: var(--fs-h1); line-height: 1.06; } | |
| 91 | +h2 { font-size: var(--fs-h2); line-height: 1.15; } | |
| 92 | +h3 { font-size: var(--fs-h3); line-height: 1.25; } | |
| 93 | +a { color: inherit; } | |
| 94 | +::selection { background: var(--accent); color: var(--on-accent); } | |
| 95 | +:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; } | |
| 96 | + | |
| 97 | +/* Grain de film pleine page — ⚠️ jamais de z-index sur body > * (position: | |
| 98 | + relative seulement), sinon les utilitaires z-* sont écrasés. */ | |
| 99 | +body::before { | |
| 100 | + content: ""; | |
| 101 | + position: fixed; inset: 0; pointer-events: none; opacity: 0.35; z-index: 9999; | |
| 102 | + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.06'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E"); | |
| 103 | +} | |
| 104 | +body > * { position: relative; } | |
| 105 | + | |
| 106 | +/* ---- Conteneur commun ---- */ | |
| 107 | +.container { max-width: 1152px; margin: 0 auto; padding: 0 var(--sp-4); } | |
| 108 | +@media (min-width: 768px) { .container { padding: 0 var(--sp-5); } } | |
| 109 | + | |
| 110 | +/* ---- Micro-typographie signature ---- */ | |
| 111 | +.kicker { | |
| 112 | + display: inline-flex; align-items: center; gap: 10px; | |
| 113 | + font-family: var(--font-mono); font-size: 11.5px; font-weight: 500; | |
| 114 | + text-transform: uppercase; letter-spacing: 0.12em; color: var(--green); | |
| 115 | +} | |
| 116 | +.kicker::before { content: ""; width: 22px; height: 2px; background: var(--green); } | |
| 117 | +.klabel { | |
| 118 | + font-family: var(--font-mono); font-size: 10px; font-weight: 700; | |
| 119 | + text-transform: uppercase; letter-spacing: 0.1em; color: var(--ink-3); | |
| 120 | +} | |
| 121 | +.hl { | |
| 122 | + display: inline-block; background: var(--accent); color: var(--on-accent); | |
| 123 | + border-radius: 8px; padding: 0 10px 2px; transform: rotate(-1deg); | |
| 124 | +} | |
| 125 | +.outline-txt { color: transparent; -webkit-text-stroke: 2px var(--ink); } | |
| 126 | + | |
| 127 | +/* ---- Boutons (cible ≥ 44 px) ---- */ | |
| 128 | +.btn { | |
| 129 | + display: inline-flex; align-items: center; justify-content: center; gap: 8px; | |
| 130 | + min-height: var(--touch); padding: 10px 18px; | |
| 131 | + font-family: var(--font-display); font-weight: 700; font-size: 14px; | |
| 132 | + border: 1.5px solid var(--ink); border-radius: var(--r-ctl); | |
| 133 | + background: var(--surface); color: var(--ink); | |
| 134 | + cursor: pointer; text-decoration: none; | |
| 135 | + transition: transform 0.15s, box-shadow 0.15s, background 0.15s, color 0.15s; | |
| 136 | +} | |
| 137 | +.btn:hover { transform: translate(-2px, -2px); box-shadow: var(--shadow-off-mid); } | |
| 138 | +.btn:active { transform: translate(0, 0); box-shadow: none; } | |
| 139 | +.btn:disabled { opacity: 0.45; pointer-events: none; } | |
| 140 | +.btn-primary { background: var(--ink); color: var(--accent); } | |
| 141 | +.btn-primary:hover { background: var(--accent-deep); } | |
| 142 | +.btn-accent { background: var(--accent); color: var(--on-accent); } | |
| 143 | +.btn-ghost { background: transparent; border-color: var(--line); } | |
| 144 | +.btn-ghost:hover { border-color: var(--ink); } | |
| 145 | + | |
| 146 | +/* ---- Cartes ---- */ | |
| 147 | +.card { | |
| 148 | + background: var(--surface); border: 1.5px solid var(--ink); | |
| 149 | + border-radius: var(--r-card); box-shadow: var(--shadow-off-soft); | |
| 150 | + overflow: hidden; | |
| 151 | +} | |
| 152 | +.card-hover { transition: transform 0.15s, box-shadow 0.15s; } | |
| 153 | +.card-hover:hover { transform: translate(-2px, -2px); box-shadow: var(--shadow-off); } | |
| 154 | + | |
| 155 | +/* ---- Chips / badges ---- */ | |
| 156 | +.chip { | |
| 157 | + display: inline-flex; align-items: center; gap: 6px; | |
| 158 | + padding: 4px 11px; font-family: var(--font-mono); font-size: 11px; font-weight: 700; | |
| 159 | + text-transform: uppercase; letter-spacing: 0.06em; | |
| 160 | + border: 1.5px solid var(--ink); border-radius: var(--r-pill); | |
| 161 | + background: var(--surface); color: var(--ink); | |
| 162 | +} | |
| 163 | +.chip-accent { background: var(--accent); color: var(--on-accent); } | |
| 164 | +.chip-soft { background: var(--accent-soft); border-color: var(--line); } | |
| 165 | + | |
| 166 | +/* ---- Champs ---- */ | |
| 167 | +.input, .select, .textarea { | |
| 168 | + width: 100%; min-height: var(--touch); padding: 10px 14px; | |
| 169 | + font: inherit; color: var(--ink); background: var(--surface); | |
| 170 | + border: 1.5px solid var(--ink); border-radius: var(--r-ctl); | |
| 171 | +} | |
| 172 | +.input:focus, .select:focus, .textarea:focus { | |
| 173 | + outline: none; box-shadow: 3px 3px 0 var(--accent); border-color: var(--ink); | |
| 174 | +} | |
| 175 | +.input::placeholder { color: var(--ink-3); } | |
| 176 | + | |
| 177 | +/* ---- Badge « Un service Groupe KA » (header, cliquable → hub) ---- */ | |
| 178 | +.gk-badge { | |
| 179 | + display: inline-flex; align-items: center; gap: 7px; | |
| 180 | + min-height: 30px; padding: 3px 10px 4px; | |
| 181 | + font-family: var(--font-mono); font-size: 10px; font-weight: 700; | |
| 182 | + letter-spacing: 0.08em; text-transform: uppercase; text-decoration: none; | |
| 183 | + border: 1.5px solid var(--ink); border-radius: var(--r-pill); | |
| 184 | + background: var(--surface); color: var(--ink-2); white-space: nowrap; | |
| 185 | +} | |
| 186 | +.gk-badge b { | |
| 187 | + font-family: var(--font-display); font-size: 12px; letter-spacing: -0.02em; | |
| 188 | + text-transform: none; color: var(--ink); | |
| 189 | +} | |
| 190 | +.gk-badge b .ka { | |
| 191 | + display: inline-block; background: var(--ink); color: var(--accent); | |
| 192 | + border-radius: 5px; padding: 0 5px 1px; margin-left: 3px; transform: rotate(-2deg); | |
| 193 | +} | |
| 194 | +.gk-badge:hover .ka { transform: rotate(0); } | |
| 195 | +.gk-badge--dark { background: transparent; border-color: rgba(245,243,238,0.4); color: rgba(245,243,238,0.75); } | |
| 196 | +.gk-badge--dark b { color: var(--paper); } | |
| 197 | + | |
| 198 | +/* ---- Footer commun (fond encre — voir react/KaFooter.tsx) ---- */ | |
| 199 | +.ka-footer { margin-top: var(--sp-8); background: var(--ink); padding: 44px 0; font-size: 13px; color: rgba(245,243,238,0.75); } | |
| 200 | +.ka-footer a { text-decoration: none; } | |
| 201 | +.ka-footer .wordmark { font-family: var(--font-display); font-weight: 700; font-size: 30px; letter-spacing: -0.04em; color: var(--paper); text-decoration: none; } | |
| 202 | +.ka-footer .wordmark .ka { color: var(--accent); } | |
| 203 | +.ka-footer .desc { max-width: 640px; margin-top: var(--sp-4); } | |
| 204 | +.ka-footer .notice { max-width: 640px; margin-top: var(--sp-4); border-left: 2px solid var(--accent); padding-left: var(--sp-4); } | |
| 205 | +.ka-footer .notice b { color: var(--paper); } | |
| 206 | +.ka-footer .sites { list-style: none; display: flex; flex-wrap: wrap; gap: 10px 26px; margin: 26px 0 0; padding: 0; font-family: var(--font-mono); font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; } | |
| 207 | +.ka-footer .sites a { color: rgba(245,243,238,0.65); } | |
| 208 | +.ka-footer .sites a:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 4px; } | |
| 209 | +.ka-footer .contacts { display: grid; gap: 14px 32px; border-top: 1px solid rgba(245,243,238,0.15); margin-top: 30px; padding-top: 26px; } | |
| 210 | +@media (min-width: 768px) { .ka-footer .contacts { grid-template-columns: repeat(3, 1fr); } } | |
| 211 | +.ka-footer .contacts a { font-family: var(--font-mono); font-weight: 700; font-size: 12px; color: rgba(245,243,238,0.85); } | |
| 212 | +.ka-footer .contacts a:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 4px; } | |
| 213 | +.ka-footer .contacts span { display: block; margin-top: 3px; font-size: 11px; color: rgba(245,243,238,0.5); } | |
| 214 | +.ka-footer .legal { margin-top: 30px; font-family: var(--font-mono); font-size: 11px; color: rgba(245,243,238,0.45); } | |
| 215 | +.ka-footer .legal a { color: inherit; } | |
| 216 | +.ka-footer .legal a:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 4px; } | |
| 217 | + | |
| 218 | +/* ---- Tableaux → cartes empilées sous 768 px ---- */ | |
| 219 | +.tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; } | |
| 220 | +@media (max-width: 767px) { | |
| 221 | + .tbl-stack thead { display: none; } | |
| 222 | + .tbl-stack tr { display: block; border: 1.5px solid var(--ink); border-radius: var(--r-card); margin-bottom: var(--sp-3); background: var(--surface); } | |
| 223 | + .tbl-stack td { display: flex; justify-content: space-between; gap: var(--sp-3); padding: 8px 12px; border: 0; } | |
| 224 | + .tbl-stack td::before { content: attr(data-label); font-family: var(--font-mono); font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-3); } | |
| 225 | +} | |
| 226 | + | |
| 227 | +/* ---- Utilitaires responsive ---- */ | |
| 228 | +.only-mobile { display: initial; } .only-desktop { display: none; } | |
| 229 | +@media (min-width: 768px) { .only-mobile { display: none; } .only-desktop { display: initial; } } | |
modified
frontend/src/main.tsx
+1 −0
@@ -6,6 +6,7 @@ import React from "react"; | ||
| 6 | 6 | import ReactDOM from "react-dom/client"; |
| 7 | 7 | import { BrowserRouter } from "react-router-dom"; |
| 8 | 8 | import App from "./App"; |
| 9 | +import "./ka/tokens.css"; // socle Groupe KA (tokens + composants partagés) — AVANT le CSS local | |
| 9 | 10 | import "./styles.css"; |
| 10 | 11 | |
| 11 | 12 | ReactDOM.createRoot(document.getElementById("root")!).render( |
added
frontend/src/pages/Contact.tsx
+73 −0
@@ -0,0 +1,73 @@ | ||
| 1 | +// ----------------------------------------------------------------------------- | |
| 2 | +// Auto-Ka — Agrégateur de voitures usagées à vendre (province de Québec) | |
| 3 | +// Auteur : Simon-Pierre Boucher — contact@spboucher.ai | |
| 4 | +// pages/Contact.tsx : page /contact — coordonnées officielles du Groupe KA, | |
| 5 | +// lues d'ecosystem.json (source canonique ka-ui) : 3 courriels + rôles, | |
| 6 | +// avertissement agrégateur, lien vers le hub et liste des sites du groupe. | |
| 7 | +// ----------------------------------------------------------------------------- | |
| 8 | +import { useEffect } from "react"; | |
| 9 | +import eco from "../ka/ecosystem.json"; | |
| 10 | + | |
| 11 | +export default function ContactPage() { | |
| 12 | + useEffect(() => { | |
| 13 | + document.title = "Contact — Auto-Ka, un service Groupe KA"; | |
| 14 | + window.scrollTo(0, 0); | |
| 15 | + }, []); | |
| 16 | + | |
| 17 | + const others = eco.sites.filter((s) => s.id !== "auto-ka"); | |
| 18 | + | |
| 19 | + return ( | |
| 20 | + <div className="page container"> | |
| 21 | + <span className="kicker">Nous joindre</span> | |
| 22 | + <h1>Contact</h1> | |
| 23 | + <p className="lead"> | |
| 24 | + Auto·Ka est un service du <b>{eco.org.name}</b> — {eco.org.tagline}{" "} | |
| 25 | + Toutes les demandes passent par les adresses officielles du groupe. | |
| 26 | + </p> | |
| 27 | + | |
| 28 | + <div className="contact-grid"> | |
| 29 | + {eco.contacts.map((c) => ( | |
| 30 | + <div className="contact-card" key={c.email}> | |
| 31 | + <a className="mail" href={`mailto:${c.email}`}>{c.email}</a> | |
| 32 | + <span className="role">{c.role}</span> | |
| 33 | + </div> | |
| 34 | + ))} | |
| 35 | + </div> | |
| 36 | + | |
| 37 | + <div className="contact-note"> | |
| 38 | + <b>{eco.org.disclaimer}</b> Les annonces affichées sur Auto·Ka | |
| 39 | + proviennent des sites publics des concessionnaires ; chaque fiche | |
| 40 | + renvoie vers l'annonce originale du commerçant. | |
| 41 | + </div> | |
| 42 | + | |
| 43 | + <div className="contact-hub"> | |
| 44 | + <a | |
| 45 | + className="btn" | |
| 46 | + href={eco.hub.url} | |
| 47 | + target="_blank" | |
| 48 | + rel="noopener noreferrer" | |
| 49 | + > | |
| 50 | + Visiter le portail Groupe KA ↗ | |
| 51 | + </a> | |
| 52 | + </div> | |
| 53 | + | |
| 54 | + <div className="seo-block"> | |
| 55 | + <h2>Les autres plateformes du Groupe KA</h2> | |
| 56 | + <div className="contact-sites"> | |
| 57 | + {others.map((s) => ( | |
| 58 | + <a | |
| 59 | + key={s.id} | |
| 60 | + className="spec-chip" | |
| 61 | + href={`https://${s.domain}`} | |
| 62 | + target="_blank" | |
| 63 | + rel="noopener noreferrer" | |
| 64 | + title={s.tagline} | |
| 65 | + > | |
| 66 | + {s.wordmark} | |
| 67 | + </a> | |
| 68 | + ))} | |
| 69 | + </div> | |
| 70 | + </div> | |
| 71 | + </div> | |
| 72 | + ); | |
| 73 | +} | |
modified
frontend/src/pages/Profil.tsx
+13 −3
@@ -115,9 +115,19 @@ export default function ProfilPage() { | ||
| 115 | 115 | Connectez-vous avec votre <b>KA ID</b> — l'identifiant de membre |
| 116 | 116 | du Groupe KA, le même sur toutes les plateformes du groupe. |
| 117 | 117 | </p> |
| 118 | − <a className="btn login-cta" href="/api/auth/ka/login?next=%2Fprofil"> | |
| 119 | − Se connecter avec KA ID | |
| 120 | − </a> | |
| 118 | + <div className="profil-actions"> | |
| 119 | + <a className="btn login-cta" href="/api/auth/ka/login?next=%2Fprofil"> | |
| 120 | + Se connecter avec KA ID | |
| 121 | + </a> | |
| 122 | + <a | |
| 123 | + className="btn ghost login-cta" | |
| 124 | + href="https://www.groupe-ka.com/connexion" | |
| 125 | + target="_blank" | |
| 126 | + rel="noopener noreferrer" | |
| 127 | + > | |
| 128 | + Créer un compte sur groupe-ka.com ↗ | |
| 129 | + </a> | |
| 130 | + </div> | |
| 121 | 131 | </div> |
| 122 | 132 | ); |
| 123 | 133 | } |
modified
frontend/src/styles.css
+86 −83
@@ -1,79 +1,43 @@ | ||
| 1 | 1 | /* ----------------------------------------------------------------------------- |
| 2 | 2 | Auto-Ka — Agrégateur de voitures usagées à vendre (province de Québec) |
| 3 | 3 | Auteur : Simon-Pierre Boucher — contact@spboucher.ai |
| 4 | − styles.css : système de design « éditorial sharp » — thème clair | |
| 5 | − · Typo display Space Grotesk / texte Inter / micro-étiquettes JetBrains Mono | |
| 6 | − · Signature : bordures encre + ombres décalées (néo-brutalisme raffiné) | |
| 7 | − · Accent orange racing #ff5a2a sur encre charbon | |
| 4 | + styles.css : classes MÉTIER par-dessus le socle Groupe KA (ka/tokens.css). | |
| 5 | + · Le socle (palette papier/encre, typo, ombres décalées, breakpoints, | |
| 6 | + composants partagés) vient de ka/tokens.css, importé AVANT ce fichier. | |
| 7 | + · Ici : SEUL l'accent du site est surchargé + les classes propres à | |
| 8 | + Auto-Ka (fiches véhicules, filtres, stats, compte KA ID). | |
| 9 | + · Accent Auto-Ka : orange brûlé #ff5a2a sur encre. | |
| 8 | 10 | ----------------------------------------------------------------------------- */ |
| 9 | 11 | :root { |
| 10 | − --paper: #f4f2ec; | |
| 11 | − --surface: #ffffff; | |
| 12 | − --surface-2: #faf8f4; | |
| 13 | − --ink: #17181c; | |
| 14 | − --ink-2: #4c4f57; | |
| 15 | − --ink-3: #8b8e96; | |
| 16 | − --line: rgba(23, 24, 28, 0.14); | |
| 17 | − --line-strong: rgba(23, 24, 28, 0.85); | |
| 12 | + /* ---- ACCENT Auto-Ka — seules variables surchargées des tokens ka-ui ---- */ | |
| 18 | 13 | --accent: #ff5a2a; |
| 19 | − --accent-deep: #cc3f16; | |
| 20 | 14 | --accent-soft: #ffe8de; |
| 15 | + --accent-deep: #cc3f16; | |
| 16 | + --on-accent: #ffffff; | |
| 17 | + /* alias rétro-compatibles avec le socle */ | |
| 18 | + --lime: var(--accent); | |
| 19 | + --lime-soft: var(--accent-soft); | |
| 20 | + /* variables métier locales (absentes des tokens) */ | |
| 21 | 21 | --good: #1c7a4d; |
| 22 | 22 | --good-soft: #e2f4e9; |
| 23 | − --amber: #e8a33d; | |
| 24 | − --amber-soft: #fdf3e2; | |
| 25 | − --danger: #b3423a; | |
| 26 | − --r-card: 10px; | |
| 27 | − --r-ctl: 6px; | |
| 28 | − --shadow-flat: 0 1px 2px rgba(23, 24, 28, 0.05); | |
| 29 | − --shadow-off: 6px 6px 0 var(--ink); | |
| 30 | − --shadow-off-soft: 8px 8px 0 rgba(23, 24, 28, 0.08); | |
| 31 | − --font-display: "Space Grotesk", system-ui, sans-serif; | |
| 32 | − --font-body: "Inter", system-ui, sans-serif; | |
| 33 | − --font-mono: "JetBrains Mono", ui-monospace, monospace; | |
| 34 | −} | |
| 35 | − | |
| 36 | −* { box-sizing: border-box; } | |
| 37 | −html { scroll-behavior: smooth; } | |
| 38 | −body { | |
| 39 | − margin: 0; | |
| 40 | − background: var(--paper); | |
| 41 | − color: var(--ink); | |
| 42 | − font-family: var(--font-body); | |
| 43 | − font-size: 15px; | |
| 44 | − line-height: 1.55; | |
| 45 | − -webkit-font-smoothing: antialiased; | |
| 46 | − padding-bottom: env(safe-area-inset-bottom); | |
| 47 | −} | |
| 48 | −/* grain subtil — texture signature */ | |
| 49 | −body::before { | |
| 50 | − content: ""; | |
| 51 | − position: fixed; inset: 0; z-index: 0; pointer-events: none; opacity: 0.35; | |
| 52 | − background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.02 0'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E"); | |
| 53 | −} | |
| 54 | −#root { position: relative; z-index: 1; } | |
| 55 | − | |
| 56 | −h1, h2, h3, h4 { font-family: var(--font-display); letter-spacing: -0.03em; margin: 0; } | |
| 57 | −a { color: inherit; text-decoration: none; } | |
| 23 | +} | |
| 24 | + | |
| 25 | +/* — surcharges locales du socle (layout historique d'Auto-Ka) — */ | |
| 26 | +h1, h2, h3, h4 { margin: 0; } | |
| 27 | +a { text-decoration: none; } | |
| 58 | 28 | button { font-family: inherit; } |
| 59 | −img { display: block; } | |
| 60 | −::selection { background: var(--accent); color: #fff; } | |
| 61 | 29 | |
| 62 | 30 | .mono { font-family: var(--font-mono); } |
| 63 | −.kicker { | |
| 64 | − font-family: var(--font-mono); font-size: 11.5px; font-weight: 500; | |
| 65 | − text-transform: uppercase; letter-spacing: 0.14em; color: var(--accent-deep); | |
| 66 | − display: inline-flex; align-items: center; gap: 8px; | |
| 67 | −} | |
| 68 | −.kicker::before { content: ""; width: 22px; height: 2px; background: var(--accent); } | |
| 31 | +.kicker { color: var(--accent-deep); } | |
| 32 | +.kicker::before { background: var(--accent); } | |
| 69 | 33 | |
| 70 | −.container { max-width: 1280px; margin: 0 auto; padding: 0 24px; } | |
| 34 | +.container { max-width: 1280px; padding: 0 24px; } | |
| 71 | 35 | @media (max-width: 640px) { .container { padding: 0 16px; } } |
| 72 | 36 | |
| 73 | 37 | /* ================= Header ================= */ |
| 74 | 38 | .header { |
| 75 | 39 | position: sticky; top: 0; z-index: 50; |
| 76 | − background: rgba(244, 242, 236, 0.88); | |
| 40 | + background: rgba(245, 243, 238, 0.88); /* var(--paper) à 88 % */ | |
| 77 | 41 | backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); |
| 78 | 42 | border-bottom: 2px solid var(--ink); |
| 79 | 43 | } |
@@ -93,11 +57,16 @@ img { display: block; } | ||
| 93 | 57 | letter-spacing: 0.08em; text-transform: uppercase; margin-left: 12px; |
| 94 | 58 | } |
| 95 | 59 | @media (max-width: 860px) { .brand-tag { display: none; } } |
| 96 | −.nav { margin-left: auto; display: flex; gap: 4px; } | |
| 60 | +.nav { | |
| 61 | + margin-left: auto; display: flex; gap: 4px; | |
| 62 | + overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; | |
| 63 | +} | |
| 64 | +.nav::-webkit-scrollbar { display: none; } | |
| 65 | +.nav a { flex: none; } | |
| 97 | 66 | .nav a { |
| 98 | 67 | padding: 9px 16px; border-radius: 999px; font-weight: 600; font-size: 14px; |
| 99 | 68 | color: var(--ink-2); border: 1.5px solid transparent; |
| 100 | − transition: all 0.15s ease; min-height: 40px; display: inline-flex; align-items: center; | |
| 69 | + transition: all 0.15s ease; min-height: 44px; display: inline-flex; align-items: center; | |
| 101 | 70 | } |
| 102 | 71 | .nav a:hover { border-color: var(--ink); color: var(--ink); } |
| 103 | 72 | .nav a.active { background: var(--ink); color: var(--accent); } |
@@ -105,6 +74,17 @@ img { display: block; } | ||
| 105 | 74 | .nav a { padding: 8px 11px; font-size: 13px; } |
| 106 | 75 | } |
| 107 | 76 | |
| 77 | +/* — badge « Un service Groupe KA » (composant ka/GroupeKaBadge) — */ | |
| 78 | +.header .gk-badge { flex: none; margin-left: 2px; } | |
| 79 | +@media (max-width: 1023px) { .header .gk-badge { display: none; } } | |
| 80 | +/* variante mobile : petite barre sous le ticker, tactile ≥ 44 px */ | |
| 81 | +.gk-mobile { | |
| 82 | + display: none; align-items: center; justify-content: center; | |
| 83 | + min-height: 44px; padding: 5px 16px; | |
| 84 | + background: var(--surface-2); border-bottom: 1.5px solid var(--line); | |
| 85 | +} | |
| 86 | +@media (max-width: 1023px) { .gk-mobile { display: flex; } } | |
| 87 | + | |
| 108 | 88 | /* ================= Ticker ================= */ |
| 109 | 89 | .ticker { |
| 110 | 90 | background: var(--ink); color: var(--accent); overflow: hidden; |
@@ -152,7 +132,7 @@ img { display: block; } | ||
| 152 | 132 | .f-field select, .f-field input { |
| 153 | 133 | border: 1.5px solid var(--line-strong); border-radius: var(--r-ctl); |
| 154 | 134 | background: var(--surface); font: inherit; font-size: 14px; |
| 155 | − padding: 9px 10px; min-height: 40px; color: var(--ink); | |
| 135 | + padding: 9px 10px; min-height: 44px; color: var(--ink); | |
| 156 | 136 | } |
| 157 | 137 | .f-field select:focus, .f-field input:focus { |
| 158 | 138 | outline: 2px solid var(--accent); outline-offset: 1px; |
@@ -161,8 +141,8 @@ img { display: block; } | ||
| 161 | 141 | .btn { |
| 162 | 142 | font-family: var(--font-display); font-weight: 600; font-size: 14.5px; |
| 163 | 143 | border: 2px solid var(--ink); border-radius: var(--r-ctl); |
| 164 | − background: var(--ink); color: #fff; cursor: pointer; | |
| 165 | − padding: 9px 18px; min-height: 40px; | |
| 144 | + background: var(--ink); color: var(--paper); cursor: pointer; | |
| 145 | + padding: 9px 18px; min-height: 44px; | |
| 166 | 146 | transition: transform 0.12s ease, box-shadow 0.12s ease; |
| 167 | 147 | } |
| 168 | 148 | .btn:hover { transform: translate(-2px, -2px); box-shadow: 4px 4px 0 var(--accent); } |
@@ -205,19 +185,19 @@ img { display: block; } | ||
| 205 | 185 | } |
| 206 | 186 | .vcard .year-chip { |
| 207 | 187 | position: absolute; top: 10px; left: 10px; |
| 208 | − background: var(--ink); color: #fff; font-family: var(--font-mono); | |
| 188 | + background: var(--ink); color: var(--paper); font-family: var(--font-mono); | |
| 209 | 189 | font-size: 11.5px; font-weight: 600; padding: 3px 9px; border-radius: 999px; |
| 210 | 190 | } |
| 211 | 191 | .vcard .drop-chip { |
| 212 | 192 | position: absolute; top: 10px; right: 10px; |
| 213 | − background: var(--good); color: #fff; font-family: var(--font-mono); | |
| 193 | + background: var(--good); color: var(--paper); font-family: var(--font-mono); | |
| 214 | 194 | font-size: 10.5px; font-weight: 600; padding: 3px 9px; border-radius: 999px; |
| 215 | 195 | } |
| 216 | 196 | |
| 217 | 197 | /* ===== Favoris — cœur rond « Mon univers Ka » en coin de photo ===== */ |
| 218 | 198 | .fav-btn { |
| 219 | 199 | position: absolute; right: 10px; bottom: 10px; z-index: 2; |
| 220 | − width: 34px; height: 34px; padding: 0; | |
| 200 | + width: 44px; height: 44px; padding: 0; | |
| 221 | 201 | display: flex; align-items: center; justify-content: center; |
| 222 | 202 | background: rgba(255, 255, 255, 0.94); border: 2px solid var(--ink); |
| 223 | 203 | border-radius: 999px; cursor: pointer; color: var(--ink); |
@@ -227,7 +207,7 @@ img { display: block; } | ||
| 227 | 207 | .fav-btn.on { background: var(--accent-soft); color: var(--accent-deep); } |
| 228 | 208 | .fav-btn.on svg { filter: drop-shadow(0 0 3px rgba(204, 63, 22, 0.35)); } |
| 229 | 209 | .gallery .main { position: relative; } |
| 230 | −.gallery .main .fav-btn { right: 14px; bottom: 14px; width: 42px; height: 42px; } | |
| 210 | +.gallery .main .fav-btn { right: 14px; bottom: 14px; width: 44px; height: 44px; } | |
| 231 | 211 | .gallery .main .fav-btn svg { width: 20px; height: 20px; } |
| 232 | 212 | .vcard .body { padding: 14px 16px 16px; display: flex; flex-direction: column; gap: 8px; flex: 1; } |
| 233 | 213 | .vcard h3 { font-size: 16.5px; line-height: 1.25; } |
@@ -296,7 +276,7 @@ img { display: block; } | ||
| 296 | 276 | |
| 297 | 277 | .cta-source { |
| 298 | 278 | display: block; text-align: center; font-family: var(--font-display); |
| 299 | − font-weight: 700; font-size: 16px; background: var(--accent); color: #fff; | |
| 279 | + font-weight: 700; font-size: 16px; background: var(--accent); color: var(--on-accent); | |
| 300 | 280 | border: 2px solid var(--ink); border-radius: var(--r-ctl); |
| 301 | 281 | padding: 13px 18px; margin-top: 4px; |
| 302 | 282 | transition: transform 0.12s ease, box-shadow 0.12s ease; |
@@ -359,7 +339,7 @@ img { display: block; } | ||
| 359 | 339 | |
| 360 | 340 | .chart-tip { |
| 361 | 341 | position: absolute; transform: translate(-50%, -100%); pointer-events: none; |
| 362 | − background: var(--ink); color: #fff; font-size: 12.5px; line-height: 1.35; | |
| 342 | + background: var(--ink); color: var(--paper); font-size: 12.5px; line-height: 1.35; | |
| 363 | 343 | padding: 6px 10px; border-radius: 6px; white-space: nowrap; z-index: 5; |
| 364 | 344 | box-shadow: 0 4px 14px rgba(23,24,28,0.25); |
| 365 | 345 | } |
@@ -466,20 +446,20 @@ img { display: block; } | ||
| 466 | 446 | font-family: var(--font-display); font-weight: 600; font-size: 13.5px; |
| 467 | 447 | border: 2px solid var(--ink); border-radius: 999px; |
| 468 | 448 | background: var(--surface); color: var(--ink); |
| 469 | − padding: 8px 15px; min-height: 40px; flex: none; | |
| 449 | + padding: 8px 15px; min-height: 44px; flex: none; | |
| 470 | 450 | transition: transform 0.12s ease, box-shadow 0.12s ease; |
| 471 | 451 | } |
| 472 | 452 | .login-btn:hover { transform: translate(-2px, -2px); box-shadow: 4px 4px 0 var(--accent); } |
| 473 | 453 | .login-ka { |
| 474 | 454 | display: inline-flex; align-items: center; justify-content: center; |
| 475 | 455 | width: 18px; height: 16px; border-radius: 4px; |
| 476 | − background: #141814; color: #d9f26b; | |
| 456 | + background: var(--ink); color: #d9f26b; /* lime KA ID — identité du groupe */ | |
| 477 | 457 | font: 700 9px/1 var(--font-display); letter-spacing: -0.02em; |
| 478 | 458 | transform: rotate(-2deg); |
| 479 | 459 | } |
| 480 | 460 | .account { position: relative; flex: none; } |
| 481 | 461 | .account-btn { |
| 482 | − width: 40px; height: 40px; padding: 0; cursor: pointer; | |
| 462 | + width: 44px; height: 44px; padding: 0; cursor: pointer; | |
| 483 | 463 | border: 2px solid var(--ink); border-radius: 999px; overflow: hidden; |
| 484 | 464 | background: var(--surface); display: flex; align-items: center; justify-content: center; |
| 485 | 465 | transition: transform 0.12s ease, box-shadow 0.12s ease; |
@@ -488,7 +468,7 @@ img { display: block; } | ||
| 488 | 468 | .account-btn img { width: 100%; height: 100%; object-fit: cover; } |
| 489 | 469 | .account-initial { |
| 490 | 470 | font-family: var(--font-display); font-weight: 700; font-size: 17px; |
| 491 | − background: var(--accent); color: #fff; width: 100%; height: 100%; | |
| 471 | + background: var(--accent); color: var(--on-accent); width: 100%; height: 100%; | |
| 492 | 472 | display: flex; align-items: center; justify-content: center; |
| 493 | 473 | } |
| 494 | 474 | .account-backdrop { position: fixed; inset: 0; z-index: 60; } |
@@ -608,19 +588,42 @@ a.hub-chip:hover { border-color: var(--ink); color: var(--ink); } | ||
| 608 | 588 | .profil-note a { text-decoration: underline; text-underline-offset: 3px; } |
| 609 | 589 | .profil-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 26px; } |
| 610 | 590 | |
| 611 | −/* ================= Footer ================= */ | |
| 612 | −.footer { | |
| 613 | − background: var(--ink); color: #c9cbd1; margin-top: 30px; | |
| 614 | − padding: 42px 0 30px; border-top: 3px solid var(--accent); | |
| 591 | +/* ================= Footer ================= | |
| 592 | + Le footer est désormais le KaFooter commun (ka/KaFooter.tsx + .ka-footer | |
| 593 | + dans ka/tokens.css). Bordure accent au-dessus, signature Auto-Ka. */ | |
| 594 | +.ka-footer { border-top: 3px solid var(--accent); } | |
| 595 | + | |
| 596 | +/* ================= Page /contact ================= */ | |
| 597 | +.contact-grid { | |
| 598 | + display: grid; gap: 14px; margin: 22px 0 6px; | |
| 599 | + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); max-width: 900px; | |
| 615 | 600 | } |
| 616 | −.fbrand { font-family: var(--font-display); font-weight: 700; font-size: 24px; color: #fff; margin-bottom: 14px; } | |
| 617 | −.fbrand .ka { background: var(--accent); color: var(--ink); padding: 1px 6px 3px; border-radius: 5px; margin-left: 2px; display: inline-block; transform: rotate(-2deg); } | |
| 618 | −.frow { font-size: 13.5px; max-width: 560px; line-height: 1.6; } | |
| 619 | −.fmono { font-family: var(--font-mono); font-size: 11px; color: #82858d; margin-top: 22px; } | |
| 620 | −.fmono a { text-decoration: underline; } | |
| 601 | +.contact-card { | |
| 602 | + background: var(--surface); border: 2px solid var(--ink); border-radius: var(--r-card); | |
| 603 | + padding: 16px 18px; display: flex; flex-direction: column; gap: 6px; | |
| 604 | + box-shadow: var(--shadow-flat); | |
| 605 | + transition: transform 0.14s ease, box-shadow 0.14s ease; | |
| 606 | +} | |
| 607 | +.contact-card:hover { transform: translate(-2px, -2px); box-shadow: var(--shadow-off); } | |
| 608 | +.contact-card a.mail { | |
| 609 | + font-family: var(--font-mono); font-weight: 700; font-size: 14px; | |
| 610 | + color: var(--accent-deep); word-break: break-all; | |
| 611 | + display: inline-flex; align-items: center; min-height: 44px; | |
| 612 | +} | |
| 613 | +.contact-card a.mail:hover { text-decoration: underline; text-underline-offset: 3px; } | |
| 614 | +.contact-card .role { font-size: 13px; color: var(--ink-2); } | |
| 615 | +.contact-note { | |
| 616 | + max-width: 720px; margin: 24px 0; padding: 14px 18px; | |
| 617 | + background: var(--accent-soft); border: 2px solid var(--ink); | |
| 618 | + border-left-width: 6px; border-radius: var(--r-card); font-size: 14px; | |
| 619 | +} | |
| 620 | +.contact-sites { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; max-width: 900px; } | |
| 621 | +.contact-sites a.spec-chip { text-decoration: none; min-height: 32px; display: inline-flex; align-items: center; } | |
| 622 | +.contact-sites a.spec-chip:hover { border-color: var(--accent); color: var(--ink); } | |
| 623 | +.contact-hub { margin-top: 26px; } | |
| 621 | 624 | |
| 622 | 625 | /* --- blocs SEO (pages programmatiques rendues serveur + React) --------------- */ |
| 623 | −.breadcrumbs { font-size: 12px; color: var(--muted, #82858d); margin: 14px 0 4px; } | |
| 626 | +.breadcrumbs { font-size: 12px; color: var(--ink-3); margin: 14px 0 4px; } | |
| 624 | 627 | .breadcrumbs a { text-decoration: underline; } |
| 625 | 628 | .seo-block { margin: 30px 0; } |
| 626 | 629 | .seo-block h2 { font-size: 17px; margin: 0 0 12px; } |
| 627 | 630 | |