feat(frontend): wire Vite app to FastAPI parser with NDJSON streaming + Upload page
This commit is contained in:
+187
@@ -0,0 +1,187 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
/* Refined Apple-HIG dark — true black with a whisper of blue */
|
||||
--background: 240 6% 4%; /* #0a0a0c */
|
||||
--foreground: 240 6% 96%; /* #f5f5f7 */
|
||||
|
||||
--card: 240 5% 8%; /* #131316 */
|
||||
--card-foreground: 240 6% 96%;
|
||||
|
||||
--popover: 240 5% 9%;
|
||||
--popover-foreground: 240 6% 96%;
|
||||
|
||||
--muted: 240 4% 12%; /* #1e1e21 */
|
||||
--muted-foreground: 240 4% 61%; /* #9a9a9f */
|
||||
|
||||
--secondary: 240 4% 12%;
|
||||
--secondary-foreground: 240 6% 96%;
|
||||
|
||||
--accent: 217 100% 56%; /* #1a73ff — electric, more committed than stock */
|
||||
--accent-foreground: 0 0% 100%;
|
||||
|
||||
--primary: 217 100% 56%;
|
||||
--primary-foreground: 0 0% 100%;
|
||||
|
||||
--destructive: 1 100% 60%; /* #ff453a */
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
|
||||
--success: 142 71% 50%; /* #30d158 */
|
||||
--success-foreground: 144 70% 10%;
|
||||
|
||||
--warning: 38 100% 56%; /* #ff9f0a */
|
||||
--warning-foreground: 26 80% 14%;
|
||||
|
||||
--border: 240 4% 14%; /* #232327 */
|
||||
--input: 240 4% 14%;
|
||||
--ring: 217 100% 56%;
|
||||
|
||||
--sidebar: 240 6% 5%;
|
||||
--sidebar-foreground: 240 6% 96%;
|
||||
--sidebar-accent: 217 100% 56%;
|
||||
--sidebar-border: 240 4% 12%;
|
||||
|
||||
--radius: 0.75rem; /* 12px */
|
||||
}
|
||||
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
|
||||
html, body, #root {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
font-feature-settings: "ss01", "cv11", "calt";
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/* A single, precise light source anchored top-right.
|
||||
One light, not two — an instrument, not a wash. */
|
||||
body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
background: radial-gradient(
|
||||
55rem 35rem at 100% -15%,
|
||||
hsla(218, 100%, 58%, 0.085),
|
||||
transparent 62%
|
||||
);
|
||||
}
|
||||
|
||||
/* Fine grain — the substrate of a precision instrument. */
|
||||
body::after {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
opacity: 0.045;
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
|
||||
}
|
||||
|
||||
/* Custom scrollbar — minimal, hairline, Apple-style */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: hsl(var(--border));
|
||||
border-radius: 999px;
|
||||
border: 2px solid transparent;
|
||||
background-clip: content-box;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: hsl(var(--muted-foreground) / 0.4);
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
/* Focus ring — accent, 2px, with offset */
|
||||
:focus-visible {
|
||||
outline: 2px solid hsl(var(--ring));
|
||||
outline-offset: 2px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
/* Tabular numerals everywhere a number is shown */
|
||||
.num {
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-feature-settings: "tnum", "ss01";
|
||||
}
|
||||
|
||||
/* Display face — used for KPI numbers and data emphasis */
|
||||
.display {
|
||||
font-family: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;
|
||||
font-variant-numeric: tabular-nums;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
/* Hairline — a 1px separator that reads as a divider, not a border */
|
||||
.hairline {
|
||||
border-color: hsl(var(--border) / 0.6);
|
||||
}
|
||||
|
||||
/* Soft card surface with a 1px hairline + subtle inner highlight */
|
||||
.surface {
|
||||
background-color: hsl(var(--card));
|
||||
border: 1px solid hsl(var(--border));
|
||||
box-shadow:
|
||||
inset 0 1px 0 0 hsl(0 0% 100% / 0.035),
|
||||
0 1px 2px 0 hsl(0 0% 0% / 0.5);
|
||||
}
|
||||
|
||||
/* Active nav indicator — a thin left-aligned accent line */
|
||||
.nav-active {
|
||||
background-color: hsl(var(--muted) / 0.6);
|
||||
color: hsl(var(--foreground));
|
||||
}
|
||||
.nav-active::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -0.75rem;
|
||||
top: 0.5rem;
|
||||
bottom: 0.5rem;
|
||||
width: 2px;
|
||||
border-radius: 2px;
|
||||
background-color: hsl(var(--accent));
|
||||
box-shadow: 0 0 12px hsl(var(--accent) / 0.5);
|
||||
}
|
||||
|
||||
/* Keyboard hint chip */
|
||||
.kbd {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.15rem;
|
||||
height: 1.375rem;
|
||||
padding: 0 0.4rem;
|
||||
border-radius: 0.375rem;
|
||||
border: 1px solid hsl(var(--border));
|
||||
background: hsl(var(--muted) / 0.5);
|
||||
color: hsl(var(--muted-foreground));
|
||||
font-family: "Geist Mono", ui-monospace, monospace;
|
||||
font-size: 10.5px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.04em;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.text-balance {
|
||||
text-wrap: balance;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user