/* S437: import gerarchia z-index — variabili --z-* disponibili globalmente */ @import './styles/z-index.css'; /* S_THEME: theme.css source per --card-bg-streaming, .stream-progress-bar, --terminal-*, .agent-chip e token mancanti da index.css. index.css :root viene DOPO → sovrascrive token duplicati (Glow Glass prevale). */ @import './styles/theme.css'; /* ========================================================= GLOBAL RESET + TYPOGRAPHY min-width: 0 globale previene flex shrink collapse ========================================================= */ *, *::before, *::after { box-sizing: border-box; min-width: 0; } html, body, #root { margin: 0; padding: 0; height: 100%; width: 100%; overflow-x: hidden; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; -webkit-text-size-adjust: 100%; } /* iOS: html deve bloccare lo scroll del documento root */ html { overflow: hidden; height: var(--vh, 100dvh); } /* ========================================================= STRUCTURAL TOKENS — radius, type stacks, transitions Color tokens live in theme.css (Glow Glass canonical source) ========================================================= */ :root { /* ─��� Font stacks ── */ --font-display: "Geist", "Inter", sans-serif; --font-mono: "JetBrains Mono", ui-monospace, "Cascadia Code", "Fira Code", monospace; --font-sans: Inter, system-ui, -apple-system, sans-serif; /* ── Radius — tight square corners ── */ --radius-sm: 6px; --radius-md: 8px; --radius-lg: 8px; /* P10-CSS: IDE-style compact */ --radius-xl: 10px; /* P10-CSS: IDE-style compact */ --radius-2xl: 16px; /* P10-CSS: ridotto da 24px */ /* ── Transitions ── */ --transition-fast: 130ms cubic-bezier(0.4, 0, 0.2, 1); --transition-normal: 220ms cubic-bezier(0.4, 0, 0.2, 1); /* G5: base font size token */ --base-font-size: 16px; } /* ========================================================= BUG #3: Focus outline — remove browser default dashed/yellow ring Use :focus-visible (keyboard only) for accessibility compliance Safari: outline: none on :focus is safe — Safari uses :focus-visible natively ========================================================= */ *:focus { outline: none; } *:focus-visible { outline: 2px solid rgba(99, 102, 241, 0.55); outline-offset: 2px; border-radius: 4px; } /* Touch/mobile users never need keyboard focus ring */ @media (hover: none) { *:focus-visible { outline: none; } } /* G5+G7: mobile-first overrides */ @media (max-width: 767px) { :root { --base-font-size: 14px; } body { font-size: var(--base-font-size); } /* G7: sidebar overlay full width on mobile */ .sidebar-overlay > div { width: calc(100vw - 24px) !important; max-width: calc(100vw - 24px) !important; } } /* ── Glass cards — glow edition (S250-GLASS) ── */ .glass-card { background: rgba(8, 10, 28, 0.58); /* Zen: semi-trasparente — il body gradient si intravede */ border: 1px solid rgba(255, 255, 255, 0.08); box-shadow: 0 0 0 1px rgba(99,102,241,0.08), 0 8px 32px rgba(0, 0, 0, 0.50), inset 0 1px 0 rgba(255, 255, 255, 0.06), inset 0 -1px 0 rgba(0,0,0,0.3); border-radius: var(--radius-lg); backdrop-filter: blur(8px) saturate(120%); /* P10-CSS: ridotto, mobile già disabilitato da @media */ -webkit-backdrop-filter: blur(8px) saturate(120%); } .glass-card:hover { border-color: rgba(99, 102, 241, 0.36); box-shadow: 0 0 0 1px rgba(99,102,241,0.18), 0 0 20px 0 rgba(99,102,241,0.12), 0 8px 32px rgba(0, 0, 0, 0.50), inset 0 1px 0 rgba(255, 255, 255, 0.06); transition: border-color var(--transition-fast), box-shadow var(--transition-fast); } .glass-card:active { will-change: transform; transform: scale(0.97); transition: transform 0.12s ease; } /* Glassmorphism — backdrop-filter attivo, sfondo intravisto (Zen/Manus) */ .glass-surface { background: rgba(6, 8, 22, 0.58); /* Zen: 0.94 → 0.58 */ border: 1px solid rgba(99, 102, 241, 0.18); box-shadow: 0 0 0 1px rgba(0,212,255,0.06), 0 8px 40px rgba(0, 0, 0, 0.65); } /* ========================================================= BODY — Deep space background with subtle radial depth ========================================================= */ body { background: radial-gradient(ellipse at 15% 0%, rgba(99, 102, 241, 0.12) 0%, transparent 48%), radial-gradient(ellipse at 85% 5%, rgba(139, 92, 246, 0.08) 0%, transparent 42%), radial-gradient(ellipse at 50% 100%, rgba(0, 212, 255, 0.07) 0%, transparent 50%), radial-gradient(ellipse at 90% 60%, rgba(99, 102, 241, 0.05) 0%, transparent 38%), #04050e; color: var(--text); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; height: var(--vh, 100dvh); overflow: hidden; overscroll-behavior: none; } /* ========================================================= MAIN APP LAYOUT ========================================================= */ .app-layout { display: flex; width: 100%; height: var(--vh, 100dvh); overflow: hidden; background: transparent; } #root { width: 100%; height: var(--vh, 100dvh); display: flex; } /* ========================================================= SIDEBAR DESKTOP — refined futuristic border ========================================================= */ .sidebar-desktop { flex-shrink: 0; width: 260px; border-right: 1px solid rgba(99, 102, 241, 0.18); box-shadow: 2px 0 32px -4px rgba(0, 0, 0, 0.70), 1px 0 0 0 rgba(99, 102, 241, 0.08), inset -1px 0 0 rgba(0, 212, 255, 0.04); background: rgba(5, 6, 16, 0.82); /* Zen: più trasparente */ backdrop-filter: blur(24px) saturate(180%); -webkit-backdrop-filter: blur(16px) saturate(160%); will-change: transform; /* GAP-8: forza GPU compositing layer — backdrop-filter safe su Safari */ z-index: 10; } [data-theme="light"] .sidebar-desktop { background: var(--bg2); box-shadow: 2px 0 16px -4px rgba(0, 0, 0, 0.10); } .main-content { flex: 1; display: flex; flex-direction: column; min-width: 0; background: transparent; position: relative; overflow: hidden; height: var(--vh, 100dvh); } /* ========================================================= CONV-ROW — ⋯ menu button visibility (S253) Desktop: hidden, shown on row hover or when menu open Touch devices: always visible at 45% opacity (no hover available) ========================================================= */ .conv-row .conv-menu-btn { opacity: 0; transition: opacity 0.15s; } .conv-row:hover .conv-menu-btn { opacity: 0.7; } .conv-row:hover .conv-menu-btn:hover { opacity: 1; background: rgba(59,130,246,0.08) !important; } /* Touch / Mobile: no hover state → always show */ @media (hover: none) { .conv-row .conv-menu-btn { opacity: 0.45 !important; } } /* Sidebar mobile overlay */ .sidebar-overlay { position: fixed; inset: 0; z-index: var(--z-modal-backdrop); background: rgba(0, 0, 0, 0.72); /* G2-S202: darker solid bg replaces expensive blur */ /* backdrop-filter removed — G2-S202: was expensive on mobile Safari */ display: flex; animation: overlay-fade-in 0.22s cubic-bezier(0.4, 0, 0.2, 1); } .sidebar-overlay > div { animation: sidebar-slide-in 0.24s cubic-bezier(0.16, 1, 0.3, 1); } /* ── S86-UX: Chat card animations ─────────────────────────────────────── */ @keyframes message-slide-in { from { opacity: 0; transform: translateY(10px) scale(0.985); } to { opacity: 1; transform: translateY(0) scale(1); } } @keyframes bounce-dot { 0%, 80%, 100% { transform: scale(0.55); opacity: 0.35; } 40% { transform: scale(1); opacity: 1; } } @keyframes stream-border-pulse { 0%, 100% { border-color: rgba(0,212,255,0.22); box-shadow: 0 0 0 1px rgba(0,212,255,0.08), 0 4px 20px rgba(0,0,0,0.38); } 50% { border-color: rgba(0,212,255,0.60); box-shadow: 0 0 0 1px rgba(0,212,255,0.20), 0 0 28px 0 rgba(0,212,255,0.22), 0 0 56px 0 rgba(99,102,241,0.10), 0 4px 20px rgba(0,0,0,0.38); } } @keyframes waveform-bar { 0%, 100% { transform: scaleY(0.4); opacity: 0.5; } 50% { transform: scaleY(1.0); opacity: 1.0; } } /* CSS class applied to AI card while streaming */ .chat-card-streaming { animation: stream-border-pulse 2.2s ease-in-out infinite; } /* S313-perf: content-visibility — browser skips rendering off-screen messages Riduce il tempo di paint su conversazioni lunghe del ~60% su mobile */ .chat-message-item { content-visibility: auto; contain-intrinsic-size: 0 90px; } @keyframes overlay-fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes sidebar-slide-in { from { transform: translateX(-100%); } to { transform: translateX(0); } } /* ── Tab pane fade+lift on switch ── */ .tab-pane-active { animation: tab-fade-in 0.18s cubic-bezier(0.16, 1, 0.3, 1) both; } @keyframes tab-fade-in { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } } /* ========================================================= SCROLLBAR — minimal, indigo tint ========================================================= */ ::-webkit-scrollbar { width: 3px; height: 3px; } ::-webkit-scrollbar-thumb { background: rgba(99,102,241,0.28); border-radius: 999px; } ::-webkit-scrollbar-thumb:hover { background: rgba(99,102,241,0.50); box-shadow: 0 0 6px rgba(99,102,241,0.4); } ::-webkit-scrollbar-track { background: transparent; } /* ========================================================= CHAT INPUT CONTAINER — focus glow (CSS-only, no JS) ========================================================= */ .chat-input-container { max-width: 700px; margin: 0 auto; display: flex; flex-direction: column; border-radius: var(--radius-xl); background: rgba(8, 10, 28, 0.90); border: 1px solid rgba(99, 102, 241, 0.22); overflow: visible; backdrop-filter: none; -webkit-backdrop-filter: none; box-shadow: 0 0 0 1px rgba(99,102,241,0.06), 0 8px 32px rgba(0,0,0,0.40), inset 0 1px 0 rgba(255,255,255,0.05); transition: border-color var(--transition-normal), box-shadow var(--transition-normal); } .chat-input-container:focus-within { border-color: rgba(99, 102, 241, 0.55); box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.14), 0 0 32px 0 rgba(99, 102, 241, 0.18), 0 0 64px 0 rgba(0, 212, 255, 0.08), 0 8px 32px rgba(0,0,0,0.40), inset 0 1px 0 rgba(255,255,255,0.06); } /* ========================================================= COMMIT BADGE — monospace futuristic ========================================================= */ .commit-badge { display: flex; align-items: center; gap: 4px; font-size: 0.62rem; padding: 3px 7px; border-radius: var(--radius-sm); background: rgba(99,102,241,0.06); border: 1px solid rgba(99,102,241,0.16); color: var(--text-muted); text-decoration: none; font-family: var(--font-mono); letter-spacing: 0.04em; transition: border-color var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast); } .commit-badge:hover { border-color: rgba(0, 212, 255, 0.35); color: var(--accent); box-shadow: 0 0 8px rgba(0,212,255,0.18); } /* ========================================================= CODE / PRE ========================================================= */ pre, code { overflow-x: auto; font-family: var(--font-mono); } /* ========================================================= ANIMAZIONI — GPU-safe (opacity + box-shadow only) Tutte rispettano prefers-reduced-motion ========================================================= */ /* Glow che respira lentamente — tab attivo, elementi chiave */ @keyframes neon-breathe { 0%, 100% { text-shadow: 0 0 6px rgba(0, 212, 255, 0.25); } 50% { text-shadow: 0 0 14px rgba(0, 212, 255, 0.55), 0 0 4px rgba(59,130,246,0.3); } } /* Pulsazione dot streaming — più elettrico */ @keyframes brain-glow { 0%, 100% { filter: drop-shadow(0 0 2px rgba(59,130,246,0.2)); } 50% { filter: drop-shadow(0 0 10px rgba(0, 212, 255, 0.6)); } } @keyframes neuron-pulse { 0%, 100% { opacity: 0.3; transform: scale(0.7); } 50% { opacity: 1; transform: scale(1.3); } } @keyframes neuron-line-pulse { 0%, 100% { opacity: 0.08; } 50% { opacity: 0.5; } } @keyframes fadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } } @keyframes fadeInUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } /* Dot streaming — più cyan, più elettrico */ @keyframes pulse-dot { 0%, 100% { opacity: 1; transform: scale(1); box-shadow: 0 0 4px var(--accent); } 50% { opacity: 0.3; transform: scale(0.7); box-shadow: 0 0 2px transparent; } } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } } @keyframes chip-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } @keyframes dot-blink { 0%, 100% { opacity: 0.15; } 50% { opacity: 1; } } @keyframes chip-fadein { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: translateY(0); } } @keyframes pulse-ring { 0% { transform: scale(1); opacity: 0.6; } 100% { transform: scale(1.6); opacity: 0; } } @keyframes mem-tab-pulse { 0% { transform: scale(1); opacity: 1; box-shadow: 0 0 0 0 rgba(59,130,246,0.7); } 50% { transform: scale(1.2); opacity: 0.85; box-shadow: 0 0 0 4px rgba(59,130,246,0); } 100% { transform: scale(1); opacity: 1; box-shadow: 0 0 0 0 rgba(59,130,246,0.7); } } @keyframes blink-cursor { 0%, 100% { opacity: 0.8; } 50% { opacity: 0; } } /* ========================================================= P42-REPLIT — Replit-style streaming text effect - replit-para-reveal : fade-in per nuovi

