@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 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; }