dda8ef6368
Replace ASCII-art separators (====, box-drawing rules, ---- dashes) with plain section labels and rewrite the casual one-liners as terse, factual comments.
537 lines
15 KiB
CSS
537 lines
15 KiB
CSS
@import "tailwindcss";
|
|
@import "tw-animate-css";
|
|
@import "./fonts.css";
|
|
|
|
@variant dark (&:where(.dark, .dark *));
|
|
|
|
:root {
|
|
/* Base font size */
|
|
--font-size: 16px;
|
|
|
|
/* GLYPHDIFF Design System */
|
|
/* Primary Colors */
|
|
--swiss-beige: #f3f0e9;
|
|
--swiss-red: #ff3b30;
|
|
--swiss-black: #1a1a1a;
|
|
--swiss-white: #ffffff;
|
|
|
|
/* Semantic mode-switching colors. These are redefined inside `.dark`
|
|
so utilities that reference them auto-adapt without a `dark:` variant. */
|
|
--color-border-subtle: var(--neutral-300);
|
|
--color-text-subtle: var(--neutral-500);
|
|
--color-skeleton: var(--neutral-200);
|
|
--color-grid-line: rgb(0 0 0 / 0.03);
|
|
|
|
/* Neutral Grays */
|
|
--neutral-50: #fafafa;
|
|
--neutral-100: #f5f5f5;
|
|
--neutral-200: #e5e5e5;
|
|
--neutral-300: #d4d4d4;
|
|
--neutral-400: #a3a3a3;
|
|
--neutral-500: #737373;
|
|
--neutral-600: #525252;
|
|
--neutral-700: #404040;
|
|
--neutral-800: #262626;
|
|
--neutral-900: #171717;
|
|
|
|
/* Dark Mode Backgrounds */
|
|
--dark-bg: #121212;
|
|
--dark-card: #1e1e1e;
|
|
--dark-border: rgba(255, 255, 255, 0.1);
|
|
|
|
/* Light Mode Backgrounds */
|
|
--light-bg: #f3f0e9;
|
|
--light-card: #ffffff;
|
|
--light-border: rgba(0, 0, 0, 0.05);
|
|
|
|
/* Semantic Colors */
|
|
--color-brand: var(--swiss-red);
|
|
--color-surface: var(--swiss-beige);
|
|
--color-paper: var(--swiss-white);
|
|
|
|
/* Base Tailwind Colors (for compatibility) */
|
|
--background: #ffffff;
|
|
--foreground: oklch(0.145 0 0);
|
|
--card: #ffffff;
|
|
--card-foreground: oklch(0.145 0 0);
|
|
--popover: oklch(1 0 0);
|
|
--popover-foreground: oklch(0.145 0 0);
|
|
--primary: #030213;
|
|
--primary-foreground: oklch(1 0 0);
|
|
--secondary: oklch(0.95 0.0058 264.53);
|
|
--secondary-foreground: #030213;
|
|
--muted: #ececf0;
|
|
--muted-foreground: #717182;
|
|
--accent: #e9ebef;
|
|
--accent-foreground: #030213;
|
|
--destructive: #d4183d;
|
|
--destructive-foreground: #ffffff;
|
|
--border: rgba(0, 0, 0, 0.1);
|
|
--input: transparent;
|
|
--input-background: #f3f3f5;
|
|
--switch-background: #cbced4;
|
|
--font-weight-medium: 500;
|
|
--font-weight-normal: 400;
|
|
--ring: oklch(0.708 0 0);
|
|
--chart-1: oklch(0.646 0.222 41.116);
|
|
--chart-2: oklch(0.6 0.118 184.704);
|
|
--chart-3: oklch(0.398 0.07 227.392);
|
|
--chart-4: oklch(0.828 0.189 84.429);
|
|
--chart-5: oklch(0.769 0.188 70.08);
|
|
--radius: 0rem;
|
|
--sidebar: oklch(0.985 0 0);
|
|
--sidebar-foreground: oklch(0.145 0 0);
|
|
--sidebar-primary: #030213;
|
|
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
--sidebar-accent: oklch(0.97 0 0);
|
|
--sidebar-accent-foreground: oklch(0.205 0 0);
|
|
--sidebar-border: oklch(0.922 0 0);
|
|
--sidebar-ring: oklch(0.708 0 0);
|
|
|
|
/* Typography Scale */
|
|
--text-xs: 0.75rem;
|
|
--text-sm: 0.875rem;
|
|
--text-base: 1rem;
|
|
--text-lg: 1.125rem;
|
|
--text-xl: 1.25rem;
|
|
--text-2xl: 1.5rem;
|
|
--text-3xl: 1.875rem;
|
|
--text-4xl: 2.25rem;
|
|
--text-5xl: 3rem;
|
|
--text-6xl: 3.75rem;
|
|
--text-7xl: 4.5rem;
|
|
--text-8xl: 6rem;
|
|
|
|
/* Comparison Font Sizes */
|
|
--comparison-font-mobile: 3rem;
|
|
--comparison-font-tablet: 4.5rem;
|
|
--comparison-font-desktop: 6rem;
|
|
}
|
|
|
|
.dark {
|
|
--color-surface: var(--dark-bg);
|
|
--color-paper: var(--dark-card);
|
|
|
|
/* Dark-mode overrides for the semantic mode-switching colors. */
|
|
--color-border-subtle: rgb(255 255 255 / 0.1);
|
|
--color-text-subtle: var(--neutral-400);
|
|
--color-skeleton: var(--neutral-800);
|
|
--color-grid-line: rgb(255 255 255 / 0.05);
|
|
|
|
--background: oklch(0.145 0 0);
|
|
--foreground: oklch(0.985 0 0);
|
|
--card: oklch(0.145 0 0);
|
|
--card-foreground: oklch(0.985 0 0);
|
|
--popover: oklch(0.145 0 0);
|
|
--popover-foreground: oklch(0.985 0 0);
|
|
--primary: oklch(0.985 0 0);
|
|
--primary-foreground: oklch(0.205 0 0);
|
|
--secondary: oklch(0.269 0 0);
|
|
--secondary-foreground: oklch(0.985 0 0);
|
|
--muted: oklch(0.269 0 0);
|
|
--muted-foreground: oklch(0.708 0 0);
|
|
--accent: oklch(0.269 0 0);
|
|
--accent-foreground: oklch(0.985 0 0);
|
|
--destructive: oklch(0.396 0.141 25.723);
|
|
--destructive-foreground: oklch(0.637 0.237 25.331);
|
|
--border: oklch(0.269 0 0);
|
|
--input: oklch(0.269 0 0);
|
|
--ring: oklch(0.439 0 0);
|
|
--font-weight-medium: 500;
|
|
--font-weight-normal: 400;
|
|
--chart-1: oklch(0.488 0.243 264.376);
|
|
--chart-2: oklch(0.696 0.17 162.48);
|
|
--chart-3: oklch(0.769 0.188 70.08);
|
|
--chart-4: oklch(0.627 0.265 303.9);
|
|
--chart-5: oklch(0.645 0.246 16.439);
|
|
--sidebar: oklch(0.205 0 0);
|
|
--sidebar-foreground: oklch(0.985 0 0);
|
|
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
--sidebar-accent: oklch(0.269 0 0);
|
|
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
--sidebar-border: oklch(0.269 0 0);
|
|
--sidebar-ring: oklch(0.439 0 0);
|
|
}
|
|
|
|
@theme {
|
|
--color-background: var(--background);
|
|
--color-foreground: var(--foreground);
|
|
--color-card: var(--card);
|
|
--color-card-foreground: var(--card-foreground);
|
|
--color-popover: var(--popover);
|
|
--color-popover-foreground: var(--popover-foreground);
|
|
--color-primary: var(--primary);
|
|
--color-primary-foreground: var(--primary-foreground);
|
|
--color-secondary: var(--secondary);
|
|
--color-secondary-foreground: var(--secondary-foreground);
|
|
--color-muted: var(--muted);
|
|
--color-muted-foreground: var(--muted-foreground);
|
|
--color-accent: var(--accent);
|
|
--color-accent-foreground: var(--accent-foreground);
|
|
--color-destructive: var(--destructive);
|
|
--color-destructive-foreground: var(--destructive-foreground);
|
|
--color-border: var(--border);
|
|
--color-input: var(--input);
|
|
--color-input-background: var(--input-background);
|
|
--color-switch-background: var(--switch-background);
|
|
--color-ring: var(--ring);
|
|
--color-chart-1: var(--chart-1);
|
|
--color-chart-2: var(--chart-2);
|
|
--color-chart-3: var(--chart-3);
|
|
--color-chart-4: var(--chart-4);
|
|
--color-chart-5: var(--chart-5);
|
|
--radius-sm: 0rem;
|
|
--radius-md: 0rem;
|
|
--radius-lg: 0rem;
|
|
--radius-xl: 0rem;
|
|
--color-sidebar: var(--sidebar);
|
|
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
--color-sidebar-primary: var(--sidebar-primary);
|
|
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
--color-sidebar-accent: var(--sidebar-accent);
|
|
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
--color-sidebar-border: var(--sidebar-border);
|
|
--color-sidebar-ring: var(--sidebar-ring);
|
|
|
|
--color-swiss-beige: var(--swiss-beige);
|
|
--color-swiss-red: var(--swiss-red);
|
|
--color-swiss-black: var(--swiss-black);
|
|
--color-swiss-white: var(--swiss-white);
|
|
--color-brand: var(--color-brand);
|
|
--color-surface: var(--color-surface);
|
|
--color-paper: var(--color-paper);
|
|
--color-dark-bg: var(--dark-bg);
|
|
--color-dark-card: var(--dark-card);
|
|
|
|
--font-logo: 'Syne', system-ui, -apple-system, 'Segoe UI', Inter, Roboto, Arial, sans-serif;
|
|
--font-mono: 'Space Mono', monospace;
|
|
--font-primary: 'Space Grotesk', system-ui, -apple-system, 'Segoe UI', Inter, Roboto, Arial, sans-serif;
|
|
--font-secondary: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
|
|
|
|
/* Micro typography scale — extends Tailwind's text-xs (0.75rem) downward */
|
|
--text-5xs: 0.4375rem;
|
|
--text-4xs: 0.5rem;
|
|
--text-3xs: 0.5625rem;
|
|
--text-2xs: 0.625rem;
|
|
/* Monospace label tracking — used in Loader and Footnote */
|
|
--tracking-wider-mono: 0.2em;
|
|
|
|
/* Shadow tokens */
|
|
|
|
/* Default resting shadow — equivalent to Tailwind's shadow-sm. Used on
|
|
buttons, sliders, popover triggers in non-floating state. */
|
|
--shadow-rest: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
|
|
/* Swiss "hard offset" stamp — rests at 2px/2px, lifts to 3px/3px on
|
|
hover, presses back to 1px/1px on active. Primary button motif. */
|
|
--shadow-stamp-rest: 0.125rem 0.125rem 0 0 rgb(0 0 0 / 0.1);
|
|
--shadow-stamp-hover: 0.1875rem 0.1875rem 0 0 rgb(0 0 0 / 0.15);
|
|
--shadow-stamp-pressed: 0.0625rem 0.0625rem 0 0 rgb(0 0 0 / 0.1);
|
|
|
|
/* Card-tier hard-offset stamp — wider, brand-tinted. Used on
|
|
interactive cards (FontSampler hover). */
|
|
--shadow-stamp-card: 5px 5px 0 0 var(--color-brand);
|
|
|
|
/* Floating popovers (typography menu, combo control list). */
|
|
--shadow-popover: 0 20px 40px -10px rgb(0 0 0 / 0.15);
|
|
|
|
/* Drop-shadow under semi-translucent floating panels like the
|
|
comparison slider's character row. */
|
|
--shadow-floating-panel: 0 25px 50px -12px rgb(0 0 0 / 0.05);
|
|
--shadow-floating-panel-dark: 0 25px 50px -12px rgb(0 0 0 / 0.2);
|
|
|
|
/* Drawer / overlay shadow — full-strength shadow-2xl. */
|
|
--shadow-overlay: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
|
|
|
/* Motion tokens */
|
|
|
|
--duration-fast: 150ms;
|
|
--duration-normal: 200ms;
|
|
--duration-slow: 300ms;
|
|
--duration-slower: 500ms;
|
|
|
|
/* Tailwind's default ease-in-out — symmetric, good for layout shifts. */
|
|
--ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
|
|
/* Decelerating curve — matches Tailwind's ease-out. Dominant in this codebase. */
|
|
--ease-out-soft: cubic-bezier(0, 0, 0.2, 1);
|
|
/* Spring overshoot — used in character pop animation. */
|
|
--ease-spring-overshoot: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
}
|
|
|
|
@layer base {
|
|
* {
|
|
@apply border-border outline-ring/50;
|
|
}
|
|
|
|
::selection {
|
|
background-color: var(--color-brand);
|
|
color: var(--swiss-white);
|
|
}
|
|
|
|
body {
|
|
@apply bg-background text-foreground;
|
|
font-family: var(--font-secondary);
|
|
font-optical-sizing: auto;
|
|
}
|
|
|
|
html {
|
|
font-size: var(--font-size);
|
|
}
|
|
|
|
h1 {
|
|
font-size: var(--text-2xl);
|
|
font-weight: var(--font-weight-medium);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
h2 {
|
|
font-size: var(--text-xl);
|
|
font-weight: var(--font-weight-medium);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
h3 {
|
|
font-size: var(--text-lg);
|
|
font-weight: var(--font-weight-medium);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
h4 {
|
|
font-size: var(--text-base);
|
|
font-weight: var(--font-weight-medium);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
label {
|
|
font-size: var(--text-base);
|
|
font-weight: var(--font-weight-medium);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
button {
|
|
font-size: var(--text-base);
|
|
font-weight: var(--font-weight-medium);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
input {
|
|
font-size: var(--text-base);
|
|
font-weight: var(--font-weight-normal);
|
|
line-height: 1.5;
|
|
}
|
|
}
|
|
|
|
/* Design-system utilities.
|
|
Defined via `@utility` (Tailwind v4) so they integrate with the variant
|
|
system (`hover:`, `dark:`, breakpoints) and don't rely on `@apply`
|
|
chains. Colors reference the mode-switching semantic vars defined in
|
|
`:root`/`.dark` above, so most utilities need no `dark:` variant in
|
|
their definition or at call sites. */
|
|
|
|
@utility border-subtle {
|
|
border-color: var(--color-border-subtle);
|
|
}
|
|
|
|
/* Same color as border-subtle, applied via background-color — for 1px
|
|
dividers, inline separator strips, and other hairlines that aren't
|
|
element borders. */
|
|
@utility bg-subtle {
|
|
background-color: var(--color-border-subtle);
|
|
}
|
|
|
|
/* Muted text color — paired with `border-subtle` naming. The previous
|
|
name `text-secondary` collided with Tailwind v4 auto-generating a
|
|
utility from `--color-secondary` (the shadcn near-white surface token
|
|
registered in `@theme`), which made every consumer effectively
|
|
invisible (near-white text on light backgrounds). */
|
|
@utility text-subtle {
|
|
color: var(--color-text-subtle);
|
|
}
|
|
|
|
@utility focus-ring {
|
|
&:focus-visible {
|
|
outline: 2px solid transparent;
|
|
outline-offset: 2px;
|
|
box-shadow: 0 0 0 2px var(--color-background, white), 0 0 0 4px var(--color-brand);
|
|
}
|
|
}
|
|
|
|
/* Surface utilities */
|
|
|
|
@utility surface-canvas {
|
|
background-color: var(--color-surface);
|
|
}
|
|
|
|
@utility surface-card {
|
|
background-color: var(--color-paper);
|
|
border: 1px solid var(--color-border-subtle);
|
|
}
|
|
|
|
@utility surface-card-elevated {
|
|
background-color: var(--color-paper);
|
|
border: 1px solid var(--color-border-subtle);
|
|
box-shadow: var(--shadow-rest);
|
|
}
|
|
|
|
@utility surface-popover {
|
|
background-color: var(--color-paper);
|
|
border: 1px solid var(--color-border-subtle);
|
|
box-shadow: var(--shadow-popover);
|
|
}
|
|
|
|
@utility surface-floating {
|
|
background-color: color-mix(in srgb, var(--color-surface) 80%, transparent);
|
|
backdrop-filter: blur(12px);
|
|
border: 1px solid var(--color-border-subtle);
|
|
}
|
|
|
|
/* Shape / layout */
|
|
|
|
@utility flex-center {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
@utility skeleton-fill {
|
|
background-color: color-mix(in srgb, var(--color-skeleton) 70%, transparent);
|
|
}
|
|
|
|
/* Subtle dotted-grid overlay used as a decorative background on the
|
|
comparison paper surface. Color and intensity auto-switch via
|
|
--color-grid-line. `bg-grid-sm` uses a tighter cell — typical mobile
|
|
choice; `bg-grid` is the default desktop cell. Pair with absolute /
|
|
pointer-events-none on the overlay element. */
|
|
@utility bg-grid {
|
|
background-image:
|
|
linear-gradient(var(--color-grid-line) 1px, transparent 1px),
|
|
linear-gradient(90deg, var(--color-grid-line) 1px, transparent 1px);
|
|
background-size: 20px 20px;
|
|
}
|
|
|
|
@utility bg-grid-sm {
|
|
background-image:
|
|
linear-gradient(var(--color-grid-line) 1px, transparent 1px),
|
|
linear-gradient(90deg, var(--color-grid-line) 1px, transparent 1px);
|
|
background-size: 10px 10px;
|
|
}
|
|
|
|
/* Typography */
|
|
|
|
@utility text-label-mono {
|
|
font-family: var(--font-primary);
|
|
font-weight: 700;
|
|
letter-spacing: -0.025em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
/* Honor prefers-reduced-motion: collapse animation and transition timing. */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
* {
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
}
|
|
|
|
/* Hint the upcoming height animation on open collapsibles. */
|
|
[data-state="open"] {
|
|
will-change: height;
|
|
}
|
|
|
|
/* Transition siblings of a focus-visible peer. */
|
|
.peer:focus-visible ~ * {
|
|
transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
@keyframes nudge {
|
|
0%, 100% {
|
|
transform: translateY(0) scale(1) rotate(0deg);
|
|
}
|
|
2% {
|
|
transform: translateY(-2px) scale(1.1) rotate(-1deg);
|
|
}
|
|
4% {
|
|
transform: translateY(0) scale(1) rotate(1deg);
|
|
}
|
|
6% {
|
|
transform: translateY(-2px) scale(1.1) rotate(0deg);
|
|
}
|
|
8% {
|
|
transform: translateY(0) scale(1) rotate(0deg);
|
|
}
|
|
}
|
|
|
|
.animate-nudge {
|
|
animation: nudge 10s ease-in-out infinite;
|
|
}
|
|
|
|
/* Scrollbar styling */
|
|
|
|
/* Standard API: color + width (Chrome 121+, Firefox 64+). */
|
|
@supports (scrollbar-width: auto) {
|
|
* {
|
|
scrollbar-width: thin;
|
|
scrollbar-color: hsl(0 0% 70% / 0.4) var(--color-surface);
|
|
}
|
|
|
|
.dark * {
|
|
scrollbar-color: hsl(0 0% 40% / 0.5) var(--color-surface);
|
|
}
|
|
}
|
|
|
|
/* WebKit fallback: applies on top of the standard API in Chrome, standalone in
|
|
older Safari. Covers what scrollbar-width can't — hiding buttons, exact sizing. */
|
|
@supports selector(::-webkit-scrollbar) {
|
|
::-webkit-scrollbar {
|
|
width: 6px;
|
|
height: 6px;
|
|
}
|
|
|
|
::-webkit-scrollbar-button {
|
|
display: none; /* hide scrollbar buttons */
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: hsl(0 0% 70% / 0.4);
|
|
border-radius: 3px;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: hsl(0 0% 50% / 0.6);
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:active {
|
|
background: hsl(0 0% 40% / 0.8);
|
|
}
|
|
|
|
::-webkit-scrollbar-corner {
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
.dark ::-webkit-scrollbar-thumb { background: hsl(0 0% 40% / 0.5); }
|
|
.dark ::-webkit-scrollbar-thumb:hover { background: hsl(0 0% 55% / 0.6); }
|
|
.dark ::-webkit-scrollbar-thumb:active { background: hsl(0 0% 65% / 0.7); }
|
|
}
|
|
|
|
html {
|
|
scroll-behavior: smooth;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
html { scroll-behavior: auto; }
|
|
}
|
|
|
|
body {
|
|
overscroll-behavior-y: none;
|
|
}
|
|
|
|
.scroll-stable {
|
|
scrollbar-gutter: stable;
|
|
}
|