diff --git a/src/web/src/components/ui/card.tsx b/src/web/src/components/ui/card.tsx index c5d18d4..3f2d85d 100644 --- a/src/web/src/components/ui/card.tsx +++ b/src/web/src/components/ui/card.tsx @@ -1,20 +1,34 @@ import * as React from 'react' +import { cva, type VariantProps } from 'class-variance-authority' import { cn } from '@/lib/utils' -const Card = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) +const cardVariants = cva('rounded-xl text-card-foreground transition-shadow', { + variants: { + variant: { + default: 'border border-border bg-card shadow-sm', + elevated: 'border border-border bg-card shadow-lg', + glass: 'glass shadow-xl', + }, + }, + defaultVariants: { + variant: 'default', + }, +}) + +export interface CardProps + extends React.HTMLAttributes, + VariantProps {} + +const Card = React.forwardRef( + ({ className, variant, ...props }, ref) => ( +
+ ), +) Card.displayName = 'Card' const CardHeader = React.forwardRef< diff --git a/src/web/src/components/ui/input.tsx b/src/web/src/components/ui/input.tsx index 54ed77b..46fa970 100644 --- a/src/web/src/components/ui/input.tsx +++ b/src/web/src/components/ui/input.tsx @@ -10,7 +10,11 @@ const Input = React.forwardRef( - - SIG-CM 2.0 - - Iniciar sesión + + + {/* Brand mark */} +
+ +
+ SIG-CM 2.0 + + Sistema de gestión comercial · El Día
- + {errorMessage && ( diff --git a/src/web/src/index.css b/src/web/src/index.css index f7c4014..db20bdb 100644 --- a/src/web/src/index.css +++ b/src/web/src/index.css @@ -7,110 +7,155 @@ @import "@fontsource/jetbrains-mono/400.css"; /* ================================================================ - SIG-CM 2.0 Design System — Tokens + SIG-CM 2.0 Design System v2.0 — Tokens Source of truth: Obsidian/02-ARQUITECTURA-y-TECH-STACK/2.14 🎨 Design System.md - Brand color: #008fbe (logo El Día) — escalado OKLCH + Brand: #008fbe (logo) + violet accent → tech sophistication + Style: dark-first elegante, glassmorphism, multi-layer shadows ================================================================ */ @layer base { :root { - /* ── Brand (cyan-blue around logo #008fbe) ─────────────────── */ + /* ── Brand cyan (logo #008fbe) ──────────────────────────── */ --brand-50: oklch(0.972 0.013 220); --brand-100: oklch(0.935 0.035 220); --brand-200: oklch(0.870 0.072 220); --brand-300: oklch(0.780 0.108 220); - --brand-400: oklch(0.690 0.128 220); + --brand-400: oklch(0.700 0.135 220); --brand-500: oklch(0.625 0.130 220); /* logo #008fbe */ - --brand-600: oklch(0.550 0.128 222); - --brand-700: oklch(0.460 0.110 224); - --brand-800: oklch(0.360 0.082 226); - --brand-900: oklch(0.280 0.058 228); - --brand-950: oklch(0.200 0.040 230); + --brand-600: oklch(0.530 0.135 222); + --brand-700: oklch(0.440 0.115 224); + --brand-800: oklch(0.350 0.085 226); + --brand-900: oklch(0.270 0.060 228); + --brand-950: oklch(0.190 0.040 230); - /* ── Neutral (cool slate, complementa el blue) ─────────────── */ - --neutral-50: oklch(0.985 0.003 240); - --neutral-100: oklch(0.965 0.005 240); - --neutral-200: oklch(0.918 0.008 240); - --neutral-300: oklch(0.850 0.012 240); - --neutral-400: oklch(0.690 0.015 240); - --neutral-500: oklch(0.550 0.018 240); - --neutral-600: oklch(0.450 0.018 240); - --neutral-700: oklch(0.360 0.015 240); - --neutral-800: oklch(0.270 0.013 240); - --neutral-900: oklch(0.210 0.010 240); - --neutral-950: oklch(0.150 0.008 240); + /* ── Violet accent (combo tech con brand cyan) ──────────── */ + --accent-violet-400: oklch(0.700 0.180 280); + --accent-violet-500: oklch(0.620 0.200 280); + --accent-violet-600: oklch(0.530 0.205 280); - /* ── Semantic ──────────────────────────────────────────────── */ - --success: oklch(0.640 0.155 145); - --success-foreground: oklch(0.990 0.000 0); - --warning: oklch(0.760 0.150 75); - --warning-foreground: oklch(0.220 0.050 75); + /* ── Neutral (slate con shift sutil hacia azul/violeta) ── */ + --neutral-50: oklch(0.985 0.004 250); + --neutral-100: oklch(0.962 0.007 250); + --neutral-200: oklch(0.910 0.012 250); + --neutral-300: oklch(0.835 0.018 250); + --neutral-400: oklch(0.680 0.022 250); + --neutral-500: oklch(0.540 0.025 250); + --neutral-600: oklch(0.435 0.025 250); + --neutral-700: oklch(0.345 0.022 250); + --neutral-800: oklch(0.250 0.020 250); + --neutral-900: oklch(0.185 0.015 250); + --neutral-950: oklch(0.130 0.013 250); - /* ── shadcn semantic mapping (LIGHT) ───────────────────────── */ - --background: oklch(0.992 0.003 220); /* off-white tinted brand */ - --foreground: var(--neutral-900); + /* ── Semantic ──────────────────────────────────────────── */ + --success: oklch(0.640 0.155 145); + --success-foreground: oklch(0.990 0.000 0); + --warning: oklch(0.760 0.150 75); + --warning-foreground: oklch(0.220 0.050 75); - --card: oklch(1 0 0); /* pure white over tinted bg */ - --card-foreground: var(--neutral-900); + /* ── shadcn semantic mapping (LIGHT) ─────────────────── */ + --background: oklch(0.988 0.003 250); /* slate barely warm */ + --foreground: var(--neutral-900); - --popover: oklch(1 0 0); - --popover-foreground: var(--neutral-900); + --card: oklch(1 0 0); /* pure white */ + --card-foreground: var(--neutral-900); - --primary: var(--brand-600); /* WCAG AA on white */ - --primary-foreground: oklch(0.990 0.000 0); + --popover: oklch(1 0 0); + --popover-foreground: var(--neutral-900); - --secondary: var(--neutral-100); - --secondary-foreground: var(--neutral-800); + --primary: var(--brand-600); /* WCAG AA on white */ + --primary-foreground: oklch(0.990 0.000 0); - --muted: var(--neutral-100); - --muted-foreground: var(--neutral-500); + --secondary: var(--neutral-100); + --secondary-foreground: var(--neutral-800); - --accent: var(--brand-50); /* hover navigation, subtle brand tint */ - --accent-foreground: var(--brand-700); + --muted: var(--neutral-100); + --muted-foreground: var(--neutral-500); - --destructive: oklch(0.600 0.220 25); + --accent: var(--brand-50); + --accent-foreground: var(--brand-700); + + --destructive: oklch(0.600 0.220 25); --destructive-foreground: oklch(0.990 0.000 0); - --border: var(--neutral-200); - --input: var(--neutral-200); - --ring: var(--brand-500); + --border: var(--neutral-200); + --input: oklch(1 0 0); /* WHITE inputs en light, no gris */ + --input-border: var(--neutral-300); /* border más prominente */ + --ring: var(--brand-500); - /* ── Spacing & shape ──────────────────────────────────────── */ - --radius: 0.5rem; /* 8px */ + /* ── Glass surfaces (backdrop-blur) ───────────────────── */ + --glass-bg: oklch(1 0 0 / 0.7); + --glass-border: oklch(1 0 0 / 0.4); - /* ── Typography ───────────────────────────────────────────── */ + /* ── Gradient backgrounds (hero, login) ───────────────── */ + --gradient-mesh: + radial-gradient(at 100% 0%, oklch(0.625 0.130 220 / 0.12) 0px, transparent 50%), + radial-gradient(at 0% 100%, oklch(0.620 0.200 280 / 0.10) 0px, transparent 50%), + radial-gradient(at 50% 50%, oklch(0.700 0.135 220 / 0.05) 0px, transparent 60%); + + /* ── Shadows (multi-layer para depth real) ────────────── */ + --shadow-sm: 0 1px 2px 0 oklch(0.185 0.015 250 / 0.05); + --shadow: 0 1px 3px 0 oklch(0.185 0.015 250 / 0.08), 0 1px 2px -1px oklch(0.185 0.015 250 / 0.06); + --shadow-md: 0 4px 8px -2px oklch(0.185 0.015 250 / 0.08), 0 2px 4px -2px oklch(0.185 0.015 250 / 0.04); + --shadow-lg: 0 12px 24px -6px oklch(0.185 0.015 250 / 0.12), 0 4px 8px -3px oklch(0.185 0.015 250 / 0.06); + --shadow-xl: 0 24px 48px -12px oklch(0.185 0.015 250 / 0.18), 0 8px 16px -8px oklch(0.185 0.015 250 / 0.08); + --shadow-glow: 0 0 0 1px oklch(0.625 0.130 220 / 0.10), 0 0 24px -4px oklch(0.625 0.130 220 / 0.20); + + /* ── Spacing & shape ───────────────────────────────────── */ + --radius: 0.625rem; /* 10px */ + + /* ── Typography ────────────────────────────────────────── */ --font-sans: "Inter", system-ui, -apple-system, sans-serif; --font-mono: "JetBrains Mono", "Cascadia Code", Consolas, monospace; } .dark { - --background: var(--neutral-950); - --foreground: var(--neutral-50); + /* Background con shift sutil hacia violet → "tech" feel */ + --background: oklch(0.135 0.018 252); /* deep slate-violet */ + --foreground: var(--neutral-50); - --card: var(--neutral-900); - --card-foreground: var(--neutral-50); + --card: oklch(0.180 0.020 252); /* elevación visual */ + --card-foreground: var(--neutral-50); - --popover: var(--neutral-900); - --popover-foreground: var(--neutral-50); + --popover: oklch(0.200 0.022 252); + --popover-foreground: var(--neutral-50); - --primary: var(--brand-400); /* lighter on dark */ - --primary-foreground: var(--neutral-950); + --primary: var(--brand-400); /* brighter en dark, "neon" feel */ + --primary-foreground: oklch(0.130 0.013 250); - --secondary: var(--neutral-800); - --secondary-foreground: var(--neutral-100); + --secondary: oklch(0.230 0.020 252); + --secondary-foreground: var(--neutral-100); - --muted: var(--neutral-800); - --muted-foreground: var(--neutral-400); + --muted: oklch(0.220 0.020 252); + --muted-foreground: var(--neutral-400); - --accent: var(--neutral-800); - --accent-foreground: var(--brand-300); + --accent: oklch(0.250 0.030 252); + --accent-foreground: var(--brand-300); - --destructive: oklch(0.580 0.190 25); + --destructive: oklch(0.580 0.190 25); --destructive-foreground: oklch(0.990 0.000 0); - --border: var(--neutral-800); - --input: var(--neutral-800); - --ring: var(--brand-400); + --border: oklch(1 0 0 / 0.10); /* sutil glass-style border */ + --input: oklch(0.215 0.020 252); /* elevado del bg, contrast con texto */ + --input-border: oklch(1 0 0 / 0.14); + --ring: var(--brand-400); + + /* Glass para dark */ + --glass-bg: oklch(0.180 0.020 252 / 0.6); + --glass-border: oklch(1 0 0 / 0.10); + + /* Gradient mesh dark mode — más vibrante */ + --gradient-mesh: + radial-gradient(at 100% 0%, oklch(0.625 0.130 220 / 0.20) 0px, transparent 50%), + radial-gradient(at 0% 100%, oklch(0.620 0.200 280 / 0.18) 0px, transparent 50%), + radial-gradient(at 50% 50%, oklch(0.700 0.135 220 / 0.08) 0px, transparent 60%); + + /* Shadows más intensas en dark */ + --shadow-sm: 0 1px 2px 0 oklch(0 0 0 / 0.30); + --shadow: 0 2px 4px 0 oklch(0 0 0 / 0.40), 0 1px 2px -1px oklch(0 0 0 / 0.30); + --shadow-md: 0 4px 8px -2px oklch(0 0 0 / 0.40), 0 2px 4px -2px oklch(0 0 0 / 0.30); + --shadow-lg: 0 12px 24px -6px oklch(0 0 0 / 0.50), 0 4px 8px -3px oklch(0 0 0 / 0.30); + --shadow-xl: 0 24px 48px -12px oklch(0 0 0 / 0.60), 0 8px 16px -8px oklch(0 0 0 / 0.30); + --shadow-glow: 0 0 0 1px oklch(0.700 0.135 220 / 0.30), 0 0 32px -4px oklch(0.700 0.135 220 / 0.40); } } @@ -120,7 +165,6 @@ } html { - /* Smooth color transitions when toggling theme */ color-scheme: light dark; } @@ -137,17 +181,15 @@ min-height: 100svh; } - /* Selection color uses brand */ ::selection { background-color: var(--brand-200); color: var(--brand-900); } .dark ::selection { - background-color: var(--brand-800); + background-color: var(--brand-700); color: var(--brand-50); } - /* Focus visible — accessible ring usando brand */ *:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; @@ -156,7 +198,7 @@ h1, h2, h3, h4, h5, h6 { font-family: var(--font-sans); font-weight: 600; - letter-spacing: -0.01em; + letter-spacing: -0.015em; } code, pre, kbd, samp { @@ -165,9 +207,30 @@ } /* ================================================================ - Tailwind 4 inline theme — expone tokens como utility classes - Cada token aquí queda disponible como Tailwind utility - (bg-background, text-foreground, border-border, etc.) + Glass surface utility + Uso:
+ ================================================================ */ +@layer components { + .glass { + background-color: var(--glass-bg); + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); + border: 1px solid var(--glass-border); + } + + .gradient-mesh { + background-image: var(--gradient-mesh); + } + + /* Brand glow para focus en inputs críticos */ + .focus-glow:focus-visible { + box-shadow: var(--shadow-glow); + outline: none; + } +} + +/* ================================================================ + Tailwind 4 inline theme — utilidades disponibles globalmente ================================================================ */ @theme inline { --color-background: var(--background); @@ -188,9 +251,10 @@ --color-destructive-foreground: var(--destructive-foreground); --color-border: var(--border); --color-input: var(--input); + --color-input-border: var(--input-border); --color-ring: var(--ring); - /* Brand scale (utilities tipo bg-brand-500, text-brand-700, etc.) */ + /* Brand */ --color-brand-50: var(--brand-50); --color-brand-100: var(--brand-100); --color-brand-200: var(--brand-200); @@ -203,6 +267,11 @@ --color-brand-900: var(--brand-900); --color-brand-950: var(--brand-950); + /* Violet accent */ + --color-violet-400: var(--accent-violet-400); + --color-violet-500: var(--accent-violet-500); + --color-violet-600: var(--accent-violet-600); + /* Semantic */ --color-success: var(--success); --color-success-foreground: var(--success-foreground); @@ -212,6 +281,14 @@ --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + + --shadow-sm: var(--shadow-sm); + --shadow: var(--shadow); + --shadow-md: var(--shadow-md); + --shadow-lg: var(--shadow-lg); + --shadow-xl: var(--shadow-xl); + --shadow-glow: var(--shadow-glow); --font-sans: var(--font-sans); --font-mono: var(--font-mono); diff --git a/src/web/src/layouts/PublicLayout.tsx b/src/web/src/layouts/PublicLayout.tsx index 11731a8..fc4232a 100644 --- a/src/web/src/layouts/PublicLayout.tsx +++ b/src/web/src/layouts/PublicLayout.tsx @@ -6,8 +6,26 @@ interface PublicLayoutProps { export function PublicLayout({ children }: PublicLayoutProps) { return ( -
- {children} +
+ {/* Gradient mesh background — subtle radial blobs (brand cyan + violet) */} +
+ + {/* Subtle grid texture overlay (visible on dark, fades on light) */} +
+ + {/* Brand glow accents (positioned blobs) */} +
+
+ + {/* Content */} +
{children}
) }