Adopte le langage visuel du design system Emerald dans l'IDE web : neutres zinc + accent emerald, polices auto-hébergées Inter + JetBrains Mono, radii/pills mono, points de statut, motif terminal, halo/grain. Refonte purement visuelle et additive (layout, routing, stores, protocole inchangés). - style.css : défauts sombres dans @theme + override clair sous html[data-theme=light] ; accent scindé (bright #34d399 / solid #059669 / hover) ; tokens border-soft/info/warn/danger/coffee ; idiomes globaux (focus/selection accent, scrollbars fines, jl-pulse/jl-blink, classes .chip/.status/.eyebrow/.label-mono/.caret/.halo/.grain, .btn*/.badge pill). - lib/theme.ts : singleton themeMode/resolvedTheme (dark/light/system, persistedRef arb.theme) + application dataset.theme/metas ; script anti-FOUC inline dans index.html ; toggle ActivityBar + Réglages. - Thèmes Monaco + xterm dark/light réactifs (palette ANSI + coloration syntaxique) ; fonts.ready + remeasureFonts pour l'alignement des glyphes. - status-tokens : tons sémantiques tokenisés ; balayage des ~340 couleurs Tailwind brutes vers les tokens sur tout components/* et views/* (exceptions assumées commentées). - GroupSummary.color exploité : icône de groupe teintée + ColorSwatchPicker (lib/group-colors.ts) dans les modals de groupe. - Polices via @fontsource-variable/{inter,jetbrains-mono} (offline).
298 lines
11 KiB
CSS
298 lines
11 KiB
CSS
@import 'tailwindcss';
|
|
|
|
/* ============================================================
|
|
Tokens de design « Emerald ».
|
|
Couche SÉMANTIQUE : les défauts (bloc @theme) portent les valeurs du thème SOMBRE ;
|
|
le thème CLAIR redéfinit les mêmes --color-* sous html[data-theme="light"].
|
|
Mécanique Tailwind v4 : @theme émet les vars sur :root et les utilitaires
|
|
(bg-surface-0, text-fg, ...) RÉFÉRENCENT ces vars ; comme [data-theme=light] cible le
|
|
même <html> que :root (et gagne la cascade), il suffit de réécrire les vars pour
|
|
basculer tout le thème, sans dupliquer d'utilitaires. Les modificateurs d'opacité
|
|
(bg-danger/15) génèrent un color-mix(... var(--color-danger) ...) → suivent le thème.
|
|
============================================================ */
|
|
@theme {
|
|
/* Ombres (sombre par défaut ; override clair plus bas). */
|
|
--shadow-card: 0 1px 2px 0 rgb(0 0 0 / 0.4);
|
|
--shadow-pop: 0 24px 48px -20px rgb(0 0 0 / 0.65);
|
|
|
|
/* Surfaces : du fond le plus profond de l'app aux surfaces survolées. */
|
|
--color-surface-0: #09090b; /* fond application (Emerald --bg) */
|
|
--color-surface-1: #18181b; /* cartes, panneaux (Emerald --surface) */
|
|
--color-surface-2: #27272a; /* surface interactive opaque (boutons, chips) */
|
|
--color-surface-3: #3f3f46; /* survol des surfaces */
|
|
|
|
/* Bordures. */
|
|
--color-border: #27272a;
|
|
--color-border-strong: #3f3f46;
|
|
--color-border-soft: #1c1c1f; /* séparateurs discrets (Emerald --border-soft) */
|
|
|
|
/* Texte. */
|
|
--color-fg: #f4f4f5;
|
|
--color-fg-muted: #a1a1aa;
|
|
--color-fg-subtle: #52525b;
|
|
|
|
/* Accent. Emerald scinde en 3 :
|
|
- accent (BRIGHT #34d399) : texte, points, anneaux, liens, carets, indicateurs ;
|
|
- accent-solid (#059669) : fond plein avec texte blanc (bouton primaire) ;
|
|
- accent-hover (#10b981) : survol du plein. */
|
|
--color-accent: #34d399;
|
|
--color-accent-solid: #059669;
|
|
--color-accent-hover: #10b981;
|
|
|
|
/* Tons sémantiques (statuts / signalétique). */
|
|
--color-coffee: #f59e0b;
|
|
--color-info: #7dd3fc;
|
|
--color-warn: #fcd34d;
|
|
--color-danger: #f87171;
|
|
|
|
/* Polices auto-hébergées (fontes variables). Ces tokens alimentent aussi font-sans /
|
|
font-mono de Tailwind. Noms exacts des paquets @fontsource-variable : "... Variable". */
|
|
--font-sans: 'Inter Variable', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
--font-mono: 'JetBrains Mono Variable', ui-monospace, 'Fira Code', Menlo, Consolas, monospace;
|
|
}
|
|
|
|
/* ---------- Thème clair : réécriture des mêmes tokens (même élément que :root) ---------- */
|
|
html[data-theme='light'] {
|
|
--shadow-card: 0 1px 2px 0 rgb(24 24 27 / 0.08);
|
|
--shadow-pop: 0 18px 38px -22px rgb(24 24 27 / 0.22);
|
|
|
|
--color-surface-0: #fafafa;
|
|
--color-surface-1: #ffffff;
|
|
--color-surface-2: #f4f4f5;
|
|
--color-surface-3: #e4e4e7;
|
|
|
|
--color-border: #e4e4e7;
|
|
--color-border-strong: #d4d4d8;
|
|
--color-border-soft: #ececee;
|
|
|
|
--color-fg: #18181b;
|
|
--color-fg-muted: #52525b;
|
|
--color-fg-subtle: #a1a1aa;
|
|
|
|
--color-accent: #059669;
|
|
--color-accent-solid: #059669;
|
|
--color-accent-hover: #047857;
|
|
|
|
--color-coffee: #d97706;
|
|
--color-info: #0284c7;
|
|
--color-warn: #d97706;
|
|
--color-danger: #dc2626;
|
|
}
|
|
|
|
/* Métriques du chrome IDE (barres, onglets, lignes), indépendantes du thème.
|
|
Consommées via des valeurs arbitraires Tailwind, ex. h-[var(--ide-tab-h)]. */
|
|
:root {
|
|
--ide-activitybar-w: 3rem;
|
|
--ide-titlebar-h: 2.25rem;
|
|
--ide-tab-h: 2.25rem;
|
|
--ide-statusbar-h: 1.5rem;
|
|
--ide-row-h: 1.75rem;
|
|
}
|
|
|
|
html,
|
|
body,
|
|
#app {
|
|
height: 100%;
|
|
}
|
|
|
|
body {
|
|
background-color: var(--color-surface-0);
|
|
color: var(--color-fg);
|
|
font-family: var(--font-sans);
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
|
|
/* ---------- Animations signature (hors couches : les @keyframes ne sont pas layerisés) ---------- */
|
|
@keyframes jl-pulse {
|
|
0%,
|
|
100% {
|
|
box-shadow: 0 0 0 0 rgb(52 211 153 / 0.55);
|
|
}
|
|
50% {
|
|
box-shadow: 0 0 0 5px rgb(52 211 153 / 0);
|
|
}
|
|
}
|
|
@keyframes jl-blink {
|
|
0%,
|
|
49% {
|
|
opacity: 1;
|
|
}
|
|
50%,
|
|
100% {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@layer base {
|
|
/* Tailwind v4 ne met plus cursor:pointer sur les boutons : on le rétablit
|
|
(sauf désactivés, qui gardent le curseur par défaut / not-allowed). */
|
|
button:not(:disabled),
|
|
[role='button']:not([aria-disabled='true']) {
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* Focus visible global (fallback accent). Les composants qui posent leur propre
|
|
focus-visible:outline-none + ring gardent leur anneau (leur règle gagne en spécificité). */
|
|
:focus-visible {
|
|
outline: 2px solid var(--color-accent);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
/* Sélection de texte du chrome (xterm/Monaco gardent la leur). */
|
|
::selection {
|
|
background: var(--color-accent);
|
|
color: var(--color-surface-0);
|
|
}
|
|
|
|
/* Scrollbars fines et discrètes (absentes auparavant). */
|
|
* {
|
|
scrollbar-width: thin;
|
|
scrollbar-color: var(--color-surface-3) transparent;
|
|
}
|
|
::-webkit-scrollbar {
|
|
width: 10px;
|
|
height: 10px;
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
background: var(--color-surface-3);
|
|
border-radius: 9999px;
|
|
border: 2px solid transparent;
|
|
background-clip: content-box;
|
|
}
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: var(--color-border-strong);
|
|
}
|
|
::-webkit-scrollbar-corner {
|
|
background: transparent;
|
|
}
|
|
|
|
/* Respect de prefers-reduced-motion (généralise le bloc scopé de ToastContainer). */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
animation-duration: 0.001ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.001ms !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
@layer components {
|
|
/* Champs : rayon unifié + anneau de focus visible. */
|
|
.input {
|
|
@apply w-full rounded-lg border border-border-strong bg-surface-0 px-2.5 py-1.5 text-sm text-fg outline-none transition-colors placeholder:text-fg-subtle focus-visible:border-accent focus-visible:ring-2 focus-visible:ring-accent/40;
|
|
}
|
|
|
|
/* Boutons : socle CSS pour les usages hors composant (RouterLink class="btn").
|
|
BaseButton réplique ces variantes et ajoute tailles / loading. Idiomes Emerald :
|
|
rayon 11px, font 600, hover accent. */
|
|
.btn {
|
|
@apply inline-flex items-center justify-center gap-[9px] rounded-[11px] border border-border bg-surface-2 px-3 py-1.5 text-sm font-semibold text-fg transition-[background-color,border-color,color,transform] hover:border-accent hover:text-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/60 focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 disabled:cursor-not-allowed disabled:opacity-50;
|
|
}
|
|
.btn-primary {
|
|
@apply inline-flex items-center justify-center gap-[9px] rounded-[11px] border border-accent-solid bg-accent-solid px-3 py-1.5 text-sm font-semibold text-white transition-[background-color,border-color,color,transform] hover:-translate-y-px hover:bg-accent-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/70 focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 disabled:cursor-not-allowed disabled:opacity-50;
|
|
}
|
|
.btn-danger {
|
|
@apply inline-flex items-center justify-center gap-[9px] rounded-[11px] border border-danger/40 bg-danger/10 px-3 py-1.5 text-sm font-semibold text-danger transition-[background-color,border-color,color,transform] hover:bg-danger/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-danger/70 focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 disabled:cursor-not-allowed disabled:opacity-50;
|
|
}
|
|
.btn-ghost {
|
|
@apply inline-flex items-center justify-center gap-[9px] rounded-[11px] px-3 py-1.5 text-sm font-semibold text-fg-muted transition-[background-color,border-color,color] hover:bg-surface-2/60 hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/60 focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 disabled:cursor-not-allowed disabled:opacity-50;
|
|
}
|
|
.btn-coffee {
|
|
@apply inline-flex items-center justify-center gap-[7px] rounded-[9px] border border-coffee bg-transparent px-[13px] py-2 text-[13px] font-semibold text-coffee transition-[background-color,transform] hover:-translate-y-px hover:bg-coffee/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-coffee/60 focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0;
|
|
}
|
|
|
|
/* Pastille (pill mono Emerald). Les variantes de ton vivent dans lib/status-tokens. */
|
|
.badge {
|
|
@apply inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 font-mono text-[11px];
|
|
}
|
|
/* Puce d'accent pulsée (halo box-shadow, pas un fondu d'opacité). */
|
|
.badge-dot {
|
|
@apply inline-block h-2 w-2 rounded-full bg-accent;
|
|
animation: jl-pulse 2.2s infinite;
|
|
}
|
|
|
|
/* Chip (tag mono discret). */
|
|
.chip {
|
|
@apply inline-flex items-center rounded-full border border-border bg-surface-0 px-[9px] py-1 font-mono text-[11px] text-fg-muted;
|
|
}
|
|
|
|
/* Statut mono uppercase + point coloré. */
|
|
.status {
|
|
@apply inline-flex items-center gap-1.5 font-mono text-[11px] tracking-[0.05em] text-fg-muted uppercase;
|
|
}
|
|
.status-dot {
|
|
@apply inline-block h-[7px] w-[7px] rounded-full;
|
|
}
|
|
|
|
/* Micro-titres. */
|
|
.eyebrow {
|
|
@apply font-mono text-[13px] text-accent;
|
|
}
|
|
.label-mono {
|
|
@apply font-mono text-[11px] tracking-[0.08em] text-fg-subtle uppercase;
|
|
}
|
|
|
|
/* Caret clignotant pour les mockups terminaux (JAMAIS xterm). */
|
|
.caret {
|
|
@apply ml-0.5 inline-block h-[15px] w-2 bg-accent align-[-2px];
|
|
animation: jl-blink 1.05s steps(1) infinite;
|
|
}
|
|
|
|
/* Cartes. */
|
|
.card {
|
|
@apply rounded-[14px] border border-border bg-surface-1/50 p-3;
|
|
}
|
|
.card-hover {
|
|
@apply transition-[transform,border-color,box-shadow] hover:-translate-y-1 hover:border-accent hover:shadow-pop;
|
|
}
|
|
.card-inset {
|
|
@apply rounded-[10px] border border-border bg-surface-0/40 p-2;
|
|
}
|
|
|
|
/* Calques décoratifs (halo accent + grain pointillé). Statiques (safe reduced-motion). */
|
|
.halo {
|
|
position: absolute;
|
|
top: -40px;
|
|
left: 50%;
|
|
width: 1100px;
|
|
max-width: 140%;
|
|
height: 560px;
|
|
transform: translateX(-50%);
|
|
background: radial-gradient(50% 60% at 50% 0%, var(--color-accent) 0%, transparent 70%);
|
|
opacity: 0.12;
|
|
filter: blur(18px);
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
}
|
|
.grain {
|
|
position: absolute;
|
|
inset: 0;
|
|
background-image: radial-gradient(var(--color-fg) 1px, transparent 1px);
|
|
background-size: 34px 34px;
|
|
opacity: 0.025;
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
-webkit-mask-image: linear-gradient(to bottom, #000, transparent 70%);
|
|
mask-image: linear-gradient(to bottom, #000, transparent 70%);
|
|
}
|
|
|
|
/* Lignes de diff : le FOND teinté porte la sémantique (ajout/suppression), le texte
|
|
reste neutre (lisible en clair ET sombre, façon GitHub). */
|
|
.diff-add {
|
|
@apply bg-accent/12 text-fg;
|
|
}
|
|
.diff-del {
|
|
@apply bg-danger/12 text-fg;
|
|
}
|
|
.diff-ctx {
|
|
@apply text-fg-muted;
|
|
}
|
|
}
|
|
|
|
/* Halo plus discret en thème clair. */
|
|
html[data-theme='light'] .halo {
|
|
opacity: 0.06;
|
|
}
|