@abuzareal/contour-ui 0.1.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 (179) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/LICENSE +21 -0
  3. package/README.md +111 -0
  4. package/RELEASING.md +37 -0
  5. package/SECURITY.md +11 -0
  6. package/dist/components/hero/SceneBoundary.d.ts +14 -0
  7. package/dist/components/hero/SceneBoundary.js +11 -0
  8. package/dist/components/hero/Sculpture.d.ts +4 -0
  9. package/dist/components/hero/Sculpture.js +54 -0
  10. package/dist/components/three/ObjectStudy.d.ts +7 -0
  11. package/dist/components/three/ObjectStudy.js +65 -0
  12. package/dist/components/ui/Alert.d.ts +13 -0
  13. package/dist/components/ui/Alert.js +15 -0
  14. package/dist/components/ui/Avatar.d.ts +7 -0
  15. package/dist/components/ui/Avatar.js +12 -0
  16. package/dist/components/ui/Badge.d.ts +11 -0
  17. package/dist/components/ui/Badge.js +5 -0
  18. package/dist/components/ui/BrandMark.d.ts +7 -0
  19. package/dist/components/ui/BrandMark.js +5 -0
  20. package/dist/components/ui/Breadcrumbs.d.ts +10 -0
  21. package/dist/components/ui/Breadcrumbs.js +8 -0
  22. package/dist/components/ui/Button.d.ts +12 -0
  23. package/dist/components/ui/Button.js +6 -0
  24. package/dist/components/ui/Card.d.ts +13 -0
  25. package/dist/components/ui/Card.js +5 -0
  26. package/dist/components/ui/Checkbox.d.ts +9 -0
  27. package/dist/components/ui/Checkbox.js +14 -0
  28. package/dist/components/ui/CountUp.d.ts +9 -0
  29. package/dist/components/ui/CountUp.js +48 -0
  30. package/dist/components/ui/DataTable.d.ts +16 -0
  31. package/dist/components/ui/DataTable.js +24 -0
  32. package/dist/components/ui/DepthButton.d.ts +6 -0
  33. package/dist/components/ui/DepthButton.js +4 -0
  34. package/dist/components/ui/Dialog.d.ts +12 -0
  35. package/dist/components/ui/Dialog.js +27 -0
  36. package/dist/components/ui/Disclosure.d.ts +11 -0
  37. package/dist/components/ui/Disclosure.js +5 -0
  38. package/dist/components/ui/Divider.d.ts +5 -0
  39. package/dist/components/ui/Divider.js +6 -0
  40. package/dist/components/ui/DropdownMenu.d.ts +14 -0
  41. package/dist/components/ui/DropdownMenu.js +38 -0
  42. package/dist/components/ui/EmptyState.d.ts +9 -0
  43. package/dist/components/ui/EmptyState.js +4 -0
  44. package/dist/components/ui/ExternalLink.d.ts +4 -0
  45. package/dist/components/ui/ExternalLink.js +5 -0
  46. package/dist/components/ui/Field.d.ts +15 -0
  47. package/dist/components/ui/Field.js +6 -0
  48. package/dist/components/ui/FlipCard.d.ts +8 -0
  49. package/dist/components/ui/FlipCard.js +9 -0
  50. package/dist/components/ui/IconButton.d.ts +11 -0
  51. package/dist/components/ui/IconButton.js +5 -0
  52. package/dist/components/ui/Kbd.d.ts +5 -0
  53. package/dist/components/ui/Kbd.js +4 -0
  54. package/dist/components/ui/Magnetic.d.ts +8 -0
  55. package/dist/components/ui/Magnetic.js +19 -0
  56. package/dist/components/ui/Marquee.d.ts +7 -0
  57. package/dist/components/ui/Marquee.js +7 -0
  58. package/dist/components/ui/Pagination.d.ts +7 -0
  59. package/dist/components/ui/Pagination.js +15 -0
  60. package/dist/components/ui/Popover.d.ts +10 -0
  61. package/dist/components/ui/Popover.js +18 -0
  62. package/dist/components/ui/ProgressBar.d.ts +7 -0
  63. package/dist/components/ui/ProgressBar.js +6 -0
  64. package/dist/components/ui/RadioGroup.d.ts +14 -0
  65. package/dist/components/ui/RadioGroup.js +11 -0
  66. package/dist/components/ui/Reveal.d.ts +9 -0
  67. package/dist/components/ui/Reveal.js +24 -0
  68. package/dist/components/ui/RevealHeading.d.ts +12 -0
  69. package/dist/components/ui/RevealHeading.js +4 -0
  70. package/dist/components/ui/ScrollProgress.d.ts +1 -0
  71. package/dist/components/ui/ScrollProgress.js +27 -0
  72. package/dist/components/ui/SectionLabel.d.ts +8 -0
  73. package/dist/components/ui/SectionLabel.js +5 -0
  74. package/dist/components/ui/SegmentedControl.d.ts +10 -0
  75. package/dist/components/ui/SegmentedControl.js +20 -0
  76. package/dist/components/ui/SelectField.d.ts +13 -0
  77. package/dist/components/ui/SelectField.js +10 -0
  78. package/dist/components/ui/Skeleton.d.ts +6 -0
  79. package/dist/components/ui/Skeleton.js +5 -0
  80. package/dist/components/ui/Slider.d.ts +12 -0
  81. package/dist/components/ui/Slider.js +10 -0
  82. package/dist/components/ui/SocialIcons.d.ts +6 -0
  83. package/dist/components/ui/SocialIcons.js +7 -0
  84. package/dist/components/ui/Spinner.d.ts +6 -0
  85. package/dist/components/ui/Spinner.js +8 -0
  86. package/dist/components/ui/Stat.d.ts +8 -0
  87. package/dist/components/ui/Stat.js +4 -0
  88. package/dist/components/ui/Stepper.d.ts +10 -0
  89. package/dist/components/ui/Stepper.js +15 -0
  90. package/dist/components/ui/Switch.d.ts +8 -0
  91. package/dist/components/ui/Switch.js +7 -0
  92. package/dist/components/ui/Tabs.d.ts +13 -0
  93. package/dist/components/ui/Tabs.js +41 -0
  94. package/dist/components/ui/Tag.d.ts +5 -0
  95. package/dist/components/ui/Tag.js +8 -0
  96. package/dist/components/ui/TextArea.d.ts +10 -0
  97. package/dist/components/ui/TextArea.js +23 -0
  98. package/dist/components/ui/TextField.d.ts +12 -0
  99. package/dist/components/ui/TextField.js +13 -0
  100. package/dist/components/ui/ThemeToggle.d.ts +5 -0
  101. package/dist/components/ui/ThemeToggle.js +9 -0
  102. package/dist/components/ui/TiltCard.d.ts +8 -0
  103. package/dist/components/ui/TiltCard.js +23 -0
  104. package/dist/components/ui/Timeline.d.ts +9 -0
  105. package/dist/components/ui/Timeline.js +6 -0
  106. package/dist/components/ui/ToastProvider.d.ts +5 -0
  107. package/dist/components/ui/ToastProvider.js +29 -0
  108. package/dist/components/ui/Tooltip.d.ts +11 -0
  109. package/dist/components/ui/Tooltip.js +16 -0
  110. package/dist/fonts.css +3 -0
  111. package/dist/hooks/useClipboardCopy.d.ts +5 -0
  112. package/dist/hooks/useClipboardCopy.js +21 -0
  113. package/dist/hooks/useDismiss.d.ts +3 -0
  114. package/dist/hooks/useDismiss.js +22 -0
  115. package/dist/hooks/useHeaderScroll.d.ts +7 -0
  116. package/dist/hooks/useHeaderScroll.js +40 -0
  117. package/dist/hooks/useIdleTrigger.d.ts +1 -0
  118. package/dist/hooks/useIdleTrigger.js +19 -0
  119. package/dist/hooks/useInitialHashScroll.d.ts +1 -0
  120. package/dist/hooks/useInitialHashScroll.js +28 -0
  121. package/dist/hooks/useMobileMenu.d.ts +3 -0
  122. package/dist/hooks/useMobileMenu.js +34 -0
  123. package/dist/hooks/useMotionPreference.d.ts +1 -0
  124. package/dist/hooks/useMotionPreference.js +13 -0
  125. package/dist/hooks/usePrintPreparation.d.ts +1 -0
  126. package/dist/hooks/usePrintPreparation.js +29 -0
  127. package/dist/hooks/useScrollSpy.d.ts +1 -0
  128. package/dist/hooks/useScrollSpy.js +36 -0
  129. package/dist/hooks/useSmoothScroll.d.ts +1 -0
  130. package/dist/hooks/useSmoothScroll.js +18 -0
  131. package/dist/hooks/useTheme.d.ts +5 -0
  132. package/dist/hooks/useTheme.js +98 -0
  133. package/dist/hooks/useThreeStage.d.ts +28 -0
  134. package/dist/hooks/useThreeStage.js +155 -0
  135. package/dist/hooks/useToast.d.ts +11 -0
  136. package/dist/hooks/useToast.js +9 -0
  137. package/dist/index.d.ts +129 -0
  138. package/dist/index.js +68 -0
  139. package/dist/kit/actions.css +209 -0
  140. package/dist/kit/data-display.css +496 -0
  141. package/dist/kit/effects.css +144 -0
  142. package/dist/kit/feedback.css +316 -0
  143. package/dist/kit/forms.css +363 -0
  144. package/dist/kit/index.css +9 -0
  145. package/dist/kit/navigation.css +262 -0
  146. package/dist/kit/overlays.css +299 -0
  147. package/dist/lib/a11y.d.ts +3 -0
  148. package/dist/lib/a11y.js +3 -0
  149. package/dist/lib/classNames.d.ts +6 -0
  150. package/dist/lib/classNames.js +4 -0
  151. package/dist/lib/format.d.ts +3 -0
  152. package/dist/lib/format.js +3 -0
  153. package/dist/lib/keyboard.d.ts +8 -0
  154. package/dist/lib/keyboard.js +22 -0
  155. package/dist/lib/motion.d.ts +3 -0
  156. package/dist/lib/motion.js +4 -0
  157. package/dist/lib/safeHref.d.ts +2 -0
  158. package/dist/lib/safeHref.js +14 -0
  159. package/dist/lib/storage.d.ts +10 -0
  160. package/dist/lib/storage.js +25 -0
  161. package/dist/lib/themeBootstrap.d.ts +6 -0
  162. package/dist/lib/themeBootstrap.js +19 -0
  163. package/dist/lib/threeMaterials.d.ts +9 -0
  164. package/dist/lib/threeMaterials.js +62 -0
  165. package/dist/lib/threeStudies.d.ts +16 -0
  166. package/dist/lib/threeStudies.js +39 -0
  167. package/dist/motion.css +59 -0
  168. package/dist/reset.css +180 -0
  169. package/dist/scroll.d.ts +1 -0
  170. package/dist/scroll.js +1 -0
  171. package/dist/styles.css +23 -0
  172. package/dist/theme-toggle.css +38 -0
  173. package/dist/three.d.ts +8 -0
  174. package/dist/three.js +5 -0
  175. package/dist/tokens.css +127 -0
  176. package/dist/types.d.ts +6 -0
  177. package/dist/types.js +1 -0
  178. package/dist/ui.css +178 -0
  179. package/package.json +101 -0
