tailwind.config.mts
Rama main · réplica de lectura del repositorio original.
import type { Config } from "tailwindcss";
const config: Config = {
darkMode: "class",
content: ["./src/**/*.{ts,tsx}"],
prefix: "",
theme: {
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
// One class per brand accent, on purpose. These were objects with
// `solid` and `text` variants tuned for contrast in specific spots; the
// palette is now one hue each, so `bg-coral`/`text-coral` and
// `bg-teal`/`text-teal` are the whole vocabulary. `destructive` below
// keeps its `solid` variant - errors are the deliberate exception.
//
// The `foreground` on each is not a second coral or a second teal. It is
// the label that sits *on* that fill, the pairing every other filled token
// here already has, and the collapse was about differently-tuned brand
// hues rather than about the object.
coral: {
DEFAULT: "hsl(var(--coral))",
foreground: "hsl(var(--coral-foreground))",
},
teal: {
DEFAULT: "hsl(var(--teal))",
foreground: "hsl(var(--teal-foreground))",
},
pressure: "hsl(var(--pressure))",
ceiling: "hsl(var(--ceiling))",
// The channels under the depth plot, one accent each - see the blocks on
// these in `globals.css` for the hues and the contrast they were measured
// at.
"heart-rate": "hsl(var(--heart-rate))",
ndl: "hsl(var(--ndl))",
tts: "hsl(var(--tts))",
ppo2: "hsl(var(--ppo2))",
cns: "hsl(var(--cns))",
"gradient-factor": "hsl(var(--gradient-factor))",
"surface-gradient-factor": "hsl(var(--surface-gradient-factor))",
"gas-oxygen": "hsl(var(--gas-oxygen))",
"gas-helium": "hsl(var(--gas-helium))",
// Whole colours, not HSL triplets - see `--map-water` in `globals.css`.
"map-water": {
DEFAULT: "var(--map-water)",
foreground: "var(--map-water-foreground)",
},
tooltip: {
DEFAULT: "hsl(var(--tooltip))",
foreground: "hsl(var(--tooltip-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
solid: "hsl(var(--destructive-solid))",
foreground: "hsl(var(--destructive-foreground))",
},
success: {
DEFAULT: "hsl(var(--success))",
foreground: "hsl(var(--success-foreground))",
},
warning: {
DEFAULT: "hsl(var(--warning))",
foreground: "hsl(var(--warning-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
fontFamily: {
wordmark: ["var(--font-outfit)", "sans-serif"],
},
// Not `tracking-tight` (-0.025em), which crowds a geometric face.
letterSpacing: {
wordmark: "-0.01em",
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
"skeleton-in": {
from: { opacity: "0" },
to: { opacity: "1" },
},
"skeleton-pulse": {
"0%, 100%": { opacity: "1" },
"50%": { opacity: "0.5" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
// Two animations, and the delay on the first is the point: a skeleton
// takes up its space immediately but stays *invisible* for 150ms, so a
// response that beats it (most of them, against a local API) swaps
// straight from the old page to the new one with no grey flash in
// between - while still reserving the layout, so nothing jumps when it
// lands. Only a load slow enough to be worth reporting is ever seen,
// and once seen it breathes so it reads as pending rather than broken.
// `both` is what holds opacity at 0 through the delay.
//
// One flat delay, counted from the placeholder's own insertion, which is
// also the click: a route draws its own frame as it mounts, and there is
// no second renderer of that frame to carry a delay across.
skeleton:
"skeleton-in 200ms ease-out 150ms both, skeleton-pulse 1.8s ease-in-out 350ms infinite",
// The reveal half on its own, for the *chrome* a placeholder draws - the
// card outlines and row borders. Those are real `Card`s and `TableRow`s,
// so without this they paint instantly and a fast response still flashes
// a grid of empty bordered boxes, which is most of what the delay exists
// to prevent. Deliberately not the full `skeleton` shorthand: a pulsing
// container multiplied by a pulsing bar would dip the bars to a quarter
// opacity instead of half.
"skeleton-reveal": "skeleton-in 200ms ease-out 150ms both",
},
},
},
plugins: [require("tailwindcss-animate")],
};
export default config;