@ponti-studios/ui 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/index.js +70 -112
  2. package/dist/index.js.map +1 -1
  3. package/package.json +25 -23
  4. package/src/animations.css +92 -15
  5. package/src/components/data-display/accordion.tsx +15 -6
  6. package/src/components/data-display/filter-chip.stories.tsx +38 -0
  7. package/src/components/data-display/filter-chip.tsx +9 -3
  8. package/src/components/data-display/sort-controls.tsx +1 -1
  9. package/src/components/data-display/table.tsx +3 -7
  10. package/src/components/feedback/empty-state.tsx +16 -6
  11. package/src/components/feedback/file-upload-status-badge.tsx +1 -1
  12. package/src/components/feedback/progress.tsx +2 -2
  13. package/src/components/feedback/update-guard.tsx +1 -1
  14. package/src/components/forms/calendar.tsx +6 -3
  15. package/src/components/forms/field.tsx +3 -3
  16. package/src/components/forms/input.tsx +1 -1
  17. package/src/components/forms/passkey-management.tsx +2 -2
  18. package/src/components/forms/radio-group.tsx +1 -1
  19. package/src/components/forms/select.tsx +11 -4
  20. package/src/components/forms/slider.tsx +16 -4
  21. package/src/components/forms/stepper.tsx +1 -1
  22. package/src/components/forms/textarea.tsx +1 -1
  23. package/src/components/layout/section-intro.tsx +1 -1
  24. package/src/components/navigation/app-navigation.tsx +4 -4
  25. package/src/components/navigation/pagination-controls.tsx +2 -2
  26. package/src/components/navigation/tabs.tsx +1 -1
  27. package/src/components/overlays/alert-dialog.tsx +30 -8
  28. package/src/components/overlays/command.tsx +123 -20
  29. package/src/components/overlays/dialog.tsx +4 -4
  30. package/src/components/overlays/dropdown-menu.tsx +137 -21
  31. package/src/components/overlays/popover.tsx +14 -3
  32. package/src/components/overlays/sheet.tsx +24 -8
  33. package/src/components/primitives/avatar.tsx +6 -2
  34. package/src/components/primitives/badge.tsx +5 -2
  35. package/src/components/primitives/button.tsx +16 -18
  36. package/src/components/primitives/card.stories.tsx +2 -2
  37. package/src/components/primitives/card.tsx +2 -5
  38. package/src/constants/chart-colors.ts +2 -2
  39. package/src/styles.css +153 -63
  40. package/src/tokens/chart-colors.stories.tsx +192 -0
  41. package/src/tokens/color-systems.stories.tsx +21 -3
  42. package/src/tokens/foundations.stories.tsx +66 -16
  43. package/src/tokens/generated/dark.colors.generated.ts +23 -50
  44. package/src/tokens/generated/dark.css +23 -48
  45. package/src/tokens/generated/foundations.css +2 -2
  46. package/src/tokens/generated/foundations.generated.ts +14 -6
  47. package/src/tokens/generated/light.colors.generated.ts +23 -50
  48. package/src/tokens/generated/light.css +23 -48
  49. package/src/tokens/index.ts +14 -9
  50. package/src/tokens/layout.stories.tsx +40 -3
@@ -8,10 +8,16 @@ import { cn } from "../../lib/utils";
8
8
 
9
9
  const Sheet = SheetPrimitive.Root;
10
10
 