package/dist/reset.css ADDED
@@ -0,0 +1,180 @@
1
+ /* Minimal reset, element defaults, and global layout utilities. */
2
+
3
+ *,
4
+ ::before,
5
+ ::after {
6
+ box-sizing: border-box;
7
+ border: 0 solid;
8
+ letter-spacing: 0;
9
+ }
10
+
11
+ html {
12
+ line-height: 1.5;
13
+ -webkit-text-size-adjust: 100%;
14
+ tab-size: 4;
15
+ }
16
+
17
+ :root {
18
+ font-family: var(--font-sans);
19
+ color: var(--fg);
20
+ background: var(--bg);
21
+ font-synthesis: none;
22
+ text-rendering: optimizeLegibility;
23
+ -webkit-font-smoothing: antialiased;
24
+ }
25
+
26
+ body {
27
+ margin: 0;
28
+ min-width: 320px;
29
+ line-height: inherit;
30
+ }
31
+
32
+ h1,
33
+ h2,
34
+ h3,
35
+ p,
36
+ dl,
37
+ dd,
38
+ figure {
39
+ margin: 0;
40
+ }
41
+
42
+ h1,
43
+ h2,
44
+ h3 {
45
+ font-family: var(--font-display);
46
+ font-size: inherit;
47
+ font-weight: 500;
48
+ }
49
+
50
+ ul,
51
+ ol {
52
+ list-style: none;
53
+ margin: 0;
54
+ padding: 0;
55
+ }
56
+
57
+ img,
58
+ svg,
59
+ canvas {
60
+ display: block;
61
+ vertical-align: middle;
62
+ }
63
+
64
+ img {
65
+ max-width: 100%;
66
+ height: auto;
67
+ }
68
+
69
+ svg {
70
+ flex-shrink: 0;
71
+ }
72
+
73
+ summary {
74
+ display: list-item;
75
+ }
76
+
77
+ [hidden]:where(:not([hidden="until-found"])) {
78
+ display: none;
79
+ }
80
+
81
+ a {
82
+ color: inherit;
83
+ text-decoration: none;
84
+ }
85
+
86
+ button {
87
+ font: inherit;
88
+ color: inherit;
89
+ margin: 0;
90
+ padding: 0;
91
+ background: transparent;
92
+ text-transform: none;
93
+ cursor: pointer;
94
+ }
95
+
96
+ button:disabled {
97
+ cursor: default;
98
+ }
99
+
100
+ button,
101
+ a {
102
+ -webkit-tap-highlight-color: transparent;
103
+ }
104
+
105
+ button:focus-visible,
106
+ a:focus-visible,
107
+ summary:focus-visible {
108
+ outline: 2px solid currentColor;
109
+ outline-offset: 6px;
110
+ }
111
+
112
+ ::selection {
113
+ background: var(--acid);
114
+ color: var(--ink);
115
+ }
116
+
117
+ /* Anchor targets land flush below the fixed header. */
118
+ section {
119
+ scroll-margin-top: 78px;
120
+ }
121
+
122
+ .site-shell {
123
+ overflow: clip;
124
+ }
125
+
126
+ .page-width {
127
+ width: calc(100% - 112px);
128
+ max-width: 1680px;
129
+ margin-inline: auto;
130
+ }
131
+
132
+ .mono {
133
+ font-family: var(--font-mono);
134
+ font-size: 11px;
135
+ line-height: 1.6;
136
+ }
137
+
138
+ .skip-link {
139
+ position: fixed;
140
+ z-index: 100;
141
+ top: 12px;
142
+ left: 12px;
143
+ padding: 14px 24px;
144
+ background: var(--acid);
145
+ color: var(--ink);
146
+ transform: translateY(-150%);
147
+ }
148
+
149
+ .skip-link:focus {
150
+ transform: translateY(0);
151
+ }
152
+
153
+ /* Hidden visually but still announced by screen readers. */
154
+ .visually-hidden {
155
+ position: absolute;
156
+ width: 1px;
157
+ height: 1px;
158
+ margin: -1px;
159
+ padding: 0;
160
+ overflow: hidden;
161
+ clip-path: inset(50%);
162
+ white-space: nowrap;
163
+ border: 0;
164
+ }
165
+
166
+ @media (max-width: 1023px) {
167
+ .page-width {
168
+ width: calc(100% - 64px);
169
+ }
170
+ }
171
+
172
+ @media (max-width: 767px) {
173
+ section {
174
+ scroll-margin-top: 70px;
175
+ }
176
+
177
+ .page-width {
178
+ width: calc(100% - 40px);
179
+ }
180
+ }
@@ -0,0 +1 @@
1
+ export { default as useSmoothScroll } from "./hooks/useSmoothScroll.js";
package/dist/scroll.js ADDED
@@ -0,0 +1 @@
1
+ export { default as useSmoothScroll } from "./hooks/useSmoothScroll.js";
@@ -0,0 +1,23 @@
1
+ @import "./tokens.css";
2
+ @import "./ui.css";
3
+ @import "./kit/index.css";
4
+ @import "./theme-toggle.css";
5
+ @import "./motion.css";
6
+
7
+ /* Shared accessibility and typography utilities also work with an application-owned reset. */
8
+ .mono {
9
+ font-family: var(--font-mono);
10
+ font-size: var(--text-label);
11
+ line-height: 1.6;
12
+ }
13
+ .visually-hidden {
14
+ position: absolute;
15
+ width: 1px;
16
+ height: 1px;
17
+ margin: -1px;
18
+ padding: 0;
19
+ overflow: hidden;
20
+ clip-path: inset(50%);
21
+ white-space: nowrap;
22
+ border: 0;
23
+ }
@@ -0,0 +1,38 @@
1
+ .theme-toggle {
2
+ display: grid;
3
+ place-items: center;
4
+ width: 38px;
5
+ height: 38px;
6
+ border: 1px solid color-mix(in srgb, currentColor 28%, transparent);
7
+ border-radius: 50%;
8
+ overflow: hidden;
9
+ transition:
10
+ background 250ms,
11
+ color 250ms,
12
+ border-color 250ms;
13
+ }
14
+
15
+ .theme-toggle:hover {
16
+ background: var(--acid);
17
+ border-color: var(--acid);
18
+ color: var(--ink);
19
+ }
20
+
21
+ .theme-toggle svg {
22
+ grid-area: 1 / 1;
23
+ transition:
24
+ transform 700ms var(--ease),
25
+ opacity 400ms ease;
26
+ }
27
+
28
+ /* The icon for the theme you can switch to is shown; the other spins away. */
29
+ .theme-icon-sun,
30
+ :root[data-theme="dark"] .theme-icon-moon {
31
+ opacity: 0;
32
+ transform: rotate(-120deg) scale(0.3);
33
+ }
34
+
35
+ :root[data-theme="dark"] .theme-icon-sun {
36
+ opacity: 1;
37
+ transform: none;
38
+ }
@@ -0,0 +1,8 @@
1
+ export { default as Sculpture } from "./components/hero/Sculpture.js";
2
+ export { default as ObjectStudy } from "./components/three/ObjectStudy.js";
3
+ export { default as useThreeStage } from "./hooks/useThreeStage.js";
4
+ export type * from "./hooks/useThreeStage.js";
5
+ export type * from "./components/hero/Sculpture.js";
6
+ export type * from "./components/three/ObjectStudy.js";
7
+ export * from "./lib/threeMaterials.js";
8
+ export * from "./lib/threeStudies.js";
package/dist/three.js ADDED
@@ -0,0 +1,5 @@
1
+ export { default as Sculpture } from "./components/hero/Sculpture.js";
2
+ export { default as ObjectStudy } from "./components/three/ObjectStudy.js";
3
+ export { default as useThreeStage } from "./hooks/useThreeStage.js";
4
+ export * from "./lib/threeMaterials.js";
5
+ export * from "./lib/threeStudies.js";
@@ -0,0 +1,127 @@
1
+ /* Design tokens: palette, typography, and per-theme surface colours (light default, dark override). */
2
+
3
+ :root {
4
+ /* Brand constants (identical in both themes). */
5
+ --ink: #171817;
6
+ --paper: #f2f3ee;
7
+ --white: #fcfcf9;
8
+ --acid: #d0f344;
9
+ --ease: cubic-bezier(0.22, 1, 0.36, 1);
10
+ --font-sans: "DM Sans Variable", "DM Sans", system-ui, sans-serif;
11
+ --font-display:
12
+ "Space Grotesk Variable", "Space Grotesk", system-ui, sans-serif;
13
+ --font-mono: "DM Mono", ui-monospace, monospace;
14
+
15
+ /* Shape and motion scales shared by every component. */
16
+ --radius-sm: 4px;
17
+ --radius-md: 8px;
18
+ --radius-pill: 999px;
19
+ --duration-fast: 160ms;
20
+ --duration-base: 300ms;
21
+ --duration-slow: 700ms;
22
+
23
+ /* Light theme: warm paper surfaces, olive-ink text, acid as the one accent. */
24
+ --bg: var(--paper);
25
+ --fg: var(--ink);
26
+ --muted: #63665f;
27
+ --line: #d6d8d0;
28
+ --line-strong: #b4b8ac;
29
+ --surface: #fbfbf8;
30
+ --surface-sunken: #e8e9e1;
31
+ --overlay: #171817b8;
32
+ --shadow-raised: 0 1px 2px #1718170d, 0 10px 28px #17181712;
33
+ --shadow-floating: 0 24px 56px #1718172e;
34
+ --olive: #75901a;
35
+ --signal: #4d7522;
36
+ --success: #3f6119;
37
+ --success-soft: #e4ecc9;
38
+ --info: #2f6a82;
39
+ --info-soft: #dbe8ec;
40
+ --warning: #7a5100;
41
+ --warning-soft: #f5e6c3;
42
+ --danger: #a8321c;
43
+ --danger-soft: #f7dcd3;
44
+ --invert-bg: var(--ink);
45
+ --invert-fg: var(--paper);
46
+ --header-bg: #f2f3eeef;
47
+ --header-bg-scrolled: #f2f3eee8;
48
+ --header-fg: var(--ink);
49
+ --header-link: #53574e;
50
+ --header-line: var(--line);
51
+ --header-dot: #75901a;
52
+ --header-underline: currentColor;
53
+ --menu-shadow: #00000012;
54
+ --focus-band-bg: var(--ink);
55
+ --focus-band-fg: var(--paper);
56
+ --focus-band-line: #353733;
57
+ --focus-band-icon: var(--acid);
58
+ --about-bg: #e4e5dc;
59
+ --experience-bg: var(--white);
60
+ --expertise-bg: #e7eacb;
61
+ --work-bg: var(--ink);
62
+ --footer-bg: var(--ink);
63
+
64
+ color-scheme: light;
65
+ }
66
+
67
+ :root[data-theme="dark"] {
68
+ /* Dark theme: tinted near-blacks stepped by elevation, off-white text. */
69
+ --bg: #0f100d;
70
+ --fg: #eef0e6;
71
+ --muted: #9a9e90;
72
+ --line: #2a2d24;
73
+ --line-strong: #444939;
74
+ --surface: #171913;
75
+ --surface-sunken: #0a0b09;
76
+ --overlay: #050605cc;
77
+ --shadow-raised: 0 1px 2px #0000004d, 0 10px 28px #00000059;
78
+ --shadow-floating: 0 24px 56px #00000099;
79
+ --olive: #c2e042;
80
+ --signal: var(--acid);
81
+ --success: #b5d33f;
82
+ --success-soft: #222914;
83
+ --info: #8fc0d6;
84
+ --info-soft: #152227;
85
+ --warning: #f0c063;
86
+ --warning-soft: #2b2311;
87
+ --danger: #ff8a70;
88
+ --danger-soft: #2f1914;
89
+ --invert-bg: var(--paper);
90
+ --invert-fg: var(--ink);
91
+ --header-bg: #0f100deb;
92
+ --header-bg-scrolled: #0f100de0;
93
+ --header-fg: #eef0e6;
94
+ --header-link: #b4b8aa;
95
+ --header-line: #2a2d24;
96
+ --header-dot: var(--acid);
97
+ --header-underline: var(--acid);
98
+ --menu-shadow: #00000066;
99
+ --focus-band-bg: var(--paper);
100
+ --focus-band-fg: var(--ink);
101
+ --focus-band-line: #d6d8d0;
102
+ --focus-band-icon: #6b8412;
103
+ --about-bg: #1b1e16;
104
+ --experience-bg: #131511;
105
+ --expertise-bg: #21251a;
106
+ --work-bg: #080907;
107
+ --footer-bg: #080907;
108
+
109
+ color-scheme: dark;
110
+ }
111
+
112
+ :root {
113
+ --space-4: 4px;
114
+ --space-8: 8px;
115
+ --space-12: 12px;
116
+ --space-16: 16px;
117
+ --space-24: 24px;
118
+ --space-32: 32px;
119
+ --space-48: 48px;
120
+ --space-64: 64px;
121
+ --space-104: 104px;
122
+ --text-body: 15px;
123
+ --text-small: 13px;
124
+ --text-label: 11px;
125
+ --text-lead: 24px;
126
+ --text-display: clamp(48px, 8vw, 116px);
127
+ }
@@ -0,0 +1,6 @@
1
+ export type Section = {
2
+ id: string;
3
+ label: string;
4
+ title: string;
5
+ number: number;
6
+ };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/ui.css ADDED
@@ -0,0 +1,178 @@
1
+ /* Shared UI patterns: brand mark, section scaffolding, links, disclosures, and reveal animations. */
2
+
3
+ .brand {
4
+ font-family: var(--font-display);
5
+ font-size: 34px;
6
+ line-height: 1;
7
+ font-weight: 700;
8
+ }
9
+
10
+ .brand > span {
11
+ color: var(--olive);
12
+ }
13
+
14
+ .section-space {
15
+ padding-block: 104px;
16
+ }
17
+
18
+ .section-label {
19
+ display: flex;
20
+ justify-content: space-between;
21
+ gap: 24px;
22
+ text-transform: uppercase;
23
+ padding-bottom: 24px;
24
+ border-bottom: 1px solid var(--line);
25
+ }
26
+
27
+ .text-link {
28
+ width: fit-content;
29
+ display: flex;
30
+ align-items: center;
31
+ gap: 18px;
32
+ font-size: 12px;
33
+ border-bottom: 1px solid currentColor;
34
+ padding-block: 8px;
35
+ transition: gap 300ms var(--ease);
36
+ }
37
+
38
+ .text-link:hover {
39
+ gap: 26px;
40
+ }
41
+
42
+ /* Disclosure: native details/summary with a plus icon that rotates into a cross. */
43
+ .disclosure > summary {
44
+ list-style: none;
45
+ cursor: pointer;
46
+ }
47
+
48
+ .disclosure > summary::-webkit-details-marker {
49
+ display: none;
50
+ }
51
+
52
+ .disclosure-icon {
53
+ transition: transform 300ms;
54
+ }
55
+
56
+ .disclosure[open] .disclosure-icon {
57
+ transform: rotate(45deg);
58
+ }
59
+
60
+ /* Two-column intro + content layout used by Experience and Expertise. */
61
+ .split-layout {
62
+ display: grid;
63
+ grid-template-columns: 0.8fr 1.2fr;
64
+ gap: 90px;
65
+ padding-top: 52px;
66
+ }
67
+
68
+ .section-intro h2 {
69
+ font-size: 60px;
70
+ line-height: 1.07;
71
+ }
72
+
73
+ .section-intro h2 .type-accent {
74
+ color: var(--heading-soft);
75
+ }
76
+
77
+ .section-intro > p {
78
+ margin-top: 27px;
79
+ font-size: 14px;
80
+ color: var(--intro-text);
81
+ line-height: 1.8;
82
+ }
83
+
84
+ .section-intro > .text-link {
85
+ margin-top: 24px;
86
+ }
87
+
88
+ /* Reveal: content fades up once, and heading lines slide up inside a clip. */
89
+ .reveal {
90
+ opacity: 0;
91
+ transform: translateY(24px);
92
+ transition:
93
+ opacity 700ms var(--ease),
94
+ transform 700ms var(--ease);
95
+ }
96
+
97
+ .reveal.is-visible {
98
+ opacity: 1;
99
+ transform: translateY(0);
100
+ }
101
+
102
+ .type-line {
103
+ display: block;
104
+ overflow: clip;
105
+ padding-block: 0.09em;
106
+ margin-block: -0.09em;
107
+ }
108
+
109
+ .type-run {
110
+ display: block;
111
+ opacity: 0;
112
+ transform: translateY(105%);
113
+ transition:
114
+ transform 850ms var(--ease),
115
+ opacity 650ms ease;
116
+ }
117
+
118
+ .type-line:nth-child(2) .type-run {
119
+ transition-delay: 110ms;
120
+ }
121
+
122
+ .type-line:nth-child(3) .type-run {
123
+ transition-delay: 220ms;
124
+ }
125
+
126
+ .reveal.is-visible .type-run {
127
+ opacity: 1;
128
+ transform: translateY(0);
129
+ }
130
+
131
+ @keyframes rise-in {
132
+ from {
133
+ opacity: 0;
134
+ transform: translateY(18px);
135
+ }
136
+ to {
137
+ opacity: 1;
138
+ transform: translateY(0);
139
+ }
140
+ }
141
+
142
+ @media (max-width: 1023px) {
143
+ .split-layout {
144
+ gap: 45px;
145
+ }
146
+
147
+ .section-intro h2 {
148
+ font-size: 48px;
149
+ }
150
+ }
151
+
152
+ @media (max-width: 767px) {
153
+ .brand {
154
+ font-size: 30px;
155
+ }
156
+
157
+ .section-space {
158
+ padding-block: 64px;
159
+ }
160
+
161
+ .section-label {
162
+ padding-bottom: 19px;
163
+ }
164
+
165
+ .section-label > span:last-child {
166
+ display: none;
167
+ }
168
+
169
+ .split-layout {
170
+ grid-template-columns: 1fr;
171
+ gap: 35px;
172
+ padding-top: 33px;
173
+ }
174
+
175
+ .section-intro h2 {
176
+ font-size: 44px;
177
+ }
178
+ }
package/package.json ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "name": "@abuzareal/contour-ui",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "Editorial React components, themes, restrained motion, and optional Three.js objects.",
6
+ "type": "module",
7
+ "files": [
8
+ "dist",
9
+ "README.md",
10
+ "LICENSE",
11
+ "CHANGELOG.md",
12
+ "SECURITY.md",
13
+ "RELEASING.md"
14
+ ],
15
+ "sideEffects": [
16
+ "**/*.css"
17
+ ],
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ },
23
+ "./three": {
24
+ "types": "./dist/three.d.ts",
25
+ "import": "./dist/three.js"
26
+ },
27
+ "./scroll": {
28
+ "types": "./dist/scroll.d.ts",
29
+ "import": "./dist/scroll.js"
30
+ },
31
+ "./theme-bootstrap": {
32
+ "types": "./dist/lib/themeBootstrap.d.ts",
33
+ "import": "./dist/lib/themeBootstrap.js"
34
+ },
35
+ "./styles.css": "./dist/styles.css",
36
+ "./reset.css": "./dist/reset.css",
37
+ "./tokens.css": "./dist/tokens.css",
38
+ "./fonts.css": "./dist/fonts.css"
39
+ },
40
+ "scripts": {
41
+ "build": "node scripts/build.mjs",
42
+ "typecheck": "tsc -p tsconfig.json --noEmit",
43
+ "lint": "oxlint src --deny-warnings",
44
+ "test": "node --test tests/*.test.mjs",
45
+ "check:package": "node scripts/check-package.mjs",
46
+ "validate": "npm run typecheck && npm run lint && npm run build && npm test && npm run check:package",
47
+ "prepublishOnly": "npm run validate",
48
+ "test:consumer": "node scripts/test-consumer.mjs"
49
+ },
50
+ "dependencies": {
51
+ "@fontsource-variable/dm-sans": "^5.3.0",
52
+ "@fontsource-variable/space-grotesk": "^5.3.0",
53
+ "@fontsource/dm-mono": "^5.3.0",
54
+ "lucide-react": "^1.49.0"
55
+ },
56
+ "peerDependencies": {
57
+ "lenis": "^1.3.26",
58
+ "react": "^18.3.1",
59
+ "react-dom": "^18.3.1",
60
+ "three": "^0.186.1"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "three": {
64
+ "optional": true
65
+ },
66
+ "lenis": {
67
+ "optional": true
68
+ }
69
+ },
70
+ "devDependencies": {
71
+ "@testing-library/react": "^16.3.3",
72
+ "@types/node": "^24.13.3",
73
+ "@types/react": "^18.3.5",
74
+ "@types/react-dom": "^18.3.0",
75
+ "@types/three": "^0.186.0",
76
+ "jsdom": "^30.1.2",
77
+ "lenis": "^1.3.26",
78
+ "oxlint": "^1.81.0",
79
+ "react": "18.3.1",
80
+ "react-dom": "18.3.1",
81
+ "three": "^0.186.1",
82
+ "typescript": "^5.5.3",
83
+ "vite": "^8.3.2"
84
+ },
85
+ "engines": {
86
+ "node": ">=22"
87
+ },
88
+ "publishConfig": {
89
+ "access": "public",
90
+ "registry": "https://registry.npmjs.org"
91
+ },
92
+ "license": "MIT",
93
+ "repository": {
94
+ "type": "git",
95
+ "url": "git+https://github.com/abuzareal/contour-ui.git"
96
+ },
97
+ "homepage": "https://github.com/abuzareal/contour-ui#readme",
98
+ "bugs": {
99
+ "url": "https://github.com/abuzareal/contour-ui/issues"
100
+ }
101
+ }