@import "tailwindcss"; @import "tw-animate-css"; @import "shadcn/tailwind.css"; @custom-variant dark (&:where(.dark, .dark *)); @custom-variant sun (&:where([data-contrast="sun"] *)); @custom-variant pointer-fine (@media (pointer: fine)); @custom-variant pointer-coarse (@media (pointer: coarse)); /* Type scale (spec 4.5): text-xs is 13 px (sun: 14 px), only for axes, legends and footers. */ @theme { --text-xs: 0.8125rem; --text-xs--line-height: calc(1.125 / 0.8125); } @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); --font-sans: var(--font-body); --font-mono: var(--font-data); --font-heading: var(--font-heading); --color-sidebar-ring: var(--sidebar-ring); --color-sidebar-border: var(--sidebar-border); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar: var(--sidebar); --color-chart-5: var(--chart-5); --color-chart-4: var(--chart-4); --color-chart-3: var(--chart-3); --color-chart-2: var(--chart-2); --color-chart-1: var(--chart-1); --color-ring: var(--ring); --color-input: var(--input); --color-border: var(--border); --color-destructive: var(--destructive); --color-warning: var(--warning); --color-warning-foreground: var(--warning-foreground); --color-success: var(--success); --color-success-foreground: var(--success-foreground); --color-condition-excellent: var(--condition-excellent); --color-condition-excellent-foreground: var(--condition-excellent-foreground); --color-condition-good: var(--condition-good); --color-condition-good-foreground: var(--condition-good-foreground); --color-condition-average: var(--condition-average); --color-condition-average-foreground: var(--condition-average-foreground); --color-condition-weak: var(--condition-weak); --color-condition-weak-foreground: var(--condition-weak-foreground); --color-condition-critical: var(--condition-critical); --color-condition-critical-foreground: var(--condition-critical-foreground); --color-holo-bg: var(--holo-bg); --color-holo-edge: var(--holo-edge); --color-holo-edge-strong: var(--holo-edge-strong); --color-holo-fill: var(--holo-fill); --color-holo-label-bg: var(--holo-label-bg); --color-holo-label-fg: var(--holo-label-fg); --color-primary-ink: var(--primary-ink); --color-warning-ink: var(--warning-ink); --color-destructive-foreground: var(--destructive-foreground); --color-condition-excellent-ink: var(--condition-excellent-ink); --color-condition-good-ink: var(--condition-good-ink); --color-condition-average-ink: var(--condition-average-ink); --color-condition-weak-ink: var(--condition-weak-ink); --color-condition-critical-ink: var(--condition-critical-ink); --color-area-betrieb: var(--area-betrieb); --color-area-erfassung: var(--area-erfassung); --color-area-arbeit: var(--area-arbeit); --color-area-ernte: var(--area-ernte); --color-area-neutral: var(--area-neutral); --color-queen-white: var(--queen-white); --color-queen-yellow: var(--queen-yellow); --color-queen-red: var(--queen-red); --color-queen-green: var(--queen-green); --color-queen-blue: var(--queen-blue); --color-accent-foreground: var(--accent-foreground); --color-accent: var(--accent); --color-muted-foreground: var(--muted-foreground); --color-muted: var(--muted); --color-secondary-foreground: var(--secondary-foreground); --color-secondary: var(--secondary); --color-primary-foreground: var(--primary-foreground); --color-primary: var(--primary); --color-popover-foreground: var(--popover-foreground); --color-popover: var(--popover); --color-card-foreground: var(--card-foreground); --color-card: var(--card); --radius-sm: calc(var(--radius) * 0.6); --radius-md: calc(var(--radius) * 0.8); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) * 1.4); --radius-2xl: calc(var(--radius) * 1.8); --radius-3xl: calc(var(--radius) * 2.2); --radius-4xl: calc(var(--radius) * 2.6); --animate-page-in: page-in 260ms ease-out; } @keyframes page-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } } :root { --background: oklch(0.968 0.014 85); --foreground: oklch(0.21 0.03 55); --card: oklch(0.995 0.004 90); --card-foreground: oklch(0.21 0.03 55); --popover: oklch(0.995 0.004 90); --popover-foreground: oklch(0.21 0.03 55); --primary: oklch(0.8 0.145 78); --primary-foreground: oklch(0.21 0.035 55); --secondary: oklch(0.44 0.07 145); --secondary-foreground: oklch(0.98 0.015 100); --muted: oklch(0.925 0.018 82); --muted-foreground: oklch(0.44 0.03 60); --accent: oklch(0.935 0.03 78); --accent-foreground: oklch(0.25 0.045 50); --destructive: oklch(0.5 0.17 28); --border: oklch(0.86 0.022 78); --input: oklch(0.6 0.035 65); --ring: oklch(0.47 0.115 55); --warning: oklch(0.79 0.15 80); --warning-foreground: oklch(0.23 0.04 60); --success: oklch(0.46 0.08 145); --success-foreground: oklch(0.98 0.015 100); --condition-excellent: oklch(0.62 0.13 150); --condition-excellent-foreground: oklch(0.15 0.04 150); --condition-good: oklch(0.645 0.13 125); --condition-good-foreground: oklch(0.17 0.04 125); --condition-average: oklch(0.665 0.125 88); --condition-average-foreground: oklch(0.19 0.04 90); --condition-weak: oklch(0.665 0.14 58); --condition-weak-foreground: oklch(0.18 0.04 55); --condition-critical: oklch(0.62 0.17 30); --condition-critical-foreground: oklch(0.15 0.04 30); --chart-1: oklch(0.56 0.13 55); --chart-2: oklch(0.46 0.08 145); --chart-3: oklch(0.6 0.12 85); --chart-4: oklch(0.5 0.17 28); --chart-5: oklch(0.52 0.08 250); --radius: 0.75rem; --sidebar: oklch(0.995 0.004 90); --sidebar-foreground: oklch(0.21 0.03 55); --sidebar-primary: oklch(0.8 0.145 78); --sidebar-primary-foreground: oklch(0.21 0.035 55); --sidebar-accent: oklch(0.935 0.03 78); --sidebar-accent-foreground: oklch(0.25 0.045 50); --sidebar-border: oklch(0.86 0.022 78); --sidebar-ring: oklch(0.47 0.115 55); --shadow-elevated: 0 1px 2px -1px oklch(0.3 0.05 50 / 8%), 0 8px 24px -8px oklch(0.3 0.05 50 / 16%); --shadow-soft: 0 1px 2px -1px oklch(0.3 0.05 50 / 6%), 0 4px 12px -4px oklch(0.3 0.05 50 / 10%); /* Hive "screen": always dark, in light and dark mode (spec 9.3). */ --holo-bg: oklch(0.18 0.03 250); --holo-edge: oklch(0.72 0.15 243); --holo-edge-strong: oklch(0.87 0.07 238); --holo-fill: oklch(0.78 0.14 220 / 10%); --holo-label-bg: oklch(0.26 0.04 250); --holo-label-fg: oklch(0.95 0.02 230); /* T5 tokens (spec 4.2). */ --primary-ink: oklch(0.47 0.115 55); --warning-ink: oklch(0.5 0.11 65); --destructive-foreground: oklch(0.985 0.005 30); --condition-excellent-ink: oklch(0.4 0.09 150); --condition-good-ink: oklch(0.41 0.09 125); --condition-average-ink: oklch(0.44 0.09 85); --condition-weak-ink: oklch(0.46 0.12 52); --condition-critical-ink: oklch(0.47 0.16 28); --area-betrieb: oklch(0.46 0.08 150); --area-erfassung: oklch(0.5 0.12 60); --area-arbeit: oklch(0.48 0.08 250); --area-ernte: oklch(0.52 0.11 75); --area-neutral: oklch(0.45 0.02 60); --queen-white: oklch(0.97 0.005 90); --queen-yellow: oklch(0.86 0.17 95); --queen-red: oklch(0.58 0.2 27); --queen-green: oklch(0.58 0.15 145); --queen-blue: oklch(0.52 0.15 255); --focus-width: 2px; --focus-offset: 2px; --control-border-width: 1px; --comb-stroke-1: 2px; --comb-stroke-2: 4px; --comb-stroke-3: 6px; } .dark { --background: oklch(0.19 0.016 55); --foreground: oklch(0.95 0.018 80); --card: oklch(0.235 0.018 55); --card-foreground: oklch(0.95 0.018 80); --popover: oklch(0.235 0.018 55); --popover-foreground: oklch(0.95 0.018 80); --primary: oklch(0.8 0.14 78); --primary-foreground: oklch(0.19 0.03 55); --secondary: oklch(0.66 0.08 145); --secondary-foreground: oklch(0.16 0.02 145); --muted: oklch(0.28 0.018 55); --muted-foreground: oklch(0.76 0.025 75); --accent: oklch(0.31 0.03 60); --accent-foreground: oklch(0.95 0.018 80); --destructive: oklch(0.7 0.15 28); --border: oklch(0.34 0.02 60); --input: oklch(0.56 0.025 70); --ring: oklch(0.82 0.13 80); --warning: oklch(0.8 0.14 80); --warning-foreground: oklch(0.2 0.03 60); --success: oklch(0.7 0.09 145); --success-foreground: oklch(0.16 0.02 145); --condition-excellent: oklch(0.68 0.12 150); --condition-excellent-foreground: oklch(0.17 0.04 150); --condition-good: oklch(0.72 0.12 125); --condition-good-foreground: oklch(0.18 0.04 125); --condition-average: oklch(0.77 0.13 90); --condition-average-foreground: oklch(0.2 0.04 90); --condition-weak: oklch(0.74 0.13 60); --condition-weak-foreground: oklch(0.19 0.04 55); --condition-critical: oklch(0.68 0.16 28); --condition-critical-foreground: oklch(0.16 0.04 30); --chart-1: oklch(0.78 0.13 70); --chart-2: oklch(0.7 0.09 145); --chart-3: oklch(0.82 0.12 90); --chart-4: oklch(0.7 0.15 28); --chart-5: oklch(0.72 0.08 250); --sidebar: oklch(0.235 0.018 55); --sidebar-foreground: oklch(0.95 0.018 80); --sidebar-primary: oklch(0.8 0.14 78); --sidebar-primary-foreground: oklch(0.19 0.03 55); --sidebar-accent: oklch(0.31 0.03 60); --sidebar-accent-foreground: oklch(0.95 0.018 80); --sidebar-border: oklch(0.34 0.02 60); --sidebar-ring: oklch(0.82 0.13 80); --shadow-elevated: 0 1px 2px -1px oklch(0 0 0 / 30%), 0 8px 24px -8px oklch(0 0 0 / 45%); --shadow-soft: 0 1px 2px -1px oklch(0 0 0 / 25%), 0 4px 12px -4px oklch(0 0 0 / 30%); /* Hive "screen": always dark, in light and dark mode (spec 9.3). */ --holo-bg: oklch(0.18 0.03 250); --holo-edge: oklch(0.72 0.15 243); --holo-edge-strong: oklch(0.87 0.07 238); --holo-fill: oklch(0.78 0.14 220 / 10%); --holo-label-bg: oklch(0.26 0.04 250); --holo-label-fg: oklch(0.95 0.02 230); /* T5 tokens (spec 4.2). */ --primary-ink: oklch(0.82 0.13 80); --warning-ink: oklch(0.82 0.13 82); --destructive-foreground: oklch(0.17 0.03 30); --condition-excellent-ink: oklch(0.8 0.11 150); --condition-good-ink: oklch(0.83 0.11 125); --condition-average-ink: oklch(0.86 0.11 90); --condition-weak-ink: oklch(0.82 0.11 60); --condition-critical-ink: oklch(0.78 0.11 28); --area-betrieb: oklch(0.74 0.09 150); --area-erfassung: oklch(0.8 0.12 70); --area-arbeit: oklch(0.76 0.07 250); --area-ernte: oklch(0.8 0.1 80); --area-neutral: oklch(0.76 0.02 70); --queen-white: oklch(0.97 0.005 90); --queen-yellow: oklch(0.86 0.17 95); --queen-red: oklch(0.62 0.2 27); --queen-green: oklch(0.66 0.15 145); --queen-blue: oklch(0.62 0.15 255); } /* Sun ("Sonne"): maximum luminance difference outdoors (spec 4.3). The two sets follow the order light, dark, sun-light, sun-dark; sun-dark restates everything sun-light sets. */ :root[data-contrast="sun"] { --background: oklch(1 0 0); --card: oklch(1 0 0); --popover: oklch(1 0 0); --sidebar: oklch(1 0 0); --foreground: oklch(0.13 0.02 55); --card-foreground: oklch(0.13 0.02 55); --popover-foreground: oklch(0.13 0.02 55); --sidebar-foreground: oklch(0.13 0.02 55); --primary-foreground: oklch(0.13 0.02 55); --ring: oklch(0.13 0.02 55); --muted: oklch(0.95 0.01 80); --muted-foreground: oklch(0.32 0.03 60); --border: oklch(0.4 0.03 60); --input: oklch(0.2 0.03 55); --primary-ink: oklch(0.38 0.1 52); --text-sm: 1rem; --text-xs: 0.875rem; --focus-width: 3px; --control-border-width: 2px; --comb-stroke-1: 3px; --comb-stroke-2: 5px; --comb-stroke-3: 7px; --shadow-soft: none; --shadow-elevated: none; /* Hive stage: black screen, pure white edges and label text. */ --holo-bg: oklch(0 0 0); --holo-edge: oklch(1 0 0); --holo-edge-strong: oklch(1 0 0); --holo-label-fg: oklch(1 0 0); --holo-label-bg: oklch(0.12 0 0); } .dark[data-contrast="sun"] { --background: oklch(0.1 0.005 55); --card: oklch(0.1 0.005 55); --popover: oklch(0.1 0.005 55); --sidebar: oklch(0.1 0.005 55); --foreground: oklch(0.99 0.005 85); --card-foreground: oklch(0.99 0.005 85); --popover-foreground: oklch(0.99 0.005 85); --sidebar-foreground: oklch(0.99 0.005 85); --primary-foreground: oklch(0.19 0.03 55); --ring: oklch(0.99 0.005 85); --muted: oklch(0.2 0.01 55); --muted-foreground: oklch(0.88 0.02 80); --border: oklch(0.7 0.02 70); --input: oklch(0.92 0.01 80); --primary-ink: oklch(0.82 0.13 80); --text-sm: 1rem; --text-xs: 0.875rem; --focus-width: 3px; --control-border-width: 2px; --comb-stroke-1: 3px; --comb-stroke-2: 5px; --comb-stroke-3: 7px; --shadow-soft: none; --shadow-elevated: none; --holo-bg: oklch(0 0 0); --holo-edge: oklch(1 0 0); --holo-edge-strong: oklch(1 0 0); --holo-label-fg: oklch(1 0 0); --holo-label-bg: oklch(0.12 0 0); } /* The hive stage is its own always-dark surface; the page focus ring (--primary-ink) has less than 3:1 on it (spec 17.8), so the stage draws the ring in its strong edge colour. */ .holo-stage { --ring: var(--holo-edge-strong); } /* A page-coloured card on the stage (the outline panel) takes the page ring back. The root keeps a copy of its ring for that, resolved for the current set (light, dark, sun). */ html { --page-ring: var(--ring); } .holo-stage .stage-card { --ring: var(--page-ring); } /* Tinted surfaces: set --tint (and --tint-ink) on the element. In sun the tint becomes the plain card with a 2 px border in the ink instead of a 15 % wash (spec 4.3). */ @layer components { .tint { --tint: var(--primary); --tint-ink: var(--primary-ink); background-color: color-mix(in oklch, var(--tint) 15%, transparent); } } :root[data-contrast="sun"] .tint { background-color: var(--card); border: var(--control-border-width) solid var(--tint-ink); } :root[data-contrast="sun"] body header.sticky { background-color: var(--card); backdrop-filter: none; } /* Print and PDF preview always use the light set (spec 4.1). Kept in step with :root by contrast.spec.ts. */ @media print { :root, .dark, :root[data-contrast="sun"], .dark[data-contrast="sun"] { --background: oklch(0.968 0.014 85); --foreground: oklch(0.21 0.03 55); --card: oklch(0.995 0.004 90); --card-foreground: oklch(0.21 0.03 55); --popover: oklch(0.995 0.004 90); --popover-foreground: oklch(0.21 0.03 55); --primary: oklch(0.8 0.145 78); --primary-foreground: oklch(0.21 0.035 55); --secondary: oklch(0.44 0.07 145); --secondary-foreground: oklch(0.98 0.015 100); --muted: oklch(0.925 0.018 82); --muted-foreground: oklch(0.44 0.03 60); --accent: oklch(0.935 0.03 78); --accent-foreground: oklch(0.25 0.045 50); --destructive: oklch(0.5 0.17 28); --border: oklch(0.86 0.022 78); --input: oklch(0.6 0.035 65); --ring: oklch(0.47 0.115 55); --warning: oklch(0.79 0.15 80); --warning-foreground: oklch(0.23 0.04 60); --success: oklch(0.46 0.08 145); --success-foreground: oklch(0.98 0.015 100); --condition-excellent: oklch(0.62 0.13 150); --condition-excellent-foreground: oklch(0.15 0.04 150); --condition-good: oklch(0.645 0.13 125); --condition-good-foreground: oklch(0.17 0.04 125); --condition-average: oklch(0.665 0.125 88); --condition-average-foreground: oklch(0.19 0.04 90); --condition-weak: oklch(0.665 0.14 58); --condition-weak-foreground: oklch(0.18 0.04 55); --condition-critical: oklch(0.62 0.17 30); --condition-critical-foreground: oklch(0.15 0.04 30); --chart-1: oklch(0.56 0.13 55); --chart-2: oklch(0.46 0.08 145); --chart-3: oklch(0.6 0.12 85); --chart-4: oklch(0.5 0.17 28); --chart-5: oklch(0.52 0.08 250); --sidebar: oklch(0.995 0.004 90); --sidebar-foreground: oklch(0.21 0.03 55); --sidebar-primary: oklch(0.8 0.145 78); --sidebar-primary-foreground: oklch(0.21 0.035 55); --sidebar-accent: oklch(0.935 0.03 78); --sidebar-accent-foreground: oklch(0.25 0.045 50); --sidebar-border: oklch(0.86 0.022 78); --sidebar-ring: oklch(0.47 0.115 55); --shadow-elevated: 0 1px 2px -1px oklch(0.3 0.05 50 / 8%), 0 8px 24px -8px oklch(0.3 0.05 50 / 16%); --shadow-soft: 0 1px 2px -1px oklch(0.3 0.05 50 / 6%), 0 4px 12px -4px oklch(0.3 0.05 50 / 10%); --holo-bg: oklch(0.18 0.03 250); --holo-edge: oklch(0.72 0.15 243); --holo-edge-strong: oklch(0.87 0.07 238); --holo-fill: oklch(0.78 0.14 220 / 10%); --holo-label-bg: oklch(0.26 0.04 250); --holo-label-fg: oklch(0.95 0.02 230); --primary-ink: oklch(0.47 0.115 55); --warning-ink: oklch(0.5 0.11 65); --destructive-foreground: oklch(0.985 0.005 30); --condition-excellent-ink: oklch(0.4 0.09 150); --condition-good-ink: oklch(0.41 0.09 125); --condition-average-ink: oklch(0.44 0.09 85); --condition-weak-ink: oklch(0.46 0.12 52); --condition-critical-ink: oklch(0.47 0.16 28); --area-betrieb: oklch(0.46 0.08 150); --area-erfassung: oklch(0.5 0.12 60); --area-arbeit: oklch(0.48 0.08 250); --area-ernte: oklch(0.52 0.11 75); --area-neutral: oklch(0.45 0.02 60); --queen-white: oklch(0.97 0.005 90); --queen-yellow: oklch(0.86 0.17 95); --queen-red: oklch(0.58 0.2 27); --queen-green: oklch(0.58 0.15 145); --queen-blue: oklch(0.52 0.15 255); --text-sm: 0.875rem; --text-xs: 0.8125rem; --focus-width: 2px; --control-border-width: 1px; --comb-stroke-1: 2px; --comb-stroke-2: 4px; --comb-stroke-3: 6px; } } /* Forced colours: the system palette wins; strokes use CanvasText so shapes stay visible. */ @media (forced-colors: active) { :root, .dark, :root[data-contrast="sun"], .dark[data-contrast="sun"] { --ring: CanvasText; --border: CanvasText; --input: CanvasText; } } /* --------------------------------------------------------------------------- App chrome (see app/(app)/layout.tsx) The page scrolls on the window. On phones a fixed bottom nav sits over its lower edge, on iOS above the home indicator (needs viewport-fit=cover). Content padding, the sticky save bar, the quick-add button and the focus scroll-padding below all derive from these values, so they stay in step. ------------------------------------------------------------------------ */ :root { --safe-area-bottom: env(safe-area-inset-bottom, 0px); --safe-area-left: env(safe-area-inset-left, 0px); --safe-area-right: env(safe-area-inset-right, 0px); --bottom-nav-height: calc(4rem + var(--safe-area-bottom)); /* Sticky header (3.5rem) plus breathing room. */ --header-clearance: 4.5rem; /* StickySubmit with its 48px button (~4.6rem) plus breathing room. */ --sticky-submit-clearance: 5.5rem; /* Toasts sit above the sticky save bar. Below sm also above the bottom nav, which carries the quick-add button (nav + 1rem + 3rem, less than the bar). */ --toast-offset-bottom: calc(var(--bottom-nav-height) + var(--sticky-submit-clearance) + 0.5rem); @variant sm { --toast-offset-bottom: calc(var(--safe-area-bottom) + var(--sticky-submit-clearance) + 0.5rem); } } @layer base { * { @apply border-border; } /* One focus style for everything (spec 4.6): a solid ring in --ring with a gap, 3 px in sun. Components add no focus classes; a row whose focus target sits inside uses focus-ring-within. */ :where(:focus-visible) { outline: var(--focus-width) solid var(--ring); outline-offset: var(--focus-offset); } /* Firefox: the preflight sets `:-moz-focusring:where(:not(iframe)) { outline: auto }` (0,1,0), which beats the rule above. Firefox matches :-moz-focusring exactly where it matches :focus-visible (keyboard, not a mouse click), so restating the ring here adds nothing else. */ :-moz-focusring:where(:not(iframe)) { outline: var(--focus-width) solid var(--ring); outline-offset: var(--focus-offset); } body { @apply bg-background text-foreground; } html { @apply font-sans; /* WCAG 2.4.11: a field scrolled into view by focus must not end up under the sticky header, the bottom nav / quick-add button or the save bar. */ scroll-padding-top: var(--header-clearance); scroll-padding-bottom: calc(var(--bottom-nav-height) + var(--sticky-submit-clearance)); @variant sm { scroll-padding-bottom: calc(var(--sticky-submit-clearance) + var(--safe-area-bottom)); } } h1, h2, h3, h4 { font-family: var(--font-heading); letter-spacing: -0.01em; } ::selection { background: color-mix(in oklch, var(--primary) 28%, transparent); color: var(--foreground); } input, textarea { caret-color: var(--primary-ink); } } /* A row whose focus target sits inside (a label with its checkbox, radio or a visually hidden input) also rings the whole row, so the focus is easy to spot from arm's length (spec 4.6). */ @utility focus-ring-within { &:has(:focus-visible) { outline: var(--focus-width) solid var(--ring); outline-offset: var(--focus-offset); } } /* --------------------------------------------------------------------------- Motion levels (see lib/motion/motion-preference.ts) html[data-motion] = full | subtle | off, chosen per device in the profile. The OS "reduce motion" setting always wins over "full". `motion-full:` = spatial movement allowed (level full AND system allows). ------------------------------------------------------------------------ */ @custom-variant motion-full { @media (prefers-reduced-motion: no-preference) { &:where(:root:not([data-motion="subtle"]):not([data-motion="off"]) *) { @slot; } } } :root { --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); } /* Off: every state change is instant. Colour and icon still carry the state. */ :root[data-motion="off"] *, :root[data-motion="off"] *::before, :root[data-motion="off"] *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; transition-delay: 0ms !important; } /* Subtle / system reduce: keep fades, drop movement. */ :root[data-motion="subtle"] .motion-safe\:animate-page-in { animation-name: fade-in; } @media (prefers-reduced-motion: reduce) { .motion-safe\:animate-page-in { animation: fade-in 160ms ease-out; } } :root[data-motion="subtle"] [data-slot="card"] { translate: none !important; } @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } /* --- Task completion: the one authored moment ------------------------------ The honey cell fills, the tick draws itself, then the row folds away. */ .honey-check { position: relative; display: inline-grid; place-items: center; flex-shrink: 0; width: 2.75rem; height: 2.75rem; border-radius: 9999px; color: var(--primary-foreground); } .honey-check::before { content: ""; position: absolute; inset: 0.375rem; border-radius: 0.6rem; border: 2px solid var(--input); background: var(--card); transition: border-color 150ms ease-out, background-color 150ms ease-out; } .honey-check::after { content: ""; position: absolute; inset: 0.375rem; border-radius: 0.6rem; background: var(--primary); clip-path: circle(0% at 50% 60%); transition: clip-path 420ms var(--ease-out-expo); } .honey-check:hover::before { border-color: var(--primary); background: color-mix(in oklch, var(--primary) 8%, var(--card)); } .honey-check svg { position: relative; z-index: 1; width: 1.1rem; height: 1.1rem; stroke-dasharray: 24; stroke-dashoffset: 24; transition: stroke-dashoffset 260ms var(--ease-out-expo) 160ms; } .honey-check[aria-checked="true"]::after { clip-path: circle(75% at 50% 60%); } .honey-check[aria-checked="true"] svg { stroke-dashoffset: 0; } .today-row { display: grid; grid-template-rows: 1fr; opacity: 1; transition: grid-template-rows 320ms var(--ease-out-expo) 380ms, opacity 220ms ease-out 360ms; } .today-row > * { min-height: 0; overflow: hidden; } .today-row[data-leaving="true"] { grid-template-rows: 0fr; opacity: 0; } /* The next step changes: bring the new one in with a short focus pull. */ @keyframes next-step-in { from { opacity: 0; filter: blur(6px); transform: translateY(8px); } to { opacity: 1; filter: blur(0); transform: none; } } @keyframes next-step-fade { from { opacity: 0; } to { opacity: 1; } } .next-step-enter { animation: next-step-in 480ms var(--ease-out-expo); } :root[data-motion="subtle"] .next-step-enter { animation: next-step-fade 200ms ease-out; } :root[data-motion="subtle"] .today-row, :root[data-motion="subtle"] .honey-check::after { transition-duration: 120ms; transition-delay: 0ms; } @media (prefers-reduced-motion: reduce) { .next-step-enter { animation: next-step-fade 200ms ease-out; } .today-row, .honey-check::after, .honey-check svg { transition-duration: 120ms; transition-delay: 0ms; } }