Files
web_sport/packages/config/tailwind/theme.css
T
2026-08-13 23:20:23 +07:00

246 lines
8.2 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Sport Store — shared design tokens (Tailwind CSS v4, CSS-first configuration).
*
* This file is the SINGLE source of truth for the visual language of both the
* storefront and the admin dashboard. Apps import it after `@import "tailwindcss"`.
*
* Direction: modern, premium, minimal, sport-oriented (Nike / Gymshark spirit).
* High-contrast neutrals, one energetic accent, generous whitespace, tight type.
*/
@theme {
/* ---- Brand ------------------------------------------------------------ */
/* Near-black ink, not pure black: prints and photographs better. */
--color-ink-50: oklch(0.98 0.002 260);
--color-ink-100: oklch(0.95 0.003 260);
--color-ink-200: oklch(0.89 0.004 260);
--color-ink-300: oklch(0.78 0.005 260);
--color-ink-400: oklch(0.63 0.006 260);
--color-ink-500: oklch(0.51 0.007 260);
--color-ink-600: oklch(0.41 0.008 260);
--color-ink-700: oklch(0.32 0.009 260);
--color-ink-800: oklch(0.23 0.01 260);
--color-ink-900: oklch(0.16 0.011 260);
--color-ink-950: oklch(0.11 0.012 260);
/* Energetic accent — "volt". Used sparingly: CTAs, price, sale badges. */
--color-volt-50: oklch(0.97 0.06 125);
--color-volt-100: oklch(0.94 0.11 125);
--color-volt-200: oklch(0.9 0.16 125);
--color-volt-300: oklch(0.86 0.2 125);
--color-volt-400: oklch(0.82 0.23 125);
--color-volt-500: oklch(0.76 0.24 125);
--color-volt-600: oklch(0.66 0.21 125);
--color-volt-700: oklch(0.54 0.17 125);
--color-volt-800: oklch(0.43 0.13 125);
--color-volt-900: oklch(0.35 0.1 125);
/* Semantic */
--color-sale: oklch(0.58 0.21 27);
--color-success: oklch(0.65 0.16 155);
--color-warning: oklch(0.78 0.15 80);
--color-danger: oklch(0.58 0.22 27);
/* ---- Typography ------------------------------------------------------- */
--font-sans: var(--font-inter), ui-sans-serif, system-ui, -apple-system, sans-serif;
--font-display: var(--font-display), var(--font-inter), ui-sans-serif, system-ui, sans-serif;
--font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;
--tracking-display: -0.03em;
/**
* Eyebrow: the 10px uppercase label used for section headings, table
* headers and field labels. It appeared as the arbitrary value
* `text-[0.625rem]` in twenty places before it was a token, which is
* exactly how a type scale stops being a scale.
*/
--text-eyebrow: 0.625rem;
--text-eyebrow--line-height: 1.4;
--text-eyebrow--letter-spacing: 0.1em;
--text-eyebrow--font-weight: 600;
/* ---- Layout ----------------------------------------------------------- */
--spacing-gutter: 1.25rem;
--container-page: 90rem;
--radius-card: 0.25rem;
--radius-pill: 999px;
/**
* Z-index scale. Named, because `z-50` scattered across files is how two
* overlays end up fighting and the loser is whichever rendered first.
*/
--z-sticky: 20;
--z-dropdown: 30;
--z-overlay: 40;
--z-modal: 50;
--z-toast: 60;
/* ---- Motion ----------------------------------------------------------- */
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
--animate-rise: rise 0.5s var(--ease-out-quint) both;
/* Micro-interaction timing. 150–200ms reads as instant-but-smooth; past
300ms a hover starts to feel like lag. */
--duration-fast: 150ms;
--duration-base: 200ms;
}
/**
* ---- shadcn/ui semantic layer --------------------------------------------
*
* shadcn components are written against role tokens (`bg-background`,
* `text-muted-foreground`, `border-input`, `ring-ring`) rather than against a
* palette. This block is the adapter: it gives those roles values drawn from
* the ink/volt scales above, so an unmodified component pasted from the
* registry already looks like this store.
*
* ONE TRAP WORTH NAMING: shadcn's `--accent` is not a brand accent. It is the
* subtle surface behind a hovered ghost button or a highlighted menu row. It
* maps to ink-100. The brand accent stays `--color-volt-*` and is applied
* deliberately — mapping volt here would turn every hover state neon.
*
* The store is committed to a light palette (`color-scheme: light`), so there
* is no `.dark` block. shadcn's `dark:` utilities simply never match, which is
* harmless and keeps the registry components paste-able unedited.
*/
:root {
--background: var(--color-white);
--foreground: var(--color-ink-950);
--card: var(--color-white);
--card-foreground: var(--color-ink-950);
--popover: var(--color-white);
--popover-foreground: var(--color-ink-950);
--primary: var(--color-ink-950);
--primary-foreground: var(--color-white);
--secondary: var(--color-ink-100);
--secondary-foreground: var(--color-ink-950);
--muted: var(--color-ink-100);
--muted-foreground: var(--color-ink-500);
/* Hover/active surface — see the trap noted above. */
--accent: var(--color-ink-100);
--accent-foreground: var(--color-ink-950);
--destructive: var(--color-danger);
--destructive-foreground: var(--color-white);
--border: var(--color-ink-200);
--input: var(--color-ink-200);
--ring: var(--color-ink-950);
/* Sport/streetwear geometry: near-square. Raising this rounds every
registry component at once, which is the point of keeping it here. */
--radius: 0.25rem;
}
@theme inline {
--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-ring: var(--ring);
--radius-sm: calc(var(--radius) - 2px);
--radius-md: var(--radius);
--radius-lg: calc(var(--radius) + 2px);
--radius-xl: calc(var(--radius) + 6px);
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(0.75rem);
}
to {
opacity: 1;
transform: none;
}
}
@layer base {
:root {
color-scheme: light;
}
html {
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
/* Sport/streetwear headings: tight, uppercase-capable, no letterspacing drift. */
h1,
h2,
h3 {
letter-spacing: var(--tracking-display);
text-wrap: balance;
}
::selection {
background-color: var(--color-volt-300);
color: var(--color-ink-950);
}
/**
* One focus ring for the whole product.
*
* Applied to `:focus-visible` rather than `:focus`, so it appears for
* keyboard and programmatic focus but not on mouse clicks — the reason
* teams remove focus outlines in the first place.
*
* This is a *baseline*, not a replacement for component-level styles: it
* means a plain <button> written in a hurry is still keyboard-navigable.
* Sixteen of them across twelve files had no focus indicator at all before
* this rule existed.
*/
:focus-visible {
outline: 2px solid var(--color-ink-950);
outline-offset: 2px;
border-radius: var(--radius-sm);
}
/* On dark surfaces an ink ring is invisible; invert it. */
.on-dark :focus-visible,
.bg-ink-950 :focus-visible {
outline-color: var(--color-volt-400);
}
}
/**
* ---- Reduced motion --------------------------------------------------------
*
* Honouring `prefers-reduced-motion` is an accessibility requirement, not a
* nicety: for people with vestibular disorders, movement can cause actual
* nausea. Animation is reduced to near-zero rather than removed, because
* `animation: none` can leave elements stuck in their pre-animation state —
* `--animate-rise` starts at `opacity: 0`, so disabling it outright would
* make content invisible.
*/
@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;
}
}