@tailwind base; @tailwind components; @tailwind utilities; /* ================================================================== EDITORIAL DESIGN SYSTEM — global tokens & type CUSTOMIZATION HOOK: design tokens are mirrored from tailwind.config.ts as CSS variables so plain CSS (grain, gradients) can reuse them. ================================================================== */ :root { color-scheme: light; --ink: #0a0a0a; --ivory: #f5f1e8; --paper: #ece6d6; --line: #d8d1c0; --vermillion: #d9342b; --cobalt: #1b3a8a; /* CUSTOMIZATION HOOK — MOTION: global reveal timing */ --reveal-duration: 600ms; --reveal-ease: cubic-bezier(0.16, 1, 0.3, 1); } html { scroll-behavior: smooth; } body { @apply bg-ivory text-ink font-sans antialiased; /* Subtle paper grain — pure CSS, no asset. */ background-image: radial-gradient( rgba(10, 10, 10, 0.022) 1px, transparent 1px ); background-size: 4px 4px; } ::selection { background: var(--vermillion); color: var(--ivory); } /* ================================================================== COMPONENT LAYER — editorial primitives ================================================================== */ @layer components { .container-content { @apply mx-auto w-full max-w-content px-5 sm:px-8 lg:px-12; } /* Massive magazine display title (English serif). */ .display { @apply font-display text-display font-light; font-optical-sizing: auto; } /* Smaller display title — used for long fallback words (PageHeader `en`) and figures that should not read at the full cover scale (e.g. the "2026" issue year on /intro). Mirrors `.display` at the `display-sm` type ramp. See LAYOUT_AUDIT #6 + #10. */ .display-sm { @apply font-display text-display-sm font-light; font-optical-sizing: auto; } /* Korean serif headline. */ .headline-ko { @apply font-serif-ko font-semibold tracking-tight; } /* Small-caps kicker / eyebrow with wide tracking. */ .kicker { @apply font-sans text-[0.7rem] font-semibold uppercase tracking-caps text-ink-mute; } /* Corner "01 / 05" spread numbering. Bumped from text-sm (14px) to text-base (16px) so the editorial spread number reads as "page number", not body copy. See LAYOUT_AUDIT #17. */ .corner-label { @apply font-display text-base font-medium tabular-nums tracking-wide text-ink-mute; } /* Huge italic serif pull-quote. */ .pull-quote { @apply font-display text-3xl font-light italic leading-tight sm:text-4xl lg:text-5xl; } /* Hairline editorial rule. */ .rule { @apply border-t border-ink/80; } /* Magazine inset card on dimmer paper. */ .spread-card { @apply border border-ink/15 bg-paper transition duration-500; } /* Animated underline-draw on hover (for links). */ .draw-underline { background-image: linear-gradient(var(--vermillion), var(--vermillion)); background-position: 0 100%; background-repeat: no-repeat; background-size: 0% 2px; transition: background-size 0.4s var(--reveal-ease); } .draw-underline:hover { background-size: 100% 2px; } } /* ================================================================== MOTION — scroll reveal (paired with components/Reveal.tsx) CUSTOMIZATION HOOK — MOTION: edit transforms / duration here. ================================================================== */ .reveal { opacity: 0; transform: translateY(28px); transition: opacity var(--reveal-duration) var(--reveal-ease), transform var(--reveal-duration) var(--reveal-ease); will-change: opacity, transform; } .reveal[data-variant="left"] { transform: translateX(-40px); } .reveal[data-variant="right"] { transform: translateX(40px); } .reveal[data-variant="scale"] { transform: scale(0.96); } .reveal.is-visible { opacity: 1; transform: none; } /* Marquee track must be 2× content for a seamless loop. */ .marquee-track { display: inline-flex; white-space: nowrap; will-change: transform; } /* Respect users who prefer reduced motion. */ @media (prefers-reduced-motion: reduce) { .reveal { opacity: 1 !important; transform: none !important; transition: none; } .marquee-track, [class*="animate-"] { animation: none !important; } html { scroll-behavior: auto; } }