@atelic-action/ui 0.17.2 → 1.0.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.
- package/README.md +428 -44
- package/bin/atelic-check-base-path.ts +5 -0
- package/bin/atelic-clean-sitemap.ts +5 -0
- package/bin/atelic-contact-canary.ts +5 -0
- package/bin/atelic-print-sheets.sh +1 -1
- package/bin/atelic-seal-document.mjs +1 -1
- package/bin/atelic-serve-static.ts +1 -1
- package/dist/gate/index.d.ts +1 -1
- package/dist/gate/index.js +1 -1
- package/dist/gate/middleware.d.ts +4 -1
- package/dist/gate/middleware.js +14 -5
- package/dist/gate/wall.d.ts +25 -0
- package/dist/gate/wall.js +41 -2
- package/dist/routing/basePath.d.ts +24 -0
- package/dist/routing/basePath.js +54 -0
- package/dist/vite/index.d.ts +3 -2
- package/dist/vite/index.js +3 -2
- package/dist/vite/marketing-config.d.ts +50 -0
- package/dist/vite/marketing-config.js +83 -0
- package/package.json +164 -5
- package/src/app/AppProvider.tsx +41 -0
- package/src/app/AuthGuard.tsx +27 -0
- package/src/app/CardErrorBoundary.tsx +39 -0
- package/src/app/ErrorFallback.tsx +39 -0
- package/src/app/GoogleGlyph.tsx +22 -0
- package/src/app/config.ts +54 -0
- package/src/app/configure.ts +18 -0
- package/src/app/context/AppContext.tsx +52 -0
- package/src/app/context/SidebarContext.tsx +124 -0
- package/src/app/context/UserContext.tsx +139 -0
- package/src/app/hooks/useDebounce.ts +12 -0
- package/src/app/hooks/useIsDesktop.ts +31 -0
- package/src/app/hooks/useWakeLock.ts +49 -0
- package/src/app/index.ts +64 -0
- package/src/app/layout/ActionButton.tsx +67 -0
- package/src/app/layout/AppLayout.tsx +110 -0
- package/src/app/layout/AppPage.tsx +268 -0
- package/src/app/layout/Breadcrumbs.tsx +57 -0
- package/src/app/layout/DesktopRail.tsx +168 -0
- package/src/app/layout/FormActionButtons.tsx +69 -0
- package/src/app/layout/MobileMenu.tsx +156 -0
- package/src/app/layout/MobileTabBar.tsx +43 -0
- package/src/app/layout/PageError.tsx +30 -0
- package/src/app/layout/PageSkeleton.tsx +65 -0
- package/src/app/layout/SectionCards.tsx +33 -0
- package/src/app/layout/UserMenu.tsx +104 -0
- package/src/app/layout/identity.ts +22 -0
- package/src/app/layout/index.ts +20 -0
- package/src/app/layout/nav.ts +52 -0
- package/src/app/lib/dates.ts +57 -0
- package/src/app/lib/env.ts +37 -0
- package/src/app/lib/format.ts +61 -0
- package/src/app/lib/http.ts +205 -0
- package/src/app/lib/lastAuth.ts +45 -0
- package/src/app/lib/oauth.ts +32 -0
- package/src/app/lib/publicRoutes.ts +33 -0
- package/src/app/lib/queryClient.ts +38 -0
- package/src/app/lib/search.ts +17 -0
- package/src/app/lib/session.ts +36 -0
- package/src/app/lib/tokenRefresh.ts +137 -0
- package/src/app/lib/transformKeys.ts +60 -0
- package/src/app/lib/units.ts +228 -0
- package/src/app/lib/unwrap.ts +48 -0
- package/src/app/lib/utils.ts +10 -0
- package/src/app/stores/authStore.ts +80 -0
- package/src/app/stores/storage.ts +40 -0
- package/src/app/stores/unitsStore.ts +54 -0
- package/src/app/types/index.ts +72 -0
- package/src/app/types/query.ts +11 -0
- package/src/app/ui/accordion.tsx +54 -0
- package/src/app/ui/alert-dialog.tsx +114 -0
- package/src/app/ui/alert.tsx +49 -0
- package/src/app/ui/avatar.tsx +45 -0
- package/src/app/ui/badge-list.tsx +51 -0
- package/src/app/ui/badge.tsx +33 -0
- package/src/app/ui/button.tsx +49 -0
- package/src/app/ui/callout.tsx +22 -0
- package/src/app/ui/card.tsx +55 -0
- package/src/app/ui/checkbox.tsx +26 -0
- package/src/app/ui/clear-button.tsx +42 -0
- package/src/app/ui/command.tsx +140 -0
- package/src/app/ui/country-dropdown.tsx +184 -0
- package/src/app/ui/dialog.tsx +104 -0
- package/src/app/ui/dropdown-menu.tsx +185 -0
- package/src/app/ui/form.tsx +172 -0
- package/src/app/ui/index.ts +36 -0
- package/src/app/ui/input.tsx +22 -0
- package/src/app/ui/label.tsx +19 -0
- package/src/app/ui/option-select.tsx +56 -0
- package/src/app/ui/pagination.tsx +90 -0
- package/src/app/ui/popover.tsx +29 -0
- package/src/app/ui/progress.tsx +25 -0
- package/src/app/ui/search-input.tsx +63 -0
- package/src/app/ui/select.tsx +151 -0
- package/src/app/ui/separator.tsx +24 -0
- package/src/app/ui/sheet.tsx +119 -0
- package/src/app/ui/slider.tsx +23 -0
- package/src/app/ui/switch.tsx +27 -0
- package/src/app/ui/textarea.tsx +21 -0
- package/src/app/ui/tooltip.tsx +32 -0
- package/src/artifact/ArtifactShell.tsx +2 -2
- package/src/artifact/Gate.tsx +2 -2
- package/src/artifact/Writeup.tsx +7 -7
- package/src/chrome/SiteShell.tsx +141 -0
- package/src/chrome/index.ts +2 -0
- package/src/components/Disclosure.tsx +80 -14
- package/src/components/GateLogin.tsx +1 -1
- package/src/components/Watermark.tsx +1 -1
- package/src/components/index.ts +6 -2
- package/src/gate/index.ts +1 -1
- package/src/gate/middleware.ts +17 -6
- package/src/gate/wall.ts +60 -2
- package/src/lib/basePathAudit.ts +96 -0
- package/src/lib/displayDate.ts +25 -0
- package/src/lib/honeypot.ts +11 -0
- package/src/lib/hours.ts +28 -0
- package/src/lib/sitemap.ts +34 -0
- package/src/lib/trackEvent.ts +26 -0
- package/src/lib/useOpenHeight.ts +28 -0
- package/src/primitives/Button.tsx +3 -1
- package/src/primitives/Chip.tsx +3 -1
- package/src/primitives/ImageFrame.tsx +48 -0
- package/src/primitives/ProseBlocks.tsx +67 -0
- package/src/primitives/QuoteCard.tsx +20 -0
- package/src/primitives/StarRow.tsx +37 -0
- package/src/primitives/TickList.tsx +24 -0
- package/src/primitives/index.ts +5 -0
- package/src/routing/BasePathProvider.tsx +47 -0
- package/src/routing/basePath.ts +57 -0
- package/src/routing/index.ts +8 -0
- package/src/scripts/check-base-path.ts +130 -0
- package/src/scripts/clean-sitemap.ts +27 -0
- package/src/scripts/contact-canary.ts +98 -0
- package/src/scripts/serve-static.ts +29 -3
- package/src/sections/BlogIndex.tsx +57 -0
- package/src/sections/BlogPost.tsx +65 -0
- package/src/sections/CTABanner.tsx +93 -0
- package/src/sections/CTASection.tsx +60 -0
- package/src/sections/ComparisonTable.tsx +114 -0
- package/src/sections/ContactForm.tsx +163 -0
- package/src/sections/ContactInfoCard.tsx +92 -0
- package/src/sections/CredentialList.tsx +28 -0
- package/src/sections/DeviceShowcase.tsx +39 -0
- package/src/sections/ExpandList.tsx +58 -0
- package/src/sections/FAQBrowser.tsx +283 -0
- package/src/sections/FeatureDetail.tsx +60 -0
- package/src/sections/FeatureGrid.tsx +83 -0
- package/src/sections/Gallery.tsx +84 -0
- package/src/sections/Hero.tsx +110 -0
- package/src/sections/HoursTable.tsx +23 -0
- package/src/sections/JumpRail.tsx +35 -0
- package/src/sections/LegalPage.tsx +43 -0
- package/src/sections/LocationSection.tsx +66 -0
- package/src/sections/Locations.tsx +71 -0
- package/src/sections/LogoMarquee.tsx +27 -0
- package/src/sections/MapEmbed.tsx +75 -0
- package/src/sections/MediaBand.tsx +20 -0
- package/src/sections/MenuList.tsx +44 -0
- package/src/sections/PageHero.tsx +25 -0
- package/src/sections/PressQuotes.tsx +51 -0
- package/src/sections/PricingBand.tsx +43 -0
- package/src/sections/PricingCard.tsx +36 -0
- package/src/sections/ProcessSteps.tsx +45 -0
- package/src/sections/ProfileCards.tsx +73 -0
- package/src/sections/RevealSlider.tsx +156 -0
- package/src/sections/ReviewCarousel.tsx +223 -0
- package/src/sections/ReviewWall.tsx +220 -0
- package/src/sections/SocialStrip.tsx +83 -0
- package/src/sections/SplitSection.tsx +56 -0
- package/src/sections/index.ts +76 -0
- package/src/sections/siteConfig.ts +201 -0
- package/src/styles/app.css +673 -0
- package/src/styles/artifact.css +472 -399
- package/src/styles/base.css +49 -47
- package/src/styles/chrome.css +71 -71
- package/src/styles/components.css +150 -140
- package/src/styles/gate.css +29 -29
- package/src/styles/primitives.css +190 -25
- package/src/styles/sections.css +2652 -0
- package/src/styles/star-rating.css +2 -2
- package/src/vite/index.ts +9 -2
- package/src/vite/marketing-config.ts +128 -0
- package/src/components/Collapsible.tsx +0 -43
- /package/src/scripts/{build-gate-payload.mjs → seal-document.mjs} +0 -0
package/src/styles/base.css
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* =================================================================
|
|
2
2
|
@atelic-action/ui BASE: the few unscoped resets, then the canvas,
|
|
3
|
-
typography, and layout helpers, scoped to .
|
|
3
|
+
typography, and layout helpers, scoped to .atelic-ui. The class is the
|
|
4
|
+
one root a consumer wears; what it gets is decided by the sheets it
|
|
5
|
+
imports, so an app that imports only components.css gets none of this.
|
|
4
6
|
Tokens are read here and never defined: each site's theme.css owns
|
|
5
7
|
them. Everything sits in the atelic-ui layer, so any rule a site
|
|
6
8
|
writes outside a layer wins without a specificity fight.
|
|
@@ -29,12 +31,12 @@
|
|
|
29
31
|
|
|
30
32
|
/* ---- Page canvas ---- */
|
|
31
33
|
/* Horizontal overflow is clipped at the body (where it still propagates to
|
|
32
|
-
the viewport) rather than on .
|
|
33
|
-
silently break position: sticky for every descendant. */
|
|
34
|
-
body:has(.
|
|
34
|
+
the viewport) rather than on .atelic-ui itself: an overflow-x there
|
|
35
|
+
would silently break position: sticky for every descendant. */
|
|
36
|
+
body:has(.atelic-ui) {
|
|
35
37
|
overflow-x: hidden;
|
|
36
38
|
}
|
|
37
|
-
.
|
|
39
|
+
.atelic-ui {
|
|
38
40
|
font-family: var(--font-sans);
|
|
39
41
|
background: var(--surface);
|
|
40
42
|
color: var(--ink);
|
|
@@ -43,35 +45,35 @@
|
|
|
43
45
|
-webkit-font-smoothing: antialiased;
|
|
44
46
|
text-rendering: optimizeLegibility;
|
|
45
47
|
}
|
|
46
|
-
.
|
|
48
|
+
.atelic-ui a {
|
|
47
49
|
color: inherit;
|
|
48
50
|
text-decoration: none;
|
|
49
51
|
}
|
|
50
|
-
.
|
|
52
|
+
.atelic-ui button {
|
|
51
53
|
font: inherit;
|
|
52
54
|
cursor: pointer;
|
|
53
55
|
border: none;
|
|
54
56
|
background: none;
|
|
55
57
|
color: inherit;
|
|
56
58
|
}
|
|
57
|
-
.
|
|
59
|
+
.atelic-ui ul {
|
|
58
60
|
list-style: none;
|
|
59
61
|
padding: 0;
|
|
60
62
|
margin: 0;
|
|
61
63
|
}
|
|
62
|
-
.
|
|
63
|
-
.
|
|
64
|
-
.
|
|
65
|
-
.
|
|
64
|
+
.atelic-ui img,
|
|
65
|
+
.atelic-ui picture,
|
|
66
|
+
.atelic-ui svg,
|
|
67
|
+
.atelic-ui video {
|
|
66
68
|
display: block;
|
|
67
69
|
max-width: 100%;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
/* ---- Typography ---- */
|
|
71
|
-
.
|
|
72
|
-
.
|
|
73
|
-
.
|
|
74
|
-
.
|
|
73
|
+
.atelic-ui h1,
|
|
74
|
+
.atelic-ui h2,
|
|
75
|
+
.atelic-ui h3,
|
|
76
|
+
.atelic-ui h4 {
|
|
75
77
|
/* Sites pairing a display face with a body face set --font-heading in
|
|
76
78
|
their theme; without it, headings share the body family. */
|
|
77
79
|
font-family: var(--font-heading, var(--font-sans));
|
|
@@ -81,27 +83,27 @@
|
|
|
81
83
|
text-wrap: balance;
|
|
82
84
|
margin: 0;
|
|
83
85
|
}
|
|
84
|
-
.
|
|
86
|
+
.atelic-ui h1 {
|
|
85
87
|
font-size: clamp(2.6rem, 8vw, 5rem);
|
|
86
88
|
}
|
|
87
|
-
.
|
|
89
|
+
.atelic-ui h2 {
|
|
88
90
|
font-size: clamp(2rem, 5.5vw, 3.4rem);
|
|
89
91
|
}
|
|
90
|
-
.
|
|
92
|
+
.atelic-ui h3 {
|
|
91
93
|
font-size: clamp(1.35rem, 3vw, 1.85rem);
|
|
92
94
|
letter-spacing: -0.015em;
|
|
93
95
|
}
|
|
94
|
-
.
|
|
96
|
+
.atelic-ui h4 {
|
|
95
97
|
font-size: 1.15rem;
|
|
96
98
|
font-weight: 700;
|
|
97
99
|
letter-spacing: -0.01em;
|
|
98
100
|
}
|
|
99
|
-
.
|
|
101
|
+
.atelic-ui p {
|
|
100
102
|
text-wrap: pretty;
|
|
101
103
|
margin: 0;
|
|
102
104
|
}
|
|
103
|
-
.
|
|
104
|
-
.
|
|
105
|
+
.atelic-ui em.serif,
|
|
106
|
+
.atelic-ui .serif-em {
|
|
105
107
|
font-family: var(--font-serif);
|
|
106
108
|
font-style: italic;
|
|
107
109
|
font-weight: 400;
|
|
@@ -111,93 +113,93 @@
|
|
|
111
113
|
/* Serif accent words in headings carry the brand accent color (the
|
|
112
114
|
wordmark's signature), so the italic word reads as the highlight it is.
|
|
113
115
|
A page on a dark surface lifts its own to the bright primary. */
|
|
114
|
-
.
|
|
115
|
-
.
|
|
116
|
+
.atelic-ui h1 .serif,
|
|
117
|
+
.atelic-ui h2 .serif {
|
|
116
118
|
color: var(--primary);
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
/* ---- Layout helpers ---- */
|
|
120
|
-
.
|
|
122
|
+
.atelic-ui .wrap {
|
|
121
123
|
width: 100%;
|
|
122
124
|
max-width: var(--max-width);
|
|
123
125
|
margin-inline: auto;
|
|
124
126
|
padding-inline: var(--gutter);
|
|
125
127
|
}
|
|
126
|
-
.
|
|
128
|
+
.atelic-ui .section {
|
|
127
129
|
padding-block: clamp(56px, 9vw, 120px);
|
|
128
130
|
}
|
|
129
131
|
/* A middle step, for a page whose alternating bands do the separating and
|
|
130
132
|
whose default rhythm reads too airy as a result. */
|
|
131
|
-
.
|
|
133
|
+
.atelic-ui .section-md {
|
|
132
134
|
padding-block: clamp(44px, 6.5vw, 84px);
|
|
133
135
|
}
|
|
134
|
-
.
|
|
136
|
+
.atelic-ui .section-sm {
|
|
135
137
|
padding-block: clamp(40px, 6vw, 72px);
|
|
136
138
|
}
|
|
137
139
|
/* Section band modifiers, global because routes across chunks use them. */
|
|
138
|
-
.
|
|
140
|
+
.atelic-ui .section.surface-alt {
|
|
139
141
|
background: var(--surface-alt);
|
|
140
142
|
}
|
|
141
|
-
.
|
|
143
|
+
.atelic-ui .section.tight-top {
|
|
142
144
|
padding-top: clamp(20px, 3vw, 40px);
|
|
143
145
|
}
|
|
144
|
-
.
|
|
146
|
+
.atelic-ui .section.tight-bottom {
|
|
145
147
|
padding-bottom: clamp(20px, 3vw, 40px);
|
|
146
148
|
}
|
|
147
|
-
.
|
|
149
|
+
.atelic-ui .stack-sm > * + * {
|
|
148
150
|
margin-top: 0.75rem;
|
|
149
151
|
}
|
|
150
|
-
.
|
|
152
|
+
.atelic-ui .stack > * + * {
|
|
151
153
|
margin-top: 1.25rem;
|
|
152
154
|
}
|
|
153
|
-
.
|
|
155
|
+
.atelic-ui .center {
|
|
154
156
|
text-align: center;
|
|
155
157
|
}
|
|
156
|
-
.
|
|
158
|
+
.atelic-ui .muted {
|
|
157
159
|
color: var(--neutral-600);
|
|
158
160
|
}
|
|
159
|
-
.
|
|
161
|
+
.atelic-ui .nowrap {
|
|
160
162
|
white-space: nowrap;
|
|
161
163
|
}
|
|
162
164
|
|
|
163
165
|
/* ---- CTA row (pairs of buttons under headlines) ---- */
|
|
164
|
-
.
|
|
166
|
+
.atelic-ui .cta-row {
|
|
165
167
|
display: flex;
|
|
166
168
|
flex-wrap: wrap;
|
|
167
169
|
gap: 14px;
|
|
168
170
|
margin-top: 32px;
|
|
169
171
|
}
|
|
170
|
-
.
|
|
172
|
+
.atelic-ui .cta-row.center {
|
|
171
173
|
justify-content: center;
|
|
172
174
|
}
|
|
173
175
|
|
|
174
176
|
/* ---- Chip row ---- */
|
|
175
|
-
.
|
|
177
|
+
.atelic-ui .chip-row {
|
|
176
178
|
display: flex;
|
|
177
179
|
flex-wrap: wrap;
|
|
178
180
|
gap: 10px;
|
|
179
181
|
}
|
|
180
182
|
|
|
181
183
|
/* ---- Prose (long form copy) ---- */
|
|
182
|
-
.
|
|
184
|
+
.atelic-ui .prose {
|
|
183
185
|
max-width: 68ch;
|
|
184
186
|
}
|
|
185
|
-
.
|
|
187
|
+
.atelic-ui .prose p {
|
|
186
188
|
margin-bottom: 1.1rem;
|
|
187
189
|
color: var(--ink-soft);
|
|
188
190
|
font-size: 1.08rem;
|
|
189
191
|
line-height: 1.7;
|
|
190
192
|
}
|
|
191
|
-
.
|
|
193
|
+
.atelic-ui .prose h3 {
|
|
192
194
|
margin: 2.2rem 0 0.8rem;
|
|
193
195
|
}
|
|
194
|
-
.
|
|
196
|
+
.atelic-ui .prose strong {
|
|
195
197
|
color: var(--ink);
|
|
196
198
|
}
|
|
197
199
|
|
|
198
200
|
/* Anchored sections sit under the fixed header; give every id an offset
|
|
199
201
|
so jump links do not land beneath it. */
|
|
200
|
-
.
|
|
202
|
+
.atelic-ui [id] {
|
|
201
203
|
scroll-margin-top: calc(var(--nav-height) + 16px);
|
|
202
204
|
}
|
|
203
205
|
|
|
@@ -209,12 +211,12 @@
|
|
|
209
211
|
whole ask was a link nobody could see. Scoped to paragraph links so a button
|
|
210
212
|
dropped into a prose block is untouched, and placed last so it reads after
|
|
211
213
|
the lighter anchor rules above. */
|
|
212
|
-
.
|
|
214
|
+
.atelic-ui .prose p a:not(.btn) {
|
|
213
215
|
color: var(--ink);
|
|
214
216
|
border-bottom: 1px solid var(--neutral-300);
|
|
215
217
|
padding-bottom: 1px;
|
|
216
218
|
}
|
|
217
|
-
.
|
|
219
|
+
.atelic-ui .prose p a:not(.btn):hover {
|
|
218
220
|
color: var(--primary);
|
|
219
221
|
border-color: var(--primary);
|
|
220
222
|
}
|
package/src/styles/chrome.css
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
================================================================= */
|
|
8
8
|
@layer atelic-ui {
|
|
9
9
|
/* ---- Skip link (a11y) ---- */
|
|
10
|
-
.
|
|
10
|
+
.atelic-ui .skip-link {
|
|
11
11
|
position: absolute;
|
|
12
12
|
left: -9999px;
|
|
13
13
|
top: 0;
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
z-index: 200;
|
|
18
18
|
border-radius: 0 0 8px 0;
|
|
19
19
|
}
|
|
20
|
-
.
|
|
20
|
+
.atelic-ui .skip-link:focus {
|
|
21
21
|
left: 0;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/* ---- Brand lockup ---- */
|
|
25
25
|
/* The brand's trailing fade bar after the wordmark (logo.run), worn in the
|
|
26
26
|
header and the footer. */
|
|
27
|
-
.
|
|
27
|
+
.atelic-ui .wordmark-run {
|
|
28
28
|
display: inline-block;
|
|
29
29
|
width: 1.7em;
|
|
30
30
|
height: 2px;
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
/* The glyph tile mark (logo.tile): the favicon's design as real DOM text,
|
|
39
39
|
so the brand webfont renders it, which an SVG loaded through an img
|
|
40
40
|
cannot do. Worn in the header and the footer. */
|
|
41
|
-
.
|
|
41
|
+
.atelic-ui .logo-tile {
|
|
42
42
|
display: inline-flex;
|
|
43
43
|
align-items: center;
|
|
44
44
|
justify-content: center;
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
position: relative;
|
|
55
55
|
flex: none;
|
|
56
56
|
}
|
|
57
|
-
.
|
|
57
|
+
.atelic-ui .logo-tile::after {
|
|
58
58
|
content: "";
|
|
59
59
|
position: absolute;
|
|
60
60
|
left: 7px;
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
|
|
68
68
|
/* ---- Header ---- */
|
|
69
69
|
/* Fixed header: transparent over a hero, solid once scrolled, or dark. */
|
|
70
|
-
.
|
|
70
|
+
.atelic-ui .nav {
|
|
71
71
|
position: fixed;
|
|
72
72
|
top: 0;
|
|
73
73
|
left: 0;
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
box-shadow 0.3s ease,
|
|
82
82
|
backdrop-filter 0.3s ease;
|
|
83
83
|
}
|
|
84
|
-
.
|
|
84
|
+
.atelic-ui .nav-inner {
|
|
85
85
|
width: 100%;
|
|
86
86
|
max-width: var(--max-width);
|
|
87
87
|
margin-inline: auto;
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
justify-content: space-between;
|
|
92
92
|
gap: 20px;
|
|
93
93
|
}
|
|
94
|
-
.
|
|
94
|
+
.atelic-ui .nav-logo {
|
|
95
95
|
display: flex;
|
|
96
96
|
align-items: center;
|
|
97
97
|
gap: 10px;
|
|
@@ -100,33 +100,33 @@
|
|
|
100
100
|
letter-spacing: -0.02em;
|
|
101
101
|
font-size: 1.02rem;
|
|
102
102
|
}
|
|
103
|
-
.
|
|
103
|
+
.atelic-ui .nav-logo .mark {
|
|
104
104
|
height: 30px;
|
|
105
105
|
width: 30px;
|
|
106
106
|
}
|
|
107
107
|
/* The recipient half of a sent artifact's lockup (BrandLockup: recipient):
|
|
108
108
|
a quiet times sign in the mono face, then the business's mark at
|
|
109
109
|
wordmark height. */
|
|
110
|
-
.
|
|
110
|
+
.atelic-ui .nav-logo .nav-x {
|
|
111
111
|
font-family: var(--font-mono);
|
|
112
112
|
font-weight: 400;
|
|
113
113
|
font-size: 0.9rem;
|
|
114
114
|
color: color-mix(in srgb, currentColor 55%, transparent);
|
|
115
115
|
margin: 0 2px;
|
|
116
116
|
}
|
|
117
|
-
.
|
|
117
|
+
.atelic-ui .nav-logo .nav-recipient {
|
|
118
118
|
/* Matches the sender's mark, so a square recipient mark reads at the
|
|
119
119
|
same size as the sender's would; a wide wordmark simply runs longer. */
|
|
120
120
|
height: 30px;
|
|
121
121
|
width: auto;
|
|
122
122
|
display: block;
|
|
123
123
|
}
|
|
124
|
-
.
|
|
124
|
+
.atelic-ui .nav-links {
|
|
125
125
|
display: none;
|
|
126
126
|
align-items: center;
|
|
127
127
|
gap: 4px;
|
|
128
128
|
}
|
|
129
|
-
.
|
|
129
|
+
.atelic-ui .nav-links a {
|
|
130
130
|
padding: 8px 14px;
|
|
131
131
|
border-radius: var(--radius-pill);
|
|
132
132
|
font-weight: 600;
|
|
@@ -135,11 +135,11 @@
|
|
|
135
135
|
background 0.15s,
|
|
136
136
|
color 0.15s;
|
|
137
137
|
}
|
|
138
|
-
.
|
|
138
|
+
.atelic-ui .nav-links a:hover {
|
|
139
139
|
background: rgba(33, 28, 23, 0.06);
|
|
140
140
|
}
|
|
141
141
|
/* A page's own stops: the scroll spied active one. */
|
|
142
|
-
.
|
|
142
|
+
.atelic-ui .nav-links a.active {
|
|
143
143
|
color: var(--primary);
|
|
144
144
|
}
|
|
145
145
|
/* Desktop only, and hidden until the bar is solid: on small screens the
|
|
@@ -147,16 +147,16 @@
|
|
|
147
147
|
width. The class sits on a wrapper around the button, because a site's
|
|
148
148
|
.btn display rule lives outside this layer and would outrank a rule here
|
|
149
149
|
that hid the button itself. */
|
|
150
|
-
.
|
|
150
|
+
.atelic-ui .nav .nav-cta {
|
|
151
151
|
display: none;
|
|
152
152
|
}
|
|
153
|
-
.
|
|
153
|
+
.atelic-ui .nav-burger {
|
|
154
154
|
display: inline-flex;
|
|
155
155
|
flex-direction: column;
|
|
156
156
|
gap: 5px;
|
|
157
157
|
padding: 10px;
|
|
158
158
|
}
|
|
159
|
-
.
|
|
159
|
+
.atelic-ui .nav-burger span {
|
|
160
160
|
width: 24px;
|
|
161
161
|
height: 2px;
|
|
162
162
|
background: currentColor;
|
|
@@ -166,16 +166,16 @@
|
|
|
166
166
|
opacity 0.2s;
|
|
167
167
|
}
|
|
168
168
|
/* A white logo image is tinted to ink when the bar is solid on light. */
|
|
169
|
-
.
|
|
169
|
+
.atelic-ui .nav.is-solid .nav-logo .mark {
|
|
170
170
|
filter: brightness(0) saturate(1);
|
|
171
171
|
}
|
|
172
|
-
.
|
|
172
|
+
.atelic-ui .nav.is-transparent {
|
|
173
173
|
color: #fff;
|
|
174
174
|
}
|
|
175
|
-
.
|
|
175
|
+
.atelic-ui .nav.is-transparent .nav-logo .wordmark {
|
|
176
176
|
color: #fff;
|
|
177
177
|
}
|
|
178
|
-
.
|
|
178
|
+
.atelic-ui .nav.is-solid {
|
|
179
179
|
background: color-mix(in srgb, var(--surface) 86%, transparent);
|
|
180
180
|
backdrop-filter: saturate(1.4) blur(14px);
|
|
181
181
|
-webkit-backdrop-filter: saturate(1.4) blur(14px);
|
|
@@ -185,40 +185,40 @@
|
|
|
185
185
|
/* The dark bar (an artifact's stage, the audit): it matches the page
|
|
186
186
|
instead of capping it with a light band. The white logo mark stays
|
|
187
187
|
untinted, and the active stop lifts to the bright primary. */
|
|
188
|
-
.
|
|
188
|
+
.atelic-ui .nav.is-solid.nav-dark {
|
|
189
189
|
background: color-mix(in srgb, var(--surface-dark) 88%, transparent);
|
|
190
190
|
box-shadow: 0 1px 0 color-mix(in srgb, var(--surface) 12%, transparent);
|
|
191
191
|
color: color-mix(in srgb, var(--surface) 96%, white);
|
|
192
192
|
}
|
|
193
|
-
.
|
|
193
|
+
.atelic-ui .nav.nav-dark .nav-logo .mark {
|
|
194
194
|
filter: none;
|
|
195
195
|
}
|
|
196
|
-
.
|
|
196
|
+
.atelic-ui .nav.nav-dark .nav-links a:hover {
|
|
197
197
|
background: rgba(255, 255, 255, 0.08);
|
|
198
198
|
}
|
|
199
|
-
.
|
|
199
|
+
.atelic-ui .nav.nav-dark .nav-links a.active {
|
|
200
200
|
color: var(--primary-bright);
|
|
201
201
|
}
|
|
202
202
|
@media (min-width: 900px) {
|
|
203
|
-
.
|
|
203
|
+
.atelic-ui .nav-links {
|
|
204
204
|
display: flex;
|
|
205
205
|
}
|
|
206
|
-
.
|
|
206
|
+
.atelic-ui .nav-burger {
|
|
207
207
|
display: none;
|
|
208
208
|
}
|
|
209
|
-
.
|
|
209
|
+
.atelic-ui .nav.is-solid .nav-cta {
|
|
210
210
|
display: inline-flex;
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
/* The burger folds into an X while the menu is open. State lives on the
|
|
214
214
|
button's own aria-expanded, so no extra class plumbing. */
|
|
215
|
-
.
|
|
215
|
+
.atelic-ui .nav-burger[aria-expanded="true"] span:nth-child(1) {
|
|
216
216
|
transform: translateY(7px) rotate(45deg);
|
|
217
217
|
}
|
|
218
|
-
.
|
|
218
|
+
.atelic-ui .nav-burger[aria-expanded="true"] span:nth-child(2) {
|
|
219
219
|
opacity: 0;
|
|
220
220
|
}
|
|
221
|
-
.
|
|
221
|
+
.atelic-ui .nav-burger[aria-expanded="true"] span:nth-child(3) {
|
|
222
222
|
transform: translateY(-7px) rotate(-45deg);
|
|
223
223
|
}
|
|
224
224
|
|
|
@@ -226,7 +226,7 @@
|
|
|
226
226
|
/* A native modal dialog, sized to the whole viewport over the dialog's own
|
|
227
227
|
box. It renders in the top layer above the header, so it carries its own
|
|
228
228
|
close button where the burger sits. */
|
|
229
|
-
.
|
|
229
|
+
.atelic-ui .mobile-menu {
|
|
230
230
|
position: fixed;
|
|
231
231
|
inset: 0;
|
|
232
232
|
width: 100%;
|
|
@@ -243,20 +243,20 @@
|
|
|
243
243
|
transform: translateY(-100%);
|
|
244
244
|
transition: transform 0.4s cubic-bezier(0.7, 0, 0.2, 1);
|
|
245
245
|
}
|
|
246
|
-
.
|
|
246
|
+
.atelic-ui .mobile-menu[open] {
|
|
247
247
|
display: flex;
|
|
248
248
|
transform: translateY(0);
|
|
249
249
|
}
|
|
250
250
|
@starting-style {
|
|
251
|
-
.
|
|
251
|
+
.atelic-ui .mobile-menu[open] {
|
|
252
252
|
transform: translateY(-100%);
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
|
-
.
|
|
255
|
+
.atelic-ui .mobile-menu::backdrop {
|
|
256
256
|
background: transparent;
|
|
257
257
|
}
|
|
258
258
|
@media (prefers-reduced-motion: reduce) {
|
|
259
|
-
.
|
|
259
|
+
.atelic-ui .mobile-menu {
|
|
260
260
|
transition: none;
|
|
261
261
|
}
|
|
262
262
|
}
|
|
@@ -264,7 +264,7 @@
|
|
|
264
264
|
html:has(dialog.mobile-menu[open]) {
|
|
265
265
|
overflow: hidden;
|
|
266
266
|
}
|
|
267
|
-
.
|
|
267
|
+
.atelic-ui .mobile-menu .mm-close {
|
|
268
268
|
position: absolute;
|
|
269
269
|
top: calc(var(--nav-height) / 2 - 14.5px);
|
|
270
270
|
right: var(--gutter);
|
|
@@ -273,21 +273,21 @@
|
|
|
273
273
|
gap: 5px;
|
|
274
274
|
padding: 10px;
|
|
275
275
|
}
|
|
276
|
-
.
|
|
276
|
+
.atelic-ui .mobile-menu .mm-close span {
|
|
277
277
|
width: 24px;
|
|
278
278
|
height: 2px;
|
|
279
279
|
background: currentColor;
|
|
280
280
|
border-radius: 2px;
|
|
281
281
|
}
|
|
282
|
-
.
|
|
282
|
+
.atelic-ui .mobile-menu .mm-close span:nth-child(1) {
|
|
283
283
|
transform: translateY(3.5px) rotate(45deg);
|
|
284
284
|
}
|
|
285
|
-
.
|
|
285
|
+
.atelic-ui .mobile-menu .mm-close span:nth-child(2) {
|
|
286
286
|
transform: translateY(-3.5px) rotate(-45deg);
|
|
287
287
|
}
|
|
288
288
|
/* Menu entries only (.mm-link), never bare anchors, so the .btn CTA below
|
|
289
289
|
keeps its standard button styling. */
|
|
290
|
-
.
|
|
290
|
+
.atelic-ui .mobile-menu .mm-link {
|
|
291
291
|
font-size: 1.8rem;
|
|
292
292
|
font-weight: 800;
|
|
293
293
|
letter-spacing: -0.02em;
|
|
@@ -297,16 +297,16 @@
|
|
|
297
297
|
justify-content: space-between;
|
|
298
298
|
align-items: center;
|
|
299
299
|
}
|
|
300
|
-
.
|
|
300
|
+
.atelic-ui .mobile-menu .mm-link .idx {
|
|
301
301
|
font-family: var(--font-mono);
|
|
302
302
|
font-size: 0.8rem;
|
|
303
303
|
color: var(--primary-bright);
|
|
304
304
|
font-weight: 500;
|
|
305
305
|
}
|
|
306
|
-
.
|
|
306
|
+
.atelic-ui .mobile-menu .mm-cta {
|
|
307
307
|
margin-top: 28px;
|
|
308
308
|
}
|
|
309
|
-
.
|
|
309
|
+
.atelic-ui .mobile-menu .mm-contact {
|
|
310
310
|
margin-top: auto;
|
|
311
311
|
font-family: var(--font-mono);
|
|
312
312
|
font-size: 0.8rem;
|
|
@@ -316,7 +316,7 @@
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
/* ---- Sticky CTA bar (phones only) ---- */
|
|
319
|
-
.
|
|
319
|
+
.atelic-ui .sticky-cta {
|
|
320
320
|
position: fixed;
|
|
321
321
|
left: 0;
|
|
322
322
|
right: 0;
|
|
@@ -332,37 +332,37 @@
|
|
|
332
332
|
transform: translateY(120%);
|
|
333
333
|
transition: transform 0.35s cubic-bezier(0.7, 0, 0.2, 1);
|
|
334
334
|
}
|
|
335
|
-
.
|
|
335
|
+
.atelic-ui .sticky-cta.show {
|
|
336
336
|
transform: translateY(0);
|
|
337
337
|
}
|
|
338
|
-
.
|
|
338
|
+
.atelic-ui .sticky-cta .btn {
|
|
339
339
|
flex: 1;
|
|
340
340
|
}
|
|
341
|
-
.
|
|
341
|
+
.atelic-ui .sticky-cta .btn-call {
|
|
342
342
|
flex: 0 0 auto;
|
|
343
343
|
}
|
|
344
344
|
@media (min-width: 900px) {
|
|
345
|
-
.
|
|
345
|
+
.atelic-ui .sticky-cta {
|
|
346
346
|
display: none;
|
|
347
347
|
}
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
/* ---- Footer ---- */
|
|
351
|
-
.
|
|
351
|
+
.atelic-ui .footer {
|
|
352
352
|
background: var(--surface-dark);
|
|
353
353
|
color: var(--neutral-200);
|
|
354
354
|
padding-block: clamp(48px, 7vw, 84px) 28px;
|
|
355
355
|
}
|
|
356
356
|
/* biome-ignore lint/style/noDescendingSpecificity: scoped to .footer, so it never meets the header's link rules */
|
|
357
|
-
.
|
|
357
|
+
.atelic-ui .footer a:hover {
|
|
358
358
|
color: #fff;
|
|
359
359
|
}
|
|
360
|
-
.
|
|
360
|
+
.atelic-ui .footer-grid {
|
|
361
361
|
display: grid;
|
|
362
362
|
gap: 40px;
|
|
363
363
|
grid-template-columns: 1fr;
|
|
364
364
|
}
|
|
365
|
-
.
|
|
365
|
+
.atelic-ui .footer h4 {
|
|
366
366
|
color: #fff;
|
|
367
367
|
font-family: var(--font-mono);
|
|
368
368
|
font-size: 0.74rem;
|
|
@@ -371,41 +371,41 @@
|
|
|
371
371
|
font-weight: 500;
|
|
372
372
|
margin-bottom: 16px;
|
|
373
373
|
}
|
|
374
|
-
.
|
|
374
|
+
.atelic-ui .footer-brand img {
|
|
375
375
|
height: 38px;
|
|
376
376
|
margin-bottom: 18px;
|
|
377
377
|
}
|
|
378
|
-
.
|
|
378
|
+
.atelic-ui .footer-brand p {
|
|
379
379
|
color: var(--neutral-300);
|
|
380
380
|
max-width: 30ch;
|
|
381
381
|
}
|
|
382
|
-
.
|
|
382
|
+
.atelic-ui .footer nav a {
|
|
383
383
|
display: block;
|
|
384
384
|
padding: 6px 0;
|
|
385
385
|
color: var(--neutral-200);
|
|
386
386
|
font-weight: 500;
|
|
387
387
|
}
|
|
388
|
-
.
|
|
388
|
+
.atelic-ui .footer .nap {
|
|
389
389
|
font-style: normal;
|
|
390
390
|
line-height: 1.9;
|
|
391
391
|
color: var(--neutral-200);
|
|
392
392
|
}
|
|
393
|
-
.
|
|
393
|
+
.atelic-ui .footer .nap a {
|
|
394
394
|
color: #fff;
|
|
395
395
|
font-weight: 600;
|
|
396
396
|
}
|
|
397
|
-
.
|
|
397
|
+
.atelic-ui .footer-hours {
|
|
398
398
|
font-family: var(--font-mono);
|
|
399
399
|
font-size: 0.82rem;
|
|
400
400
|
line-height: 1.9;
|
|
401
401
|
color: var(--neutral-300);
|
|
402
402
|
}
|
|
403
|
-
.
|
|
403
|
+
.atelic-ui .footer-social {
|
|
404
404
|
display: flex;
|
|
405
405
|
gap: 10px;
|
|
406
406
|
margin-top: 20px;
|
|
407
407
|
}
|
|
408
|
-
.
|
|
408
|
+
.atelic-ui .footer .footer-social-link {
|
|
409
409
|
display: inline-flex;
|
|
410
410
|
align-items: center;
|
|
411
411
|
justify-content: center;
|
|
@@ -415,11 +415,11 @@
|
|
|
415
415
|
border-radius: var(--radius-sm);
|
|
416
416
|
color: var(--neutral-300);
|
|
417
417
|
}
|
|
418
|
-
.
|
|
418
|
+
.atelic-ui .footer .footer-social-link:hover {
|
|
419
419
|
color: var(--primary-bright);
|
|
420
420
|
border-color: var(--primary-bright);
|
|
421
421
|
}
|
|
422
|
-
.
|
|
422
|
+
.atelic-ui .footer-bottom {
|
|
423
423
|
margin-top: 48px;
|
|
424
424
|
padding-top: 24px;
|
|
425
425
|
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
@@ -431,22 +431,22 @@
|
|
|
431
431
|
font-size: 0.82rem;
|
|
432
432
|
color: var(--neutral-500);
|
|
433
433
|
}
|
|
434
|
-
.
|
|
434
|
+
.atelic-ui .footer .footer-bottom a {
|
|
435
435
|
color: var(--neutral-300);
|
|
436
436
|
}
|
|
437
|
-
.
|
|
437
|
+
.atelic-ui .footer-legal {
|
|
438
438
|
display: flex;
|
|
439
439
|
gap: 20px;
|
|
440
440
|
flex-wrap: wrap;
|
|
441
441
|
}
|
|
442
442
|
@media (min-width: 760px) {
|
|
443
|
-
.
|
|
443
|
+
.atelic-ui .footer-grid {
|
|
444
444
|
grid-template-columns: 1.4fr 1fr 1fr 1.1fr;
|
|
445
445
|
gap: 48px;
|
|
446
446
|
}
|
|
447
447
|
}
|
|
448
448
|
/* Text wordmark for a site with no mark image. */
|
|
449
|
-
.
|
|
449
|
+
.atelic-ui .footer-wordmark {
|
|
450
450
|
color: #fff;
|
|
451
451
|
font-size: 1.3rem;
|
|
452
452
|
font-weight: 600;
|
|
@@ -459,7 +459,7 @@
|
|
|
459
459
|
small, and muted. Purely token themed (the hairline and hover lift derive
|
|
460
460
|
from --surface through color-mix), so it rebrands with theme.css on any
|
|
461
461
|
page it renders under, light or dark. */
|
|
462
|
-
.
|
|
462
|
+
.atelic-ui .credit-bar {
|
|
463
463
|
background: var(--surface-dark);
|
|
464
464
|
border-top: 1px solid color-mix(in srgb, var(--surface) 10%, transparent);
|
|
465
465
|
color: var(--neutral-500);
|
|
@@ -469,12 +469,12 @@
|
|
|
469
469
|
padding: 16px 20px;
|
|
470
470
|
}
|
|
471
471
|
/* biome-ignore lint/style/noDescendingSpecificity: scoped to .credit-bar, so it never meets the footer's link rules */
|
|
472
|
-
.
|
|
472
|
+
.atelic-ui .credit-bar a {
|
|
473
473
|
color: var(--neutral-300);
|
|
474
474
|
font-weight: 500;
|
|
475
475
|
}
|
|
476
476
|
/* biome-ignore lint/style/noDescendingSpecificity: scoped to .credit-bar, so it never meets the header's link rules */
|
|
477
|
-
.
|
|
477
|
+
.atelic-ui .credit-bar a:hover {
|
|
478
478
|
color: color-mix(in srgb, var(--surface) 96%, white);
|
|
479
479
|
}
|
|
480
480
|
}
|