durante streaming - replit-chunk-flash : flash cyan al cursore ogni ~22 char Zero layout-thrashing: solo opacity (GPU-accelerated) ========================================================= */ @keyframes replit-para-reveal { from { opacity: 0; } to { opacity: 1; } } /* Ogni nuovo

dentro una card in streaming appare con fade-in */ .chat-card-streaming p, .chat-card-streaming li { animation: replit-para-reveal 0.30s cubic-bezier(0.16, 1, 0.3, 1) both; } @keyframes replit-chunk-flash { 0% { opacity: 0.85; width: 5px; } 60% { opacity: 0.25; width: 3px; } 100% { opacity: 0; width: 0; } } /* Span effimero — rimontato ogni ~22 char di streaming per dare il pop Replit */ .replit-chunk-glow { display: inline-block; height: 0.85em; width: 0; border-radius: 2px; background: rgba(0, 212, 255, 0.55); vertical-align: middle; margin-left: 1px; animation: replit-chunk-flash 0.42s ease-out forwards; pointer-events: none; flex-shrink: 0; } /* Shimmer skeleton — più freddo/cyan */ @keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } } /* Glow pulse — input / card attive */ @keyframes glow-pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(99,102,241,0); } 50% { box-shadow: 0 0 22px 2px rgba(99,102,241,0.22), 0 0 8px 0 rgba(0, 212, 255, 0.14); } } /* Glow breathe — per elementi accent (logo, avatar, dot attivo) */ @keyframes glow-breathe { 0%, 100% { box-shadow: 0 0 4px rgba(0,212,255,0.20), 0 0 12px rgba(99,102,241,0.10); } 50% { box-shadow: 0 0 16px rgba(0,212,255,0.55), 0 0 32px rgba(99,102,241,0.25), 0 0 48px rgba(139,92,246,0.12); } } /* Indigo glow for buttons */ @keyframes indigo-glow-pulse { 0%, 100% { box-shadow: 0 0 8px rgba(99,102,241,0.25); } 50% { box-shadow: 0 0 20px rgba(99,102,241,0.55), 0 0 40px rgba(99,102,241,0.18); } } @keyframes avatar-pulse { 0%, 100% { opacity: 1; filter: drop-shadow(0 0 0 rgba(0, 212, 255, 0)); } 50% { opacity: 0.7; filter: drop-shadow(0 0 5px rgba(0, 212, 255, 0.45)); } } @keyframes spin { to { transform: rotate(360deg); } } /* Scan line futuristica — solo per decorazione leggera su desktop */ @keyframes scan-line { 0% { transform: translateY(-100%); opacity: 0; } 10% { opacity: 0.025; } 90% { opacity: 0.025; } 100% { transform: translateY(200%); opacity: 0; } } /* ========================================================= PROSE — Markdown (ChatMessage) ========================================================= */ .prose { color: var(--text, #e4e4f0); font-size: 0.92rem; line-height: 1.72; word-break: break-word; overflow-wrap: anywhere; } .prose p { margin-bottom: 1.2rem; } .prose p:last-child { margin-bottom: 0; } /* S739: heading typography — erano completamente assenti, titoli Markdown invisibili */ .prose h1, .prose h2, .prose h3, .prose h4 { font-weight: 700; line-height: 1.3; margin-top: 1.5rem; margin-bottom: 0.55rem; color: var(--text-bright, #f0f0ff); } .prose h1:first-child, .prose h2:first-child, .prose h3:first-child { margin-top: 0; } .prose h1 { font-size: 1.45rem; } .prose h2 { font-size: 1.22rem; border-bottom: 1px solid rgba(99,102,241,0.18); padding-bottom: 0.2rem; } .prose h3 { font-size: 1.06rem; } .prose h4 { font-size: 0.97rem; font-weight: 600; } /* S739: liste, citazioni, tabelle, link */ .prose ul, .prose ol { padding-left: 1.4rem; margin-bottom: 1rem; } .prose li { margin-bottom: 0.28rem; } .prose li > ul, .prose li > ol { margin-bottom: 0; margin-top: 0.2rem; } .prose blockquote { border-left: 3px solid var(--accent, #6366f1); padding: 0.1rem 0 0.1rem 0.9rem; margin: 1rem 0; color: var(--text-muted, #a0a0b8); font-style: italic; } .prose hr { border: none; border-top: 1px solid var(--border-indigo); margin: 1.4rem 0; } .prose a { color: #818cf8; text-decoration: underline; text-underline-offset: 2px; } .prose a:hover { color: #a5b4fc; } .prose strong { font-weight: 700; color: var(--text-bright, #f0f0ff); } .prose em { font-style: italic; } .prose table { width: 100%; border-collapse: collapse; margin-bottom: 1rem; font-size: 0.87em; } .prose th { background: rgba(99,102,241,0.12); padding: 0.38rem 0.7rem; border: 1px solid var(--border-indigo); text-align: left; font-weight: 600; color: var(--text-bright, #f0f0ff); } .prose td { padding: 0.38rem 0.7rem; border: 1px solid rgba(99,102,241,0.12); } .prose tr:nth-child(even) td { background: rgba(99,102,241,0.04); } .prose pre { border-radius: 10px; overflow-x: auto; font-size: 0.82em; background: rgba(8, 8, 20, 0.8); border: 1px solid var(--border-indigo); } .prose code:not(pre code) { background: rgba(59,130,246,0.1); border: 1px solid rgba(59,130,246,0.15); border-radius: var(--radius-sm); padding: 1px 5px; font-size: 0.85em; color: #93c5fd; font-family: var(--font-mono); } /* ========================================================= AGENT TIMELINE — AgentStepsPanel ========================================================= */ .agent-step-card { border-radius: 10px; overflow: hidden; transition: border-color var(--transition-normal); } .agent-step-card-running { border-color: rgba(0, 212, 255, 0.25); background: rgba(0, 212, 255, 0.03); } .agent-step-card-done { border-color: rgba(74, 222, 128, 0.12); } .agent-step-card-error { border-color: rgba(239, 68, 68, 0.28); background: rgba(239, 68, 68, 0.03); } /* ========================================================= INPUT AREA — bottom safe area iOS ========================================================= */ .input-area { flex-shrink: 0; border-top: 1px solid rgba(99, 102, 241, 0.20); box-shadow: 0 -1px 0 0 rgba(0, 212, 255, 0.06), 0 -8px 32px rgba(99,102,241,0.04); background: rgba(4, 5, 14, 0.96); backdrop-filter: blur(20px) saturate(160%); -webkit-backdrop-filter: blur(20px) saturate(160%); will-change: transform; /* GAP-8: compositing layer per backdrop-filter corretto durante scroll */ padding-bottom: max(0.5rem, env(safe-area-inset-bottom)); } /* ========================================================= iOS / SAFARI PERFORMANCE ========================================================= */ /* S243: iOS Safari — DISABLE backdrop-filter (correzione: era un bug che aggiungeva blur invece di rimuoverlo) */ /* S437: aggiunto [aria-live] per AgentLiveBar (che usa backdropFilter inline) */ /* S741: aggiunto .input-area — blur(20px) durante scrolling era il principale bottleneck su iPhone */ .ios .sidebar-desktop, .ios .glass, .ios [aria-live] { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } .ios .token-overlay { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } /* S741: .input-area usa blur(20px) — visibile sempre durante scroll → rimosso su iOS */ /* .network-banner light-theme ha blur(14px) ma solo su [data-theme="light"] → impatto minore, invariato */ .ios .chat-input-glass { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } /* GAP-8: mancava */ .ios .network-banner { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } /* GAP-8: mancava */ .ios .input-area { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; background: rgba(4, 5, 14, 0.99) !important; } /* ========================================================= MOBILE ========================================================= */ @media (max-width: 768px) { .sidebar-desktop { display: none !important; } .main-content { width: 100%; height: var(--vh, 100dvh); } } /* ========================================================= iOS SAFE AREA fallback ========================================================= */ @supports (-webkit-touch-callout: none) { .main-content { height: var(--vh, 100dvh); } } /* ========================================================= MOBILE KEYBOARD FIX ========================================================= */ textarea { touch-action: manipulation; /* previene zoom doppio tap e migliora risposta iOS */ } textarea:focus { scroll-margin-bottom: 0; /* rimosso: causava scroll jump aggiuntivo su Safari */ outline: none; } .messages-scroll { scroll-padding-bottom: 80px; overscroll-behavior-y: contain; } /* ========================================================= SUGGESTION CARDS ========================================================= */ .premium-suggestion-card { transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast) !important; border: 1px solid rgba(99,102,241,0.14); border-radius: var(--radius-md) !important; } .premium-suggestion-card:hover { border-color: rgba(99,102,241,0.38); box-shadow: 0 0 0 1px rgba(99,102,241,0.12), 0 0 16px 0 rgba(99,102,241,0.12), 0 4px 16px rgba(0,0,0,0.28); background: rgba(99,102,241,0.06) !important; } /* ========================================================= GPU LAYER HINTS — parsimoniosi ========================================================= */ [style*="pulse-dot"], [style*="spin-slow"], [style*="pulse-ring"] { will-change: transform, opacity; } /* ========================================================= PREFERS-REDUCED-MOTION — iPhone "Riduci movimento" ========================================================= */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } @keyframes fadeIn { from { opacity: 1; transform: none; } to { opacity: 1; transform: none; } } @keyframes fadeInUp { from { opacity: 1; transform: none; } to { opacity: 1; transform: none; } } .chat-input-container:focus-within { box-shadow: none; } } /* ========================================================= DESKTOP ONLY — background depth grid (very subtle) Solo su schermi > 768px, non impatta mobile/iPhone ========================================================= */ @media (min-width: 769px) { body::after { content: ''; position: fixed; inset: 0; background-image: linear-gradient(rgba(99, 102, 241, 0.028) 1px, transparent 1px), linear-gradient(90deg, rgba(99, 102, 241, 0.028) 1px, transparent 1px); background-size: 42px 42px; pointer-events: none; z-index: 0; } .app-layout, .main-content, .sidebar-desktop { position: relative; z-index: 1; } } /* ========================================================= MIGLIORIA 1 — Waveform bars TypingIndicator ========================================================= */ @keyframes waveform-bar { 0%, 100% { transform: scaleY(0.3); opacity: 0.4; } 50% { transform: scaleY(1); opacity: 1; } } /* ========================================================= MIGLIORIA 4 — Cinematic message entrance ========================================================= */ @keyframes message-slide-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } /* ========================================================= MIGLIORIA 5 — EmptyState logo ring glow pulse ========================================================= */ @keyframes neon-ring-pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(0,212,255,0), 0 8px 24px rgba(59,130,246,0.12); } 50% { box-shadow: 0 0 0 8px rgba(0,212,255,0.06), 0 8px 32px rgba(59,130,246,0.22), 0 0 40px rgba(0,212,255,0.08); } } /* Boot flicker — per EmptyState title */ @keyframes boot-flicker { 0% { opacity: 0; } 10% { opacity: 0.9; } 12% { opacity: 0.2; } 14% { opacity: 1; } 100% { opacity: 1; } } /* Staggered fade for EmptyState cards */ @keyframes card-enter { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } /* ========================================================= TEMA CHIARO — S_THEME (light/dark/auto) Attivato dalla classe data-theme="light" su ========================================================= */ [data-theme="light"] { --bg: #f2f3fc; --bg2: #e8eaf7; --bg3: #dfe1f4; --bg4: #d5d7ee; --bg-surface: #e4e6f5; --border: rgba(0, 0, 0, 0.08); --border-indigo: rgba(99,102,241,0.28); --border-cyan: rgba(0, 150, 200, 0.26); --border-glow: rgba(99, 102, 241, 0.45); --text: #0c0d24; --text-muted: #42446a; --text-dim: #7070a0; --primary: #6366f1; --primary-light: #818cf8; --primary-dark: #4f46e5; --accent: #0096c7; --accent-dim: rgba(0, 150, 200, 0.12); --accent-glow: rgba(0, 150, 200, 0.30); --glow-indigo: rgba(99,102,241,0.18); --glow-cyan: rgba(0, 150, 200, 0.14); --glow-violet: rgba(139,92,246,0.15); --avatar-primary: #6366f1; --avatar-accent: #0096c7; --narration-text: rgba(80, 60, 220, 0.75); /* footer button vars — S232 light theme */ --footer-btn-color: #4a4a6a; --footer-btn-bg: rgba(0,0,0,0.04); --footer-btn-border: rgba(0,0,0,0.12); /* ── Chat message card — light theme ── */ --card-bg: rgba(255, 255, 255, 0.90); --card-bg-error: rgba(255, 240, 240, 0.95); --card-border-streaming: rgba(0, 150, 200, 0.38); --card-border-idle: rgba(0, 0, 0, 0.10); --card-border-error: rgba(239, 68, 68, 0.32); --card-shadow-streaming: 0 0 0 1px rgba(0,150,200,0.12), 0 4px 24px rgba(0,0,0,0.10); --card-shadow-idle: 0 2px 12px rgba(0,0,0,0.08); /* ── User bubble — light theme ── */ --user-bubble-bg: rgba(59,130,246,0.16); --user-bubble-text: #0a1f3d; --user-bubble-border: rgba(59,130,246,0.32); } /* ── NetworkBanner — light theme overrides (bg più opaco per leggibilità) ── */ [data-theme="light"] .network-banner { background: rgba(200, 200, 220, 0.72) !important; backdrop-filter: blur(14px) saturate(140%); -webkit-backdrop-filter: blur(14px) saturate(140%); } [data-theme="light"] .network-banner[data-quality="offline"], [data-theme="light"] .network-banner[data-quality="poor"] { background: rgba(254, 226, 226, 0.85) !important; } [data-theme="light"] .network-banner[data-quality="reconnected"] { background: rgba(220, 252, 231, 0.85) !important; } [data-theme="light"] body { background: radial-gradient(ellipse at 15% 0%, rgba(99, 102, 241, 0.10) 0%, transparent 48%), radial-gradient(ellipse at 85% 5%, rgba(139, 92, 246, 0.06) 0%, transparent 42%), radial-gradient(ellipse at 50% 100%, rgba(0, 150, 200, 0.07) 0%, transparent 50%), #eeeff9; color: var(--text); } /* ── Glass input bar + sidebar menu — glow edition ── */ .chat-input-glass { background: rgba(6, 7, 20, 0.90); border: 1px solid rgba(99, 102, 241, 0.22); backdrop-filter: none; -webkit-backdrop-filter: none; box-shadow: 0 -4px 32px rgba(0,0,0,0.38), 0 -1px 0 rgba(0,212,255,0.06), inset 0 1px 0 rgba(255,255,255,0.05); } [data-theme="light"] .chat-input-glass { background: rgba(242, 244, 255, 0.94); border: 1px solid rgba(99,102,241,0.18); backdrop-filter: blur(24px) saturate(180%); -webkit-backdrop-filter: blur(24px) saturate(180%); will-change: transform; /* GAP-8 */ box-shadow: 0 -4px 24px rgba(0,0,0,0.06), inset 0 1px 0 rgba(255,255,255,0.9); } .sidebar-glass { background: rgba(5, 6, 16, 0.96); border-right: 1px solid rgba(99,102,241,0.18); box-shadow: 2px 0 40px rgba(0,0,0,0.50), inset -1px 0 0 rgba(0,212,255,0.04); } [data-theme="light"] .sidebar-glass { background: rgba(246, 246, 255, 0.96); border-right: 1px solid rgba(99,102,241,0.12); box-shadow: 2px 0 18px rgba(0,0,0,0.05); } [data-theme="light"] .sidebar-desktop { background: rgba(245, 246, 255, 0.96); border-right: 1px solid rgba(37, 99, 235, 0.12); box-shadow: 2px 0 20px rgba(37,99,235,0.05); } /* S313-iOS: keyboard height compensation — set dynamically by ChatInputBar visualViewport */ :root { --keyboard-height: 0px; } /* ========================================================= S752-FE — Modern touch: gradient brand + micro-interactions ========================================================= */ /* Agent brand gradient — indigo→cyan, usato nella SidebarHeader */ .agent-brand-gradient { background: linear-gradient(90deg, var(--primary-light) 0%, var(--accent) 65%, var(--primary) 100% ); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-weight: 700; letter-spacing: -0.025em; will-change: auto; } /* Send button active scale — micro-feedback su tap/click */ .send-action-btn:active { transform: scale(0.82) !important; transition: transform 0.07s ease !important; } /* New-chat button pulse on hover (Replit-style) */ .new-chat-btn:hover { box-shadow: 0 0 0 3px rgba(99,102,241,0.18), 0 6px 20px rgba(99,102,241,0.30) !important; } .new-chat-btn:active { transform: scale(0.97) !important; } /* Conv-row active: indigo left indicator bar */ .conv-row-active::before { content: ''; position: absolute; left: 0; top: 20%; height: 60%; width: 2px; border-radius: 0 2px 2px 0; background: var(--primary); opacity: 0.9; } /* ========================================================= GAP-7: Safari Performance Gate — mobile backdrop-filter backdrop-filter: blur() è MOLTO costoso su iPhone (Safari WebKit): - Forza GPU compositing layer su ogni elemento con la proprietà - Con molti elementi .glass-card in chat: frame drop visibili su A13 e inferiori Fix: su max-width 768px (mobile) → disabilita backdrop-filter, usa solid background come fallback visivamente accettabile. ChatMessage.tsx è già wrapped in memo() → nessuna modifica necessaria. content-visibility: auto su .chat-message-item già presente (S313-perf). ========================================================= */ @media (max-width: 768px) { .glass-card { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; background: rgba(4, 5, 14, 0.94) !important; } .glass-surface { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; background: rgba(6, 8, 22, 0.96) !important; } .sidebar-desktop { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; background: rgba(5, 6, 16, 0.97) !important; } /* Mantieni will-change: transform per GPU compositing — necessario per smooth scroll */ .sidebar-desktop, .glass-card { will-change: transform; } } /* ========================================================= P43-REPLIT: Typewriter reveal (risposte non-streaming) - .replit-typewriter : ogni

appare con stagger 50ms - .replit-stream-done : flash indigo al completamento streaming GPU-safe: solo opacity + transform (compositor-only). Rispetta prefers-reduced-motion. ========================================================= */ @keyframes replit-typewriter-reveal { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } } /* Stagger per i primi 8 paragrafi, poi tutti a 350ms */ .replit-typewriter p:nth-child(1) { animation: replit-typewriter-reveal 0.32s cubic-bezier(0.16,1,0.3,1) 0ms both; } .replit-typewriter p:nth-child(2) { animation: replit-typewriter-reveal 0.32s cubic-bezier(0.16,1,0.3,1) 55ms both; } .replit-typewriter p:nth-child(3) { animation: replit-typewriter-reveal 0.32s cubic-bezier(0.16,1,0.3,1) 110ms both; } .replit-typewriter p:nth-child(4) { animation: replit-typewriter-reveal 0.32s cubic-bezier(0.16,1,0.3,1) 165ms both; } .replit-typewriter p:nth-child(5) { animation: replit-typewriter-reveal 0.32s cubic-bezier(0.16,1,0.3,1) 220ms both; } .replit-typewriter p:nth-child(6) { animation: replit-typewriter-reveal 0.32s cubic-bezier(0.16,1,0.3,1) 275ms both; } .replit-typewriter p:nth-child(7) { animation: replit-typewriter-reveal 0.32s cubic-bezier(0.16,1,0.3,1) 330ms both; } .replit-typewriter p:nth-child(n+8) { animation: replit-typewriter-reveal 0.32s cubic-bezier(0.16,1,0.3,1) 350ms both; } /* Liste inline stagger */ .replit-typewriter li:nth-child(1) { animation: replit-typewriter-reveal 0.28s cubic-bezier(0.16,1,0.3,1) 30ms both; } .replit-typewriter li:nth-child(2) { animation: replit-typewriter-reveal 0.28s cubic-bezier(0.16,1,0.3,1) 75ms both; } .replit-typewriter li:nth-child(3) { animation: replit-typewriter-reveal 0.28s cubic-bezier(0.16,1,0.3,1) 120ms both; } .replit-typewriter li:nth-child(4) { animation: replit-typewriter-reveal 0.28s cubic-bezier(0.16,1,0.3,1) 165ms both; } .replit-typewriter li:nth-child(n+5) { animation: replit-typewriter-reveal 0.28s cubic-bezier(0.16,1,0.3,1) 200ms both; } /* Completamento streaming: brightness flash indigo sottile */ @keyframes replit-stream-done { 0% { filter: brightness(1) drop-shadow(0 0 0px rgba(129,140,248,0)); } 20% { filter: brightness(1.06) drop-shadow(0 0 6px rgba(129,140,248,0.22)); } 100% { filter: brightness(1) drop-shadow(0 0 0px rgba(129,140,248,0)); } } .replit-stream-done { animation: replit-stream-done 0.65s ease-out forwards; } /* Rispetta prefers-reduced-motion */ @media (prefers-reduced-motion: reduce) { .replit-typewriter p, .replit-typewriter li, .replit-stream-done { animation: none !important; opacity: 1 !important; transform: none !important; filter: none !important; } } /* ========================================================= UI-MOB1 — Mobile header optimisation ========================================================= */ .chat-header-bar { backdrop-filter: blur(20px) saturate(160%); -webkit-backdrop-filter: blur(20px) saturate(160%); } .header-badge-desktop { display: contents; } @media (max-width: 768px) { .chat-header-bar { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } .header-badge-desktop { display: none !important; } } /* ========================================================= REPLIT SPLIT LAYOUT — desktop: chat sx, workspace dx S-SPLIT: pannelli affiancati sempre visibili su desktop ========================================================= */ .split-chat-pane { width: 400px; flex-shrink: 0; display: flex; flex-direction: column; overflow: hidden; border-right: 1px solid rgba(99, 102, 241, 0.18); background: rgba(4, 5, 14, 0.97); } .split-divider { width: 4px; flex-shrink: 0; cursor: col-resize; background: rgba(99, 102, 241, 0.0); display: flex; align-items: center; justify-content: center; transition: background var(--transition-fast); } .split-divider::after { content: ""; display: block; width: 2px; height: 48px; border-radius: 9px; background: rgba(99, 102, 241, 0.28); transition: background var(--transition-fast), height var(--transition-fast); } .split-divider:hover { background: rgba(99, 102, 241, 0.06); } .split-divider:hover::after { background: rgba(99, 102, 241, 0.55); height: 64px; } .split-workspace-pane { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; } /* ========================================================= GAP-4/5: MOTION REDUCTION & MOBILE HOVER OPTIMIZATION ========================================================= */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } .sidebar-overlay, .sidebar-overlay > div, .glass-card, .message-slide-in, .fadeIn, .fadeInUp, .aml-glow, .replit-typewriter *, .replit-stream-done { animation: none !important; } } @media (hover: none) { /* Disable hover effects on touch devices to prevent "sticky" hover states */ .glass-card:hover, .glass-surface:hover, .chat-header-bar:hover { box-shadow: var(--shadow-default, none) !important; border-color: rgba(255,255,255,0.1) !important; transition: none !important; } button:hover { background: initial !important; } .conv-row:hover .conv-menu-btn { opacity: 0.45 !important; } } @media (max-width: 768px) { .chat-header-bar { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; will-change: auto; } } /* ========================================================= GAP-6: TOUCH INTERACTION OPTIMIZATION ========================================================= */ a, button, [role="button"], .clickable { touch-action: manipulation; /* Removes 300ms tap delay */ } .glass-card, .conv-row, .sidebar-item { user-select: none; /* Prevents accidental text selection during scroll */ -webkit-user-select: none; } /* Allow selection only in messages and inputs */ .message-content, input, textarea { user-select: text !important; -webkit-user-select: text !important; } /* Performance: content-visibility for off-screen sections */ .admin-panel-content, .settings-content { content-visibility: auto; contain-intrinsic-size: 0 500px; } /* S-MOBILE-ULTRA: iPhone Safari Optimization */ @media (max-width: 768px) { /* DOM Flattening: Rimuove ombre e layer complessi su mobile */ * { box-shadow: none !important; text-shadow: none !important; } /* Semplifica le transizioni per evitare jank */ .chat-message, .tool-result { transition: none !important; will-change: auto !important; } /* Forza il rendering accelerato solo per lo scroll principale */ .main-content { -webkit-overflow-scrolling: touch; scroll-behavior: auto; /* Disabilita smooth scroll su mobile per performance */ } /* Lazy Tool Rendering: Nasconde i dettagli dei tool di default su mobile */ .tool-details { display: none; } .tool-details.expanded { display: block; } } /* ========================================================= MIGLIORIA 6 — Caret blink animation (GAP-UI-CARET) ========================================================= */ @keyframes caret-blink { 0%, 70%, 100% { opacity: 1; } 20%, 50% { opacity: 0; } } .animate-caret-blink { animation: caret-blink 1.25s ease-in-out infinite; }