mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-19 05:06:56 +02:00
Petits multiples empiles sur un axe des mois commun, palette validee par script, etiquetage selectif, survol et vue tableau. FORME. Trois mesures d'ordres de grandeur differents (qte/magasin, volumes, magasins) ne peuvent pas partager un cadre : il faudrait deux ou trois echelles verticales dont l'alignement serait arbitraire, ce qui inventerait des correlations absentes des donnees. Trois facettes, une echelle chacune, le meme axe horizontal. La facette PRINCIPALE est la qte/magasin. COULEUR. Slots 1-3 de la palette categorielle de reference, en variables CSS, avec un jeu de pas CHOISI pour le fond sombre (pas un eclaircissement automatique). Palette passee au validateur dans les deux modes, toutes paires : bande de clarte, plancher de chroma, separation daltonienne (pire paire ΔE 9,2 clair / 9,4 sombre) et contraste. En mode clair l'aqua tombe a 2,82:1 — la regle de relief s'applique, d'ou etiquettes visibles ET vue tableau, toutes deux presentes. La teinte de tendance (vert/rouge/gris) ne vit plus que dans la tuile de verdict, avec fleche et libelle : un etat ne se signale jamais par la couleur seule, et la meme couleur ne veut pas dire deux choses. LISIBILITE. Etiquetage selectif — l'extreme et le dernier mois, pas les 36 valeurs. Le texte ne porte jamais la couleur d'une serie (illisible en teinte claire) : l'identite vient du repere pose a cote. Filets de base pleins et discrets, jamais pointilles. Reticule au survol reliant les trois facettes au meme mois, et vue tableau depliable : aucune valeur n'est accessible au seul survol. En-tete refait en tuiles : verdict, qte/magasin du dernier mois, magasins vendeurs. Chiffres proportionnels sur les valeurs mises en avant, tabulaires seulement dans le tableau ou les colonnes s'alignent. Rendu verifie en image dans les deux themes avant livraison : la version precedente faisait passer l'etiquette du pic par-dessus le titre de la facette — elle bascule desormais sous le point quand elle toucherait le bandeau. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DfqUihgixw4K1AmJhizWiu
499 lines
12 KiB
CSS
499 lines
12 KiB
CSS
@import "tailwindcss";
|
|
|
|
/* Police de l'app : Inter (chargée via <link> dans le layout, fallback système).
|
|
Définie ici pour que l'utilitaire `font-sans` et var(--font-sans) la prennent
|
|
sans recourir à next/font/google (pas de fetch réseau au build). */
|
|
@theme {
|
|
--font-sans: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
}
|
|
|
|
|
|
/* ═══════════════════════════════════════════
|
|
CollectFlow — Apple-inspired Design System
|
|
═══════════════════════════════════════════ */
|
|
|
|
/* ── Dark Mode (default) ── */
|
|
:root {
|
|
/* Apple macOS dark aligned to Slate palette as per UX Spec */
|
|
--bg-base: #020617;
|
|
/* Slate 950 */
|
|
--bg-surface: #0f172a;
|
|
/* Slate 900 */
|
|
--bg-elevated: #1e293b;
|
|
/* Slate 800 */
|
|
--bg-overlay: rgba(15, 23, 42, 0.85);
|
|
/* Slate 900 with opacity */
|
|
--border: #334155;
|
|
/* Slate 700 */
|
|
|
|
/* ── Palette data-viz (3 séries) ──
|
|
Slots 1-3 de la palette catégorielle de référence, pas-de-teinte propre au
|
|
fond sombre. Validée sur ce fond : bande de clarté, plancher de chroma,
|
|
séparation daltonienne (pire paire ΔE 9,4) et contraste ≥ 3:1 — toutes
|
|
paires, pas seulement les adjacentes. Ne pas retoucher une valeur isolément :
|
|
c'est l'ENSEMBLE qui passe les contrôles. */
|
|
--viz-1: #3987e5;
|
|
--viz-2: #d95926;
|
|
--viz-3: #199e70;
|
|
--border-strong: #475569;
|
|
/* Slate 600 */
|
|
|
|
--text-primary: #e2e8f0;
|
|
/* Slate 200 */
|
|
--text-secondary: #94a3b8;
|
|
/* Slate 400 */
|
|
--text-muted: #64748b;
|
|
/* Slate 500 */
|
|
|
|
--accent: #2dd4bf;
|
|
/* emerald-ish, Apple-tuned */
|
|
--accent-bg: rgba(45, 212, 191, 0.10);
|
|
--accent-border: rgba(45, 212, 191, 0.20);
|
|
|
|
/* Semantic UI accents */
|
|
--accent-success: #10b981;
|
|
--accent-success-bg: rgba(16, 185, 129, 0.10);
|
|
--accent-warning: #f59e0b;
|
|
--accent-warning-bg: rgba(245, 158, 11, 0.10);
|
|
--accent-error: #f43f5e;
|
|
--accent-error-bg: rgba(244, 63, 94, 0.10);
|
|
|
|
/* Primary Action / Brand */
|
|
--brand-solid: #10b981;
|
|
--brand-hover: #059669;
|
|
--action-secondary-bg: #2c2c2e;
|
|
--action-secondary-text: #f5f5f7;
|
|
--action-secondary-border: rgba(255, 255, 255, 0.1);
|
|
|
|
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.6), 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.7), 0 1px 4px rgba(0, 0, 0, 0.5);
|
|
--shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.8), 0 2px 8px rgba(0, 0, 0, 0.6);
|
|
}
|
|
|
|
/* ── Light Mode ── */
|
|
.light {
|
|
--bg-base: #f5f5f7;
|
|
/* Apple light gray */
|
|
--bg-surface: #ffffff;
|
|
--bg-elevated: #f0f0f5;
|
|
--bg-overlay: rgba(255, 255, 255, 0.82);
|
|
--border: rgba(0, 0, 0, 0.07);
|
|
--border-strong: rgba(0, 0, 0, 0.12);
|
|
|
|
/* Mêmes teintes, pas choisis pour le fond clair (et non un simple éclaircissement
|
|
des valeurs sombres). L'aqua passe sous 3:1 sur blanc : la « règle de relief »
|
|
s'applique — étiquettes directes visibles + vue tableau, toutes deux présentes. */
|
|
--viz-1: #2a78d6;
|
|
--viz-2: #eb6834;
|
|
--viz-3: #1baf7a;
|
|
|
|
--text-primary: #1d1d1f;
|
|
/* Apple dark */
|
|
--text-secondary: #515154;
|
|
--text-muted: #86868b;
|
|
|
|
--accent: #0d9488;
|
|
/* deeper teal in light */
|
|
--accent-bg: rgba(13, 148, 136, 0.08);
|
|
--accent-border: rgba(13, 148, 136, 0.18);
|
|
|
|
/* Semantic UI accents (Light Mode Adjustments) */
|
|
--accent-success: #059669;
|
|
--accent-success-bg: rgba(5, 150, 105, 0.08);
|
|
--accent-warning: #d97706;
|
|
--accent-warning-bg: rgba(217, 119, 6, 0.08);
|
|
--accent-error: #e11d48;
|
|
--accent-error-bg: rgba(225, 29, 72, 0.08);
|
|
|
|
/* Primary Action / Brand (Light) */
|
|
--brand-solid: #0d9488;
|
|
--brand-hover: #0f766e;
|
|
--action-secondary-bg: #ffffff;
|
|
--action-secondary-text: #1d1d1f;
|
|
--action-secondary-border: rgba(0, 0, 0, 0.1);
|
|
|
|
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.10), 0 1px 4px rgba(0, 0, 0, 0.06);
|
|
--shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
}
|
|
|
|
@layer base {
|
|
html {
|
|
color-scheme: dark;
|
|
/* Force no system scroll jump */
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
}
|
|
|
|
html.light {
|
|
color-scheme: light;
|
|
}
|
|
|
|
body {
|
|
background-color: var(--bg-base);
|
|
color: var(--text-primary);
|
|
font-family: var(--font-sans, -apple-system, "Inter", system-ui, sans-serif);
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
transition: background-color 0.25s cubic-bezier(0.4, 0, 0.2, 1),
|
|
color 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
/* Apple-style focus ring */
|
|
*:focus-visible {
|
|
outline: 2px solid var(--accent);
|
|
outline-offset: 2px;
|
|
border-radius: 4px;
|
|
}
|
|
}
|
|
|
|
/* ── Typography ── */
|
|
.text-primary {
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.text-secondary {
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.text-muted {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* ── Surfaces & containers ── */
|
|
.surface {
|
|
background: var(--bg-surface);
|
|
}
|
|
|
|
.elevated {
|
|
background: var(--bg-elevated);
|
|
}
|
|
|
|
.apple-card {
|
|
background: var(--bg-surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: 14px;
|
|
overflow: hidden;
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
.apple-card-header {
|
|
padding: 16px 20px;
|
|
background: var(--bg-elevated);
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
.apple-card-content {
|
|
padding: 20px;
|
|
}
|
|
|
|
/* ── Glass panels (sidebar, header) ── */
|
|
.glass {
|
|
background: var(--bg-overlay);
|
|
backdrop-filter: saturate(180%) blur(20px);
|
|
-webkit-backdrop-filter: saturate(180%) blur(20px);
|
|
}
|
|
|
|
/* ── Apple border ── */
|
|
.border-apple {
|
|
border: 1px solid var(--border);
|
|
}
|
|
|
|
.border-apple-strong {
|
|
border: 1px solid var(--border-strong);
|
|
}
|
|
|
|
/* ── Tabular numbers & Mono ── */
|
|
.tabular-nums {
|
|
font-variant-numeric: tabular-nums;
|
|
letter-spacing: -0.015em;
|
|
}
|
|
|
|
.font-mono-nums {
|
|
font-family: var(--font-sans, system-ui, sans-serif);
|
|
font-variant-numeric: tabular-nums;
|
|
letter-spacing: -0.015em;
|
|
}
|
|
|
|
/* ── Refined scrollbar ── */
|
|
.overflow-auto::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
|
|
.overflow-auto::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
|
|
.overflow-auto::-webkit-scrollbar-thumb {
|
|
background: var(--border-strong);
|
|
border-radius: 99px;
|
|
}
|
|
|
|
.overflow-auto::-webkit-scrollbar-thumb:hover {
|
|
background: rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.light .overflow-auto::-webkit-scrollbar-thumb:hover {
|
|
background: rgba(0, 0, 0, 0.18);
|
|
}
|
|
|
|
/* ── Heatmap cells ── */
|
|
.heatmap-zero {
|
|
background: var(--bg-elevated);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.heatmap-low {
|
|
background: rgba(14, 165, 233, 0.08);
|
|
/* sky-500 */
|
|
color: rgba(14, 165, 233, 0.70);
|
|
}
|
|
|
|
.heatmap-mid {
|
|
background: rgba(14, 165, 233, 0.15);
|
|
color: rgba(14, 165, 233, 0.90);
|
|
}
|
|
|
|
.heatmap-high {
|
|
background: rgba(14, 165, 233, 0.25);
|
|
color: #0ea5e9;
|
|
}
|
|
|
|
.light .heatmap-low {
|
|
background: rgba(2, 132, 199, 0.08);
|
|
/* sky-600 */
|
|
color: #0369a1;
|
|
}
|
|
|
|
.light .heatmap-mid {
|
|
background: rgba(2, 132, 199, 0.14);
|
|
color: #0284c7;
|
|
}
|
|
|
|
.light .heatmap-high {
|
|
background: rgba(2, 132, 199, 0.22);
|
|
color: #0369a1;
|
|
}
|
|
|
|
/* ── Apple-style input ── */
|
|
.apple-input {
|
|
width: 100%;
|
|
background: var(--bg-elevated);
|
|
border: 1px solid var(--border);
|
|
border-radius: 8px;
|
|
padding: 8px 12px;
|
|
font-size: 13px;
|
|
color: var(--text-primary);
|
|
transition: border-color 0.15s, box-shadow 0.15s;
|
|
}
|
|
|
|
.apple-input::placeholder {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.apple-input:focus {
|
|
outline: none;
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 3px var(--accent-bg);
|
|
}
|
|
|
|
/* ── Apple-style Action Buttons (Glossy & Premium v2) ── */
|
|
.apple-btn-primary,
|
|
.apple-btn-secondary,
|
|
.apple-btn-danger,
|
|
.apple-btn-ai,
|
|
.apple-btn-rules {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 10px;
|
|
height: 40px;
|
|
padding: 0 20px;
|
|
border-radius: 12px;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
cursor: pointer;
|
|
position: relative;
|
|
overflow: hidden;
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.apple-btn-primary {
|
|
background: linear-gradient(180deg, var(--brand-solid) 0%, var(--brand-hover) 100%);
|
|
color: #ffffff;
|
|
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.25), inset 0 1px 1px rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.apple-btn-secondary,
|
|
.apple-btn-rules {
|
|
background: var(--bg-surface);
|
|
color: var(--text-primary);
|
|
border-color: var(--border-strong);
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.05);
|
|
}
|
|
|
|
.apple-btn-danger {
|
|
background: linear-gradient(180deg, var(--accent-error) 0%, #be123c 100%);
|
|
color: #ffffff;
|
|
box-shadow: 0 4px 12px rgba(244, 63, 94, 0.25), inset 0 1px 1px rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.apple-btn-ai {
|
|
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #d946ef 100%);
|
|
color: #ffffff;
|
|
box-shadow: 0 4px 15px rgba(139, 92, 246, 0.3), inset 0 1px 1px rgba(255, 255, 255, 0.3);
|
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
.apple-btn-primary:hover,
|
|
.apple-btn-danger:hover,
|
|
.apple-btn-ai:hover {
|
|
filter: brightness(1.1);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.apple-btn-secondary:hover,
|
|
.apple-btn-rules:hover {
|
|
background: var(--bg-elevated);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.apple-btn-primary:active,
|
|
.apple-btn-secondary:active,
|
|
.apple-btn-danger:active,
|
|
.apple-btn-ai:active,
|
|
.apple-btn-rules:active {
|
|
transform: scale(0.97) translateY(0);
|
|
}
|
|
|
|
/* Glass effect overlay for loading/success */
|
|
.btn-glass-overlay {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
backdrop-filter: blur(4px);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
@keyframes apple-pulse {
|
|
0% {
|
|
transform: scale(1);
|
|
box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4);
|
|
}
|
|
|
|
70% {
|
|
transform: scale(1.02);
|
|
box-shadow: 0 0 0 10px rgba(16, 185, 129, 0);
|
|
}
|
|
|
|
100% {
|
|
transform: scale(1);
|
|
box-shadow: 0 0 0 0 rgba(16, 185, 129, 0);
|
|
}
|
|
}
|
|
|
|
.animate-apple-save {
|
|
animation: apple-pulse 2s infinite ease-in-out;
|
|
}
|
|
|
|
.btn-action {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 8px;
|
|
height: 36px;
|
|
padding: 0 16px;
|
|
border-radius: 10px;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
transition: all 0.15s ease-out;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.btn-action:active {
|
|
transform: scale(0.96);
|
|
}
|
|
|
|
.btn-action:disabled {
|
|
opacity: 0.5;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.btn-action-primary {
|
|
background: var(--brand-solid);
|
|
color: #fff;
|
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.btn-action-primary:hover {
|
|
filter: brightness(1.1);
|
|
}
|
|
|
|
.btn-action-secondary {
|
|
background: var(--bg-surface);
|
|
color: var(--text-primary);
|
|
border: 1px solid var(--border-strong);
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.btn-action-secondary:hover {
|
|
background: var(--bg-elevated);
|
|
}
|
|
|
|
.btn-action-ai {
|
|
background: var(--accent);
|
|
color: #fff;
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.btn-action-ai:hover {
|
|
filter: brightness(1.1);
|
|
}
|
|
|
|
.btn-action-success {
|
|
background: var(--accent-success-bg);
|
|
color: var(--accent-success);
|
|
border: 1px solid var(--accent-success);
|
|
cursor: default;
|
|
}
|
|
|
|
.btn-action-success:active {
|
|
transform: none;
|
|
}
|
|
|
|
/* ── Segment control (theme toggle) ── */
|
|
.segment-control {
|
|
display: inline-flex;
|
|
gap: 2px;
|
|
padding: 3px;
|
|
background: var(--bg-elevated);
|
|
border: 1px solid var(--border);
|
|
border-radius: 9px;
|
|
}
|
|
|
|
.segment-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
padding: 5px 14px;
|
|
border-radius: 7px;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
border: none;
|
|
background: transparent;
|
|
color: var(--text-secondary);
|
|
transition: background 0.15s, color 0.15s, box-shadow 0.15s;
|
|
}
|
|
|
|
.segment-btn.active {
|
|
background: var(--bg-surface);
|
|
color: var(--text-primary);
|
|
box-shadow: var(--shadow-sm);
|
|
} |