11
- function SheetTrigger({ asChild, children, ...props }: React.ComponentProps<typeof SheetPrimitive.Trigger> & { asChild?: boolean }) {
11
+ function SheetTrigger({
12
+ asChild,
13
+ children,
14
+ ...props
15
+ }: React.ComponentProps<typeof SheetPrimitive.Trigger> & { asChild?: boolean }) {
12
16
  return (
13
17
  <SheetPrimitive.Trigger
14
- {...(asChild && React.isValidElement(children) ? { render: children as React.ReactElement } : {})}
18
+ {...(asChild && React.isValidElement(children)
19
+ ? { render: children as React.ReactElement }
20
+ : {})}
15
21
  {...props}
16
22
  >
17
23
  {!asChild && children}
@@ -19,10 +25,16 @@ function SheetTrigger({ asChild, children, ...props }: React.ComponentProps<type
19
25
  );
20
26
  }
21
27
 
22
- function SheetClose({ asChild, children, ...props }: React.ComponentProps<typeof SheetPrimitive.Close> & { asChild?: boolean }) {
28
+ function SheetClose({
29
+ asChild,
30
+ children,
31
+ ...props
32
+ }: React.ComponentProps<typeof SheetPrimitive.Close> & { asChild?: boolean }) {
23
33
  return (
24
34
  <SheetPrimitive.Close
25
- {...(asChild && React.isValidElement(children) ? { render: children as React.ReactElement } : {})}
35
+ {...(asChild && React.isValidElement(children)
36
+ ? { render: children as React.ReactElement }
37
+ : {})}
26
38
  {...props}
27
39
  >
28
40
  {!asChild && children}
@@ -38,7 +50,7 @@ const SheetOverlay = React.forwardRef<
38
50
  >(({ className, ...props }, ref) => (
39
51
  <SheetPrimitive.Backdrop
40
52
  className={cn(
41
- "bg-black/80 data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 transition-opacity",
53
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 bg-black/80 transition-opacity",
42
54
  className,
43
55
  )}
44
56
  {...props}
@@ -59,7 +71,7 @@ const SheetContent = React.forwardRef<
59
71
  <SheetPortal>
60
72
  <SheetOverlay />
61
73
  <SheetPrimitive.Popup ref={ref} className={cn(sheetClassName, className)} {...props}>
62
- <SheetPrimitive.Close className="text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-ring absolute top-3 right-3 inline-flex size-11 items-center justify-center rounded-md border border-transparent transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none md:top-4 md:right-4">
74
+ <SheetPrimitive.Close className="text-muted-foreground hover:bg-muted hover:text-muted-foreground focus-visible:outline-ring absolute top-3 right-3 inline-flex size-9 items-center justify-center rounded-md border border-transparent transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none md:top-4 md:right-4">
63
75
  <X className="size-4.5" />
64
76
  <span className="sr-only">Close</span>
65
77
  </SheetPrimitive.Close>
@@ -86,7 +98,11 @@ const SheetTitle = React.forwardRef<
86
98
  React.ComponentRef<typeof SheetPrimitive.Title>,
87
99
  React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
88
100
  >(({ className, ...props }, ref) => (
89
- <SheetPrimitive.Title ref={ref} className={cn("text-lg font-semibold tracking-tight", className)} {...props} />
101
+ <SheetPrimitive.Title
102
+ ref={ref}
103
+ className={cn("text-lg font-semibold tracking-tight", className)}
104
+ {...props}
105
+ />
90
106
  ));
91
107
  SheetTitle.displayName = SheetPrimitive.Title.displayName;
92
108
 
@@ -96,7 +112,7 @@ const SheetDescription = React.forwardRef<
96
112
  >(({ className, ...props }, ref) => (
97
113
  <SheetPrimitive.Description
98
114
  ref={ref}
99
- className={cn("max-w-prose text-sm text-muted-foreground", className)}
115
+ className={cn("text-muted-foreground max-w-prose text-sm", className)}
100
116
  {...props}
101
117
  />
102
118
  ));
@@ -46,7 +46,11 @@ function Avatar({
46
46
  <AvatarContext.Provider value={{ size }}>
47
47
  <AvatarPrimitive.Root
48
48
  data-slot="avatar"
49
- className={cn("relative shrink-0 rounded-full select-none", avatarSize[size], className)}
49
+ className={cn(
50
+ "relative inline-flex shrink-0 rounded-full select-none",
51
+ avatarSize[size],
52
+ className,
53
+ )}
50
54
  {...props}
51
55
  >
52
56
  {children}
@@ -54,7 +58,7 @@ function Avatar({
54
58
  <span
55
59
  data-slot="avatar-badge"
56
60
  className={cn(
57
- "bg-accent ring-background absolute right-0 bottom-0 z-10 rounded-full ring-2",
61
+ "bg-primary ring-background absolute right-0 bottom-0 z-10 rounded-full ring-2",
58
62
  badgeDotSize[size],
59
63
  )}
60
64
  />
@@ -4,16 +4,19 @@ import * as React from "react";
4
4
  import { cn } from "../../lib/utils";
5
5
 
6
6
  const badgeVariants = cva(
7
- "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden whitespace-nowrap rounded border border-transparent px-1.5 py-px text-xs font-medium [&>svg]:size-3 [&>svg]:pointer-events-none aria-invalid:border-destructive aria-invalid:ring-destructive/20",
7
+ "state-settle inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden whitespace-nowrap rounded border border-transparent px-1.5 py-px text-xs font-medium [&>svg]:size-3 [&>svg]:pointer-events-none aria-invalid:border-destructive aria-invalid:ring-destructive/20",
8
8
  {
9
9
  variants: {
10
10
  variant: {
11
11
  default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
12
12
  secondary: "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/80",
13
13
  destructive: "bg-destructive text-destructive-foreground [a&]:hover:bg-destructive/90",
14
- outline: "border-border text-foreground [a&]:hover:bg-accent",
14
+ outline: "border-border text-foreground [a&]:hover:bg-muted",
15
15
  ghost: "[a&]:[a&]: [a&]: [a&]:",
16
16
  link: "text-foreground underline-offset-4 [a&]:hover:underline",
17
+ /** Quiet metadata marker for real reference IDs (case/appointment/feed
18
+ * numbers) — never for decorative sequence markers. */
19
+ ref: "ref-tag border-transparent bg-transparent px-0 py-0 font-normal",
17
20
  },
18
21
  },
19
22
  defaultVariants: {
@@ -6,28 +6,22 @@ import { cn } from "../../lib/utils";
6
6
  import { Spinner } from "../feedback/spinner";
7
7
 
8
8
  const buttonVariants = cva(
9
- "inline-flex min-h-9 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md border border-transparent px-4 py-2 text-sm font-medium transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
9
+ "inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md border border-transparent font-medium transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
10
10
  {
11
11
  variants: {
12
12
  variant: {
13
- default:
14
- "bg-primary text-primary-foreground hover:bg-primary/90",
15
- destructive:
16
- "bg-destructive text-destructive-foreground hover:bg-destructive/90",
17
- outline:
18
- "border-input bg-background hover:bg-accent hover:text-accent-foreground",
19
- secondary:
20
- "border-input bg-secondary text-secondary-foreground hover:bg-secondary/80",
21
- ghost:
22
- "border-transparent bg-transparent hover:bg-accent hover:text-accent-foreground",
13
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
14
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
15
+ outline: "border-input bg-background hover:bg-muted hover:text-muted-foreground",
16
+ secondary: "border-input bg-secondary text-secondary-foreground hover:bg-secondary/80",
17
+ ghost: "border-transparent bg-transparent hover:bg-muted hover:text-muted-foreground",
23
18
  link: "border-transparent bg-transparent px-0 text-primary underline-offset-4 hover:underline",
24
19
  },
25
20
  size: {
26
- sm: "min-h-11 px-2.5 text-sm",
27
- md: "min-h-11 px-3 text-sm",
28
- lg: "min-h-12 px-4 text-base",
29
- default: "",
30
- icon: "size-11 rounded-md p-0",
21
+ sm: "min-h-8 px-2.5 text-xs",
22
+ md: "min-h-9 px-3 text-sm",
23
+ lg: "min-h-10 px-4 text-base",
24
+ icon: "size-9 rounded-md p-0",
31
25
  },
32
26
  },
33
27
  defaultVariants: {
@@ -65,7 +59,9 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
65
59
  const renderedChild = React.cloneElement(child, {
66
60
  children: isLoading ? (
67
61
  <>
68
- <span className="opacity-0" aria-hidden="true">{child.props.children}</span>
62
+ <span className="opacity-0" aria-hidden="true">
63
+ {child.props.children}
64
+ </span>
69
65
  <span className="absolute inset-0 inline-flex items-center justify-center">
70
66
  <Spinner size="sm" aria-hidden="true" />
71
67
  </span>
@@ -105,7 +101,9 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
105
101
  >
106
102
  {isLoading ? (
107
103
  <>
108
- <span className="opacity-0" aria-hidden="true">{children}</span>
104
+ <span className="opacity-0" aria-hidden="true">
105
+ {children}
106
+ </span>
109
107
  <span className="absolute inset-0 inline-flex items-center justify-center">
110
108
  <Spinner size="sm" aria-hidden="true" />
111
109
  </span>
@@ -21,7 +21,7 @@ export const Default: Story = {
21
21
  <CardDescription>A short description of the card's content.</CardDescription>
22
22
  </CardHeader>
23
23
  <CardContent>
24
- <p className="text-sm text-muted-foreground">
24
+ <p className="text-muted-foreground text-sm">
25
25
  Card body content goes here. It can be any React node.
26
26
  </p>
27
27
  </CardContent>
@@ -47,7 +47,7 @@ export const Minimal: Story = {
47
47
  render: () => (
48
48
  <Card className="w-80">
49
49
  <CardContent>
50
- <p className="text-sm text-muted-foreground">Minimal card with only content.</p>
50
+ <p className="text-muted-foreground text-sm">Minimal card with only content.</p>
51
51
  </CardContent>
52
52
  </Card>
53
53
  ),
@@ -6,10 +6,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
6
6
  return (
7
7
  <div
8
8
  data-slot="card"
9
- className={cn(
10
- "bg-card text-card-foreground flex flex-col rounded-xl border",
11
- className,
12
- )}
9
+ className={cn("bg-card text-card-foreground flex flex-col rounded-xl border", className)}
13
10
  {...props}
14
11
  />
15
12
  );
@@ -36,7 +33,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
36
33
  return (
37
34
  <div
38
35
  data-slot="card-description"
39
- className={cn("text-sm text-muted-foreground", className)}
36
+ className={cn("text-muted-foreground text-sm", className)}
40
37
  {...props}
41
38
  />
42
39
  );
@@ -14,14 +14,14 @@ export const CHART_COLORS = {
14
14
  negative: "var(--color-chart-negative)",
15
15
  neutral: "var(--color-chart-neutral)",
16
16
 
17
- background: "var(--color-surface-canvas)",
17
+ background: "var(--color-background)",
18
18
  grid: "var(--color-border)",
19
19
 
20
20
  axis: "var(--color-muted-foreground)",
21
21
  label: "var(--color-muted-foreground)",
22
22
 
23
23
  tooltip: {
24
- background: "var(--color-surface-panel)",
24
+ background: "var(--color-card)",
25
25
  text: "var(--color-foreground)",
26
26
  border: "var(--color-border)",
27
27
  },
package/src/styles.css CHANGED
@@ -4,85 +4,175 @@
4
4
  @import "./tokens/generated/dark.css" (prefers-color-scheme: dark);
5
5
  @import "./animations.css";
6
6
 
7
- /* Keep generated token names isolated from Tailwind's standard role names. */
8
- :root {
9
- --ponti-primary: var(--color-accent);
10
- --ponti-primary-foreground: var(--color-text-on-accent);
11
- --ponti-destructive: var(--color-destructive);
12
- --ponti-destructive-foreground: var(--color-text-on-destructive);
13
- --ponti-foreground: var(--color-text-primary);
14
- --ponti-muted-foreground: var(--color-text-secondary);
15
- --ponti-border: var(--color-border-default);
16
- --ponti-ring: var(--color-ring-focus);
17
- }
18
-
19
7
  /* shadcn New York semantic contract. Values are generated from the DTCG
20
8
  * source; this file only names the roles consumed by web components. */
21
9
  @theme inline {
22
- --color-background: var(--color-surface-canvas);
23
- --color-foreground: var(--ponti-foreground);
24
- --color-card: var(--color-surface-panel);
25
- --color-card-foreground: var(--color-text-primary);
26
- --color-popover: var(--color-surface-raised);
27
- --color-popover-foreground: var(--color-text-primary);
28
- --color-primary: var(--ponti-primary);
29
- --color-primary-foreground: var(--ponti-primary-foreground);
30
- --color-secondary: var(--color-surface-panel);
31
- --color-secondary-foreground: var(--color-text-primary);
32
- --color-muted: var(--color-surface-inset);
33
- --color-muted-foreground: var(--ponti-muted-foreground);
34
- --color-accent-foreground: var(--color-text-primary);
35
- --color-destructive-foreground: var(--ponti-destructive-foreground);
36
- --color-border: var(--ponti-border);
37
- --color-input: var(--ponti-border);
38
- --color-ring: var(--ponti-ring);
39
- --color-chart-1: var(--color-border-focus);
40
- --color-chart-2: var(--color-chart-positive);
41
- --color-chart-3: var(--color-border-focus);
42
- --color-chart-4: var(--color-text-warning);
43
- --color-chart-5: var(--color-border-strong);
10
+ --color-background: var(--background);
11
+ --color-foreground: var(--text-primary);
12
+ --color-card: var(--card);
13
+ --color-card-foreground: var(--text-primary);
14
+ --color-popover: var(--popover);
15
+ --color-popover-foreground: var(--text-primary);
16
+ --color-primary: var(--primary);
17
+ --color-primary-foreground: var(--primary-foreground);
18
+ --color-secondary: var(--card);
19
+ --color-secondary-foreground: var(--text-primary);
20
+ --color-muted: var(--muted);
21
+ --color-muted-foreground: var(--text-secondary);
22
+ --color-accent: var(--primary);
23
+ --color-accent-foreground: var(--primary-foreground);
24
+ --color-destructive: var(--destructive);
25
+ --color-destructive-foreground: var(--destructive-foreground);
26
+ --color-success: var(--success);
27
+ --color-warning: var(--warning);
28
+ --color-border: var(--border-default);
29
+ --color-input: var(--border-default);
30
+ --color-ring: var(--focus-ring);
44
31
  }
45
32
 
46
- @utility pb-safe-area-inset-bottom { padding-bottom: env(safe-area-inset-bottom); }
47
- @utility mb-safe-area-inset-bottom { margin-bottom: env(safe-area-inset-bottom); }
48
- @utility min-h-screen { min-height: 100vh; min-height: 100dvh; }
49
- @utility min-h-screen-dynamic { min-height: 100dvh; }
50
- @utility h-screen { height: 100vh; height: 100dvh; }
33
+ @utility display-1 {
34
+ font-size: clamp(2.5rem, 5vw, 6rem);
35
+ font-family: var(--font-sans);
36
+ font-weight: var(--font-weight-semibold);
37
+ line-height: 1.1;
38
+ letter-spacing: var(--tracking-tight);
39
+ }
40
+ @utility display-2 {
41
+ font-size: clamp(2rem, 3vw, 3.5rem);
42
+ font-family: var(--font-sans);
43
+ font-weight: var(--font-weight-semibold);
44
+ line-height: 1.15;
45
+ letter-spacing: var(--tracking-tight);
46
+ }
47
+ @utility ref-tag {
48
+ font-family: var(--font-mono);
49
+ font-size: var(--text-xs);
50
+ color: var(--tertiary);
51
+ letter-spacing: var(--tracking-wide);
52
+ }
53
+ /* Quiet state-change "settle" — used on state-bearing indicators
54
+ * (Badge, StatusBadge, FilterChip) when their represented value changes. */
55
+ @utility state-settle {
56
+ transition:
57
+ transform 120ms ease-out,
58
+ opacity 120ms ease-out;
59
+ }
60
+ @utility pb-safe-area-inset-bottom {
61
+ padding-bottom: env(safe-area-inset-bottom);
62
+ }
63
+ @utility mb-safe-area-inset-bottom {
64
+ margin-bottom: env(safe-area-inset-bottom);
65
+ }
66
+ @utility min-h-screen {
67
+ min-height: 100vh;
68
+ min-height: 100dvh;
69
+ }
70
+ @utility min-h-screen-dynamic {
71
+ min-height: 100dvh;
72
+ }
73
+ @utility h-screen {
74
+ height: 100vh;
75
+ height: 100dvh;
76
+ }
51
77
 
52
78
  /* Shared layout rhythm. Product components own their layout; this does not
53
79
  * define visual component families. */
54
- .page-shell { @apply relative mx-auto flex w-full flex-col gap-12 px-4 py-16 md:gap-16 md:px-6 md:py-20; }
55
- .page-shell-detail { @apply relative mx-auto flex w-full flex-col gap-10 px-4 py-16 md:gap-12 md:px-6 md:py-20; }
56
- .page-bleed { @apply flex w-full flex-col; }
57
- .layout-stack { @apply flex flex-col gap-4; }
58
- .list-row { @apply flex gap-4 px-0 py-6 md:gap-6 md:py-8; }
59
- .list-media { @apply relative isolate flex shrink-0 items-center justify-center overflow-hidden rounded-md border border-border bg-card p-2 shadow-none; }
60
- .list-media-wide { @apply h-14 w-32; }
61
- .list-media-square { @apply size-10 sm:size-12; }
62
- .list-media-placeholder { @apply pointer-events-none absolute inset-0 flex items-center justify-center gap-1.5 transition-opacity duration-150; }
63
- .section { @apply flex flex-col gap-4 border-b border-border px-4 py-12 md:px-6 md:py-16; }
64
- .section-hero { @apply gap-6 py-16 md:py-20; }
65
- .detail-hero { @apply gap-4 py-10 md:gap-6 md:py-16; }
66
- .section-compact { @apply gap-4 py-8 md:py-12; }
67
- .detail-navigation { @apply flex flex-col gap-6 sm:flex-row sm:justify-between; }
68
- .detail-navigation-link { @apply flex min-h-11 flex-col justify-center gap-1; }
80
+ .page-shell {
81
+ @apply relative mx-auto flex w-full flex-col gap-12 px-4 py-16 md:gap-16 md:px-6 md:py-20;
82
+ }
83
+ .page-shell-detail {
84
+ @apply relative mx-auto flex w-full flex-col gap-10 px-4 py-16 md:gap-12 md:px-6 md:py-20;
85
+ }
86
+ .page-bleed {
87
+ @apply flex w-full flex-col;
88
+ }
89
+ .layout-stack {
90
+ @apply flex flex-col gap-4;
91
+ }
92
+ .list-row {
93
+ @apply flex gap-4 px-0 py-6 md:gap-6 md:py-8;
94
+ }
95
+ .list-media {
96
+ @apply border-border bg-card relative isolate flex shrink-0 items-center justify-center overflow-hidden rounded-md border p-2 shadow-none;
97
+ }
98
+ .list-media-wide {
99
+ @apply h-14 w-32;
100
+ }
101
+ .list-media-square {
102
+ @apply size-10 sm:size-12;
103
+ }
104
+ .list-media-placeholder {
105
+ @apply pointer-events-none absolute inset-0 flex items-center justify-center gap-1.5 transition-opacity duration-150;
106
+ }
107
+ .section {
108
+ @apply border-border flex flex-col gap-4 border-b px-4 py-12 md:px-6 md:py-16;
109
+ }
110
+ .section-hero {
111
+ @apply gap-6 py-16 md:py-20;
112
+ }
113
+ .detail-hero {
114
+ @apply gap-4 py-10 md:gap-6 md:py-16;
115
+ }
116
+ .section-compact {
117
+ @apply gap-4 py-8 md:py-12;
118
+ }
119
+ .detail-navigation {
120
+ @apply flex flex-col gap-6 sm:flex-row sm:justify-between;
121
+ }
122
+ .detail-navigation-link {
123
+ @apply flex min-h-9 flex-col justify-center gap-1;
124
+ }
69
125
 
70
126
  @layer base {
71
- :root { color-scheme: light; }
72
- @media (prefers-color-scheme: dark) { :root { color-scheme: dark; } }
73
- html, body {
127
+ :root {
128
+ color-scheme: light;
129
+ }
130
+ @media (prefers-color-scheme: dark) {
131
+ :root {
132
+ color-scheme: dark;
133
+ }
134
+ }
135
+ html,
136
+ body {
74
137
  background-color: var(--color-background);
75
138
  color: var(--color-foreground);
76
139
  font-family: var(--font-sans);
77
140
  -webkit-font-smoothing: antialiased;
78
141
  -moz-osx-font-smoothing: grayscale;
79
142
  }
80
- * { border-color: var(--color-border, currentColor); }
81
- *:focus { outline: none; }
82
- *:focus-visible { outline: 2px solid var(--color-ring); outline-offset: 2px; border-radius: inherit; }
83
- button { cursor: pointer; font-family: inherit; }
84
- h1, h2, h3, h4, h5, h6 { font-family: var(--font-sans); font-weight: 600; letter-spacing: var(--tracking-tight); }
143
+ * {
144
+ border-color: var(--color-border, currentColor);
145
+ }
146
+ *:focus {
147
+ outline: none;
148
+ }
149
+ *:focus-visible {
150
+ outline: 2px solid var(--color-ring);
151
+ outline-offset: 2px;
152
+ border-radius: inherit;
153
+ }
154
+ button {
155
+ cursor: pointer;
156
+ font-family: inherit;
157
+ }
158
+ h1,
159
+ h2,
160
+ h3,
161
+ h4,
162
+ h5,
163
+ h6 {
164
+ font-family: var(--font-sans);
165
+ font-weight: 600;
166
+ letter-spacing: var(--tracking-tight);
167
+ }
85
168
  @media (prefers-reduced-motion: reduce) {
86
- *, ::before, ::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
169
+ *,
170
+ ::before,
171
+ ::after {
172
+ animation-duration: 0.01ms !important;
173
+ animation-iteration-count: 1 !important;
174
+ transition-duration: 0.01ms !important;
175
+ scroll-behavior: auto !important;
176
+ }
87
177
  }
88
178
  }