@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.
Files changed (184) hide show
  1. package/README.md +428 -44
  2. package/bin/atelic-check-base-path.ts +5 -0
  3. package/bin/atelic-clean-sitemap.ts +5 -0
  4. package/bin/atelic-contact-canary.ts +5 -0
  5. package/bin/atelic-print-sheets.sh +1 -1
  6. package/bin/atelic-seal-document.mjs +1 -1
  7. package/bin/atelic-serve-static.ts +1 -1
  8. package/dist/gate/index.d.ts +1 -1
  9. package/dist/gate/index.js +1 -1
  10. package/dist/gate/middleware.d.ts +4 -1
  11. package/dist/gate/middleware.js +14 -5
  12. package/dist/gate/wall.d.ts +25 -0
  13. package/dist/gate/wall.js +41 -2
  14. package/dist/routing/basePath.d.ts +24 -0
  15. package/dist/routing/basePath.js +54 -0
  16. package/dist/vite/index.d.ts +3 -2
  17. package/dist/vite/index.js +3 -2
  18. package/dist/vite/marketing-config.d.ts +50 -0
  19. package/dist/vite/marketing-config.js +83 -0
  20. package/package.json +164 -5
  21. package/src/app/AppProvider.tsx +41 -0
  22. package/src/app/AuthGuard.tsx +27 -0
  23. package/src/app/CardErrorBoundary.tsx +39 -0
  24. package/src/app/ErrorFallback.tsx +39 -0
  25. package/src/app/GoogleGlyph.tsx +22 -0
  26. package/src/app/config.ts +54 -0
  27. package/src/app/configure.ts +18 -0
  28. package/src/app/context/AppContext.tsx +52 -0
  29. package/src/app/context/SidebarContext.tsx +124 -0
  30. package/src/app/context/UserContext.tsx +139 -0
  31. package/src/app/hooks/useDebounce.ts +12 -0
  32. package/src/app/hooks/useIsDesktop.ts +31 -0
  33. package/src/app/hooks/useWakeLock.ts +49 -0
  34. package/src/app/index.ts +64 -0
  35. package/src/app/layout/ActionButton.tsx +67 -0
  36. package/src/app/layout/AppLayout.tsx +110 -0
  37. package/src/app/layout/AppPage.tsx +268 -0
  38. package/src/app/layout/Breadcrumbs.tsx +57 -0
  39. package/src/app/layout/DesktopRail.tsx +168 -0
  40. package/src/app/layout/FormActionButtons.tsx +69 -0
  41. package/src/app/layout/MobileMenu.tsx +156 -0
  42. package/src/app/layout/MobileTabBar.tsx +43 -0
  43. package/src/app/layout/PageError.tsx +30 -0
  44. package/src/app/layout/PageSkeleton.tsx +65 -0
  45. package/src/app/layout/SectionCards.tsx +33 -0
  46. package/src/app/layout/UserMenu.tsx +104 -0
  47. package/src/app/layout/identity.ts +22 -0
  48. package/src/app/layout/index.ts +20 -0
  49. package/src/app/layout/nav.ts +52 -0
  50. package/src/app/lib/dates.ts +57 -0
  51. package/src/app/lib/env.ts +37 -0
  52. package/src/app/lib/format.ts +61 -0
  53. package/src/app/lib/http.ts +205 -0
  54. package/src/app/lib/lastAuth.ts +45 -0
  55. package/src/app/lib/oauth.ts +32 -0
  56. package/src/app/lib/publicRoutes.ts +33 -0
  57. package/src/app/lib/queryClient.ts +38 -0
  58. package/src/app/lib/search.ts +17 -0
  59. package/src/app/lib/session.ts +36 -0
  60. package/src/app/lib/tokenRefresh.ts +137 -0
  61. package/src/app/lib/transformKeys.ts +60 -0
  62. package/src/app/lib/units.ts +228 -0
  63. package/src/app/lib/unwrap.ts +48 -0
  64. package/src/app/lib/utils.ts +10 -0
  65. package/src/app/stores/authStore.ts +80 -0
  66. package/src/app/stores/storage.ts +40 -0
  67. package/src/app/stores/unitsStore.ts +54 -0
  68. package/src/app/types/index.ts +72 -0
  69. package/src/app/types/query.ts +11 -0
  70. package/src/app/ui/accordion.tsx +54 -0
  71. package/src/app/ui/alert-dialog.tsx +114 -0
  72. package/src/app/ui/alert.tsx +49 -0
  73. package/src/app/ui/avatar.tsx +45 -0
  74. package/src/app/ui/badge-list.tsx +51 -0
  75. package/src/app/ui/badge.tsx +33 -0
  76. package/src/app/ui/button.tsx +49 -0
  77. package/src/app/ui/callout.tsx +22 -0
  78. package/src/app/ui/card.tsx +55 -0
  79. package/src/app/ui/checkbox.tsx +26 -0
  80. package/src/app/ui/clear-button.tsx +42 -0
  81. package/src/app/ui/command.tsx +140 -0
  82. package/src/app/ui/country-dropdown.tsx +184 -0
  83. package/src/app/ui/dialog.tsx +104 -0
  84. package/src/app/ui/dropdown-menu.tsx +185 -0
  85. package/src/app/ui/form.tsx +172 -0
  86. package/src/app/ui/index.ts +36 -0
  87. package/src/app/ui/input.tsx +22 -0
  88. package/src/app/ui/label.tsx +19 -0
  89. package/src/app/ui/option-select.tsx +56 -0
  90. package/src/app/ui/pagination.tsx +90 -0
  91. package/src/app/ui/popover.tsx +29 -0
  92. package/src/app/ui/progress.tsx +25 -0
  93. package/src/app/ui/search-input.tsx +63 -0
  94. package/src/app/ui/select.tsx +151 -0
  95. package/src/app/ui/separator.tsx +24 -0
  96. package/src/app/ui/sheet.tsx +119 -0
  97. package/src/app/ui/slider.tsx +23 -0
  98. package/src/app/ui/switch.tsx +27 -0
  99. package/src/app/ui/textarea.tsx +21 -0
  100. package/src/app/ui/tooltip.tsx +32 -0
  101. package/src/artifact/ArtifactShell.tsx +2 -2
  102. package/src/artifact/Gate.tsx +2 -2
  103. package/src/artifact/Writeup.tsx +7 -7
  104. package/src/chrome/SiteShell.tsx +141 -0
  105. package/src/chrome/index.ts +2 -0
  106. package/src/components/Disclosure.tsx +80 -14
  107. package/src/components/GateLogin.tsx +1 -1
  108. package/src/components/Watermark.tsx +1 -1
  109. package/src/components/index.ts +6 -2
  110. package/src/gate/index.ts +1 -1
  111. package/src/gate/middleware.ts +17 -6
  112. package/src/gate/wall.ts +60 -2
  113. package/src/lib/basePathAudit.ts +96 -0
  114. package/src/lib/displayDate.ts +25 -0
  115. package/src/lib/honeypot.ts +11 -0
  116. package/src/lib/hours.ts +28 -0
  117. package/src/lib/sitemap.ts +34 -0
  118. package/src/lib/trackEvent.ts +26 -0
  119. package/src/lib/useOpenHeight.ts +28 -0
  120. package/src/primitives/Button.tsx +3 -1
  121. package/src/primitives/Chip.tsx +3 -1
  122. package/src/primitives/ImageFrame.tsx +48 -0
  123. package/src/primitives/ProseBlocks.tsx +67 -0
  124. package/src/primitives/QuoteCard.tsx +20 -0
  125. package/src/primitives/StarRow.tsx +37 -0
  126. package/src/primitives/TickList.tsx +24 -0
  127. package/src/primitives/index.ts +5 -0
  128. package/src/routing/BasePathProvider.tsx +47 -0
  129. package/src/routing/basePath.ts +57 -0
  130. package/src/routing/index.ts +8 -0
  131. package/src/scripts/check-base-path.ts +130 -0
  132. package/src/scripts/clean-sitemap.ts +27 -0
  133. package/src/scripts/contact-canary.ts +98 -0
  134. package/src/scripts/serve-static.ts +29 -3
  135. package/src/sections/BlogIndex.tsx +57 -0
  136. package/src/sections/BlogPost.tsx +65 -0
  137. package/src/sections/CTABanner.tsx +93 -0
  138. package/src/sections/CTASection.tsx +60 -0
  139. package/src/sections/ComparisonTable.tsx +114 -0
  140. package/src/sections/ContactForm.tsx +163 -0
  141. package/src/sections/ContactInfoCard.tsx +92 -0
  142. package/src/sections/CredentialList.tsx +28 -0
  143. package/src/sections/DeviceShowcase.tsx +39 -0
  144. package/src/sections/ExpandList.tsx +58 -0
  145. package/src/sections/FAQBrowser.tsx +283 -0
  146. package/src/sections/FeatureDetail.tsx +60 -0
  147. package/src/sections/FeatureGrid.tsx +83 -0
  148. package/src/sections/Gallery.tsx +84 -0
  149. package/src/sections/Hero.tsx +110 -0
  150. package/src/sections/HoursTable.tsx +23 -0
  151. package/src/sections/JumpRail.tsx +35 -0
  152. package/src/sections/LegalPage.tsx +43 -0
  153. package/src/sections/LocationSection.tsx +66 -0
  154. package/src/sections/Locations.tsx +71 -0
  155. package/src/sections/LogoMarquee.tsx +27 -0
  156. package/src/sections/MapEmbed.tsx +75 -0
  157. package/src/sections/MediaBand.tsx +20 -0
  158. package/src/sections/MenuList.tsx +44 -0
  159. package/src/sections/PageHero.tsx +25 -0
  160. package/src/sections/PressQuotes.tsx +51 -0
  161. package/src/sections/PricingBand.tsx +43 -0
  162. package/src/sections/PricingCard.tsx +36 -0
  163. package/src/sections/ProcessSteps.tsx +45 -0
  164. package/src/sections/ProfileCards.tsx +73 -0
  165. package/src/sections/RevealSlider.tsx +156 -0
  166. package/src/sections/ReviewCarousel.tsx +223 -0
  167. package/src/sections/ReviewWall.tsx +220 -0
  168. package/src/sections/SocialStrip.tsx +83 -0
  169. package/src/sections/SplitSection.tsx +56 -0
  170. package/src/sections/index.ts +76 -0
  171. package/src/sections/siteConfig.ts +201 -0
  172. package/src/styles/app.css +673 -0
  173. package/src/styles/artifact.css +472 -399
  174. package/src/styles/base.css +49 -47
  175. package/src/styles/chrome.css +71 -71
  176. package/src/styles/components.css +150 -140
  177. package/src/styles/gate.css +29 -29
  178. package/src/styles/primitives.css +190 -25
  179. package/src/styles/sections.css +2652 -0
  180. package/src/styles/star-rating.css +2 -2
  181. package/src/vite/index.ts +9 -2
  182. package/src/vite/marketing-config.ts +128 -0
  183. package/src/components/Collapsible.tsx +0 -43
  184. /package/src/scripts/{build-gate-payload.mjs → seal-document.mjs} +0 -0
@@ -0,0 +1,2652 @@
1
+ /* The marketing sections under src/sections, one block each, the sheets that
2
+ lived beside each component in template-marketing until 0.19.0 (ATE-643).
3
+ A section that composes another comes after it, the order the template's
4
+ bundle put them in. Every rule sits in the package's layer and answers to
5
+ .atelic-ui, so any rule a site writes outside a layer wins over it. */
6
+ @layer atelic-ui {
7
+ /* ---- BlogIndex (blog-index.css) ---- */
8
+ /* A readable stack, not a card grid. A small archive looks thinner in a
9
+ gallery than it does in a list, and these are articles to be read rather
10
+ than products to be browsed. */
11
+
12
+ .atelic-ui .bi-list {
13
+ margin: 0;
14
+ padding: 0;
15
+ list-style: none;
16
+ max-width: 760px;
17
+ }
18
+
19
+ .atelic-ui .bi-item {
20
+ border-top: 1px solid var(--hairline, rgb(0 0 0 / 10%));
21
+ }
22
+
23
+ .atelic-ui .bi-item:last-child {
24
+ border-bottom: 1px solid var(--hairline, rgb(0 0 0 / 10%));
25
+ }
26
+
27
+ /* The whole row is the target: a small archive should not make anyone aim
28
+ at a short headline link. */
29
+ .atelic-ui .bi-link {
30
+ display: block;
31
+ padding: 28px 0;
32
+ color: inherit;
33
+ text-decoration: none;
34
+ }
35
+
36
+ .atelic-ui .bi-meta {
37
+ display: block;
38
+ margin-bottom: 8px;
39
+ font-size: 0.8rem;
40
+ letter-spacing: 0.05em;
41
+ text-transform: uppercase;
42
+ color: var(--neutral-500);
43
+ }
44
+
45
+ .atelic-ui .bi-title {
46
+ margin: 0 0 10px;
47
+ font-size: 1.4rem;
48
+ line-height: 1.25;
49
+ }
50
+
51
+ .atelic-ui .bi-arrow {
52
+ margin-left: 8px;
53
+ vertical-align: baseline;
54
+ opacity: 0;
55
+ transform: translate(-4px, 2px);
56
+ transition:
57
+ opacity 0.18s ease,
58
+ transform 0.18s ease;
59
+ }
60
+
61
+ .atelic-ui .bi-link:hover .bi-arrow,
62
+ .atelic-ui .bi-link:focus-visible .bi-arrow {
63
+ opacity: 1;
64
+ transform: translate(0, 2px);
65
+ }
66
+
67
+ .atelic-ui .bi-excerpt {
68
+ margin: 0;
69
+ max-width: 62ch;
70
+ font-size: 0.98rem;
71
+ line-height: 1.65;
72
+ color: var(--neutral-700);
73
+ }
74
+
75
+ @media (prefers-reduced-motion: reduce) {
76
+ .atelic-ui .bi-arrow {
77
+ transition: none;
78
+ }
79
+ }
80
+
81
+ @media (max-width: 600px) {
82
+ .atelic-ui .bi-title {
83
+ font-size: 1.2rem;
84
+ }
85
+ }
86
+
87
+ /* ---- BlogPost (blog-post.css) ---- */
88
+ /* A single article. The title is the content, so it sits in the flow rather
89
+ than inside a hero band that would push the writing below the fold. */
90
+
91
+ .atelic-ui .bp-wrap {
92
+ max-width: 760px;
93
+ }
94
+
95
+ .atelic-ui .bp-back {
96
+ display: inline-flex;
97
+ align-items: center;
98
+ gap: 6px;
99
+ margin-bottom: 28px;
100
+ font-size: 0.85rem;
101
+ letter-spacing: 0.04em;
102
+ text-transform: uppercase;
103
+ color: var(--neutral-500);
104
+ }
105
+
106
+ .atelic-ui .bp-back:hover,
107
+ .atelic-ui .bp-back:focus-visible {
108
+ color: var(--primary);
109
+ }
110
+
111
+ .atelic-ui .bp-title {
112
+ margin: 0 0 14px;
113
+ font-size: clamp(1.9rem, 4vw, 2.6rem);
114
+ line-height: 1.15;
115
+ }
116
+
117
+ .atelic-ui .bp-meta {
118
+ display: flex;
119
+ flex-wrap: wrap;
120
+ gap: 6px 14px;
121
+ margin: 0 0 36px;
122
+ font-size: 0.85rem;
123
+ letter-spacing: 0.03em;
124
+ color: var(--neutral-500);
125
+ }
126
+
127
+ .atelic-ui .bp-author {
128
+ font-weight: 600;
129
+ color: var(--neutral-700);
130
+ }
131
+
132
+ .atelic-ui .bp-updated::before {
133
+ content: "·";
134
+ margin-right: 14px;
135
+ }
136
+
137
+ /* ---- CTABanner (cta-banner.css) ---- */
138
+ /* Mid-page full-bleed CTA banner: image backdrop, overlaid copy and actions. */
139
+ .atelic-ui .cta-banner {
140
+ position: relative;
141
+ overflow: hidden;
142
+ }
143
+ .atelic-ui .cta-banner-media {
144
+ position: absolute;
145
+ inset: 0;
146
+ width: 100%;
147
+ height: 100%;
148
+ object-fit: cover;
149
+ }
150
+ /* Token gradient backdrop when no image is provided (mirrors .hero-media-fallback). */
151
+ .atelic-ui .cta-banner-fallback {
152
+ background: linear-gradient(
153
+ 160deg,
154
+ var(--surface-dark) 0%,
155
+ var(--primary-deep) 70%,
156
+ var(--primary) 110%
157
+ );
158
+ }
159
+ .atelic-ui .cta-banner-wash {
160
+ position: absolute;
161
+ inset: 0;
162
+ }
163
+ .atelic-ui .cta-banner.dark .cta-banner-wash {
164
+ background: linear-gradient(
165
+ 90deg,
166
+ rgba(20, 15, 11, 0.85) 0%,
167
+ rgba(20, 15, 11, 0.62) 48%,
168
+ rgba(20, 15, 11, 0.22) 100%
169
+ );
170
+ }
171
+ .atelic-ui .cta-banner.light .cta-banner-wash {
172
+ background: linear-gradient(
173
+ 90deg,
174
+ color-mix(in srgb, var(--surface) 94%, transparent) 0%,
175
+ color-mix(in srgb, var(--surface) 72%, transparent) 48%,
176
+ color-mix(in srgb, var(--surface) 18%, transparent) 100%
177
+ );
178
+ }
179
+ .atelic-ui .cta-banner .wrap {
180
+ position: relative;
181
+ z-index: 1;
182
+ padding-block: clamp(56px, 9vw, 110px);
183
+ }
184
+ .atelic-ui .cta-banner-content {
185
+ max-width: 620px;
186
+ }
187
+ .atelic-ui .cta-banner-content h2 {
188
+ margin: 10px 0 0;
189
+ }
190
+ .atelic-ui .cta-banner-content .lead {
191
+ margin-top: 16px;
192
+ }
193
+ .atelic-ui .cta-banner.dark .cta-banner-content {
194
+ color: #fff;
195
+ }
196
+ .atelic-ui .cta-banner.dark .cta-banner-content .lead {
197
+ color: rgba(255, 255, 255, 0.88);
198
+ }
199
+ .atelic-ui .cta-banner-actions {
200
+ display: flex;
201
+ flex-wrap: wrap;
202
+ gap: 12px;
203
+ margin-top: 28px;
204
+ }
205
+
206
+ /* ---- CTASection (cta-section.css) ---- */
207
+ .atelic-ui .final-cta h2 {
208
+ margin: 8px 0 16px;
209
+ }
210
+ .atelic-ui .final-cta .cta-lead {
211
+ max-width: 52ch;
212
+ margin-inline: auto;
213
+ }
214
+
215
+ /* ---- ComparisonTable (comparison-table.css) ---- */
216
+ /* ComparisonTable: a graded before and after.
217
+
218
+ --cmp-stage sizes the label column, leaving the two halves exactly equal so
219
+ before and after line up against each other rather than being sized by
220
+ whichever happens to hold more words. */
221
+ .atelic-ui .comparison {
222
+ --cmp-stage: 132px;
223
+ --cmp-gutter: 16px;
224
+ }
225
+
226
+ /* The table keeps its shape and scrolls sideways rather than reflowing: a row
227
+ whose two halves no longer sit beside each other is not a comparison. */
228
+ .atelic-ui .cmp-scroll {
229
+ overflow-x: auto;
230
+ }
231
+ .atelic-ui .cmp-table {
232
+ width: 100%;
233
+ min-width: 680px;
234
+ border-collapse: collapse;
235
+ font-size: 0.92rem;
236
+ table-layout: fixed;
237
+ }
238
+ .atelic-ui .cmp-col-stage {
239
+ width: var(--cmp-stage);
240
+ }
241
+ /* Equal halves, so before and after line up with each other and with the
242
+ summaries above them. */
243
+ .atelic-ui .cmp-col-half {
244
+ width: calc((100% - var(--cmp-stage)) / 2);
245
+ }
246
+
247
+ .atelic-ui .cmp-table thead th {
248
+ font-family: var(--font-mono);
249
+ font-size: 0.72rem;
250
+ letter-spacing: 0.08em;
251
+ text-transform: uppercase;
252
+ color: var(--neutral-500);
253
+ font-weight: 500;
254
+ text-align: left;
255
+ padding: 10px var(--cmp-gutter) 10px 0;
256
+ border-bottom: 1px solid var(--hairline-strong);
257
+ }
258
+
259
+ .atelic-ui .cmp-table tbody th,
260
+ .atelic-ui .cmp-table tbody td {
261
+ padding: 14px var(--cmp-gutter) 14px 0;
262
+ border-bottom: 1px solid var(--hairline);
263
+ vertical-align: top;
264
+ text-align: left;
265
+ }
266
+ .atelic-ui .cmp-table tbody th {
267
+ color: var(--ink);
268
+ font-weight: 500;
269
+ }
270
+ .atelic-ui .cmp-table tbody td {
271
+ color: var(--ink-soft);
272
+ }
273
+ /* The after column is the one the reader is here for. */
274
+ .atelic-ui .cmp-table tbody td.is-after {
275
+ color: var(--ink);
276
+ }
277
+
278
+ /* Grade beside its reasoning, baseline aligned so the letter sits on the first
279
+ line of text however many points follow. min-width: 0 on the points track
280
+ per the library's wide-child rule: a long unbroken string in a fixed table
281
+ would otherwise push the column past the viewport. */
282
+ .atelic-ui .cmp-cell {
283
+ display: flex;
284
+ gap: 14px;
285
+ align-items: baseline;
286
+ }
287
+ .atelic-ui .cmp-points {
288
+ flex: 1 1 auto;
289
+ min-width: 0;
290
+ }
291
+ .atelic-ui .cmp-grade {
292
+ flex: 0 0 auto;
293
+ font-family: var(--font-mono);
294
+ line-height: 1.2;
295
+ white-space: nowrap;
296
+ color: var(--neutral-500);
297
+ }
298
+ .atelic-ui .cmp-grade.is-letter {
299
+ font-size: 1.15rem;
300
+ font-weight: 700;
301
+ min-width: 1.1em;
302
+ }
303
+ .atelic-ui .cmp-grade.is-note {
304
+ font-size: 0.72rem;
305
+ font-weight: 500;
306
+ }
307
+ .atelic-ui .cmp-grade.is-moved {
308
+ color: var(--primary);
309
+ }
310
+
311
+ /* Points sit flush with single-point cells, so every row starts on the same
312
+ vertical line whether it carries one item or four. */
313
+ .atelic-ui .cmp-points ul {
314
+ margin: 0;
315
+ padding: 0;
316
+ list-style: none;
317
+ }
318
+ .atelic-ui .cmp-points li + li {
319
+ margin-top: 8px;
320
+ }
321
+
322
+ .atelic-ui .cmp-footnote {
323
+ color: var(--neutral-500);
324
+ font-size: 0.86rem;
325
+ margin-top: 14px;
326
+ }
327
+
328
+ /* ---- ContactForm (contact-form.css) ---- */
329
+ /* Contact page layout. */
330
+ .atelic-ui .contact-grid {
331
+ display: grid;
332
+ gap: 40px;
333
+ }
334
+ @media (min-width: 920px) {
335
+ .atelic-ui .contact-grid {
336
+ grid-template-columns: 1fr 1fr;
337
+ gap: 56px;
338
+ }
339
+ }
340
+ /* Contact form fields. */
341
+ .atelic-ui .field {
342
+ display: flex;
343
+ flex-direction: column;
344
+ gap: 7px;
345
+ margin-bottom: 18px;
346
+ }
347
+ .atelic-ui .field label {
348
+ font-family: var(--font-mono);
349
+ font-size: 0.74rem;
350
+ letter-spacing: 0.1em;
351
+ text-transform: uppercase;
352
+ color: var(--neutral-600);
353
+ }
354
+ .atelic-ui .field input,
355
+ .atelic-ui .field textarea,
356
+ .atelic-ui .field select {
357
+ font: inherit;
358
+ padding: 14px 16px;
359
+ border-radius: var(--radius-md);
360
+ border: 1.5px solid var(--neutral-200);
361
+ background: var(--card);
362
+ color: var(--ink);
363
+ transition:
364
+ border-color 0.15s,
365
+ box-shadow 0.15s;
366
+ width: 100%;
367
+ }
368
+ .atelic-ui .field input:focus,
369
+ .atelic-ui .field textarea:focus,
370
+ .atelic-ui .field select:focus {
371
+ outline: none;
372
+ border-color: var(--primary);
373
+ box-shadow: 0 0 0 4px var(--primary-focus-ring);
374
+ }
375
+ .atelic-ui .field textarea {
376
+ min-height: 130px;
377
+ resize: vertical;
378
+ }
379
+ /* Replace the inconsistent native select arrow with a styled chevron. */
380
+ .atelic-ui .field select {
381
+ appearance: none;
382
+ -webkit-appearance: none;
383
+ padding-right: 44px;
384
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2364748b' d='M6 8 0 2 1.4.6 6 5.2 10.6.6 12 2z'/%3E%3C/svg%3E");
385
+ background-repeat: no-repeat;
386
+ background-position: right 16px center;
387
+ }
388
+ .atelic-ui .field .err {
389
+ color: var(--primary-deep);
390
+ font-size: 0.82rem;
391
+ display: none;
392
+ }
393
+ .atelic-ui .field.invalid .err {
394
+ display: block;
395
+ }
396
+ .atelic-ui .field.invalid input,
397
+ .atelic-ui .field.invalid textarea {
398
+ border-color: var(--primary-deep);
399
+ }
400
+ .atelic-ui .form-success {
401
+ background: var(--secondary-tint);
402
+ border: 1.5px solid var(--secondary-soft);
403
+ color: var(--secondary);
404
+ padding: 20px 22px;
405
+ border-radius: var(--radius-md);
406
+ font-weight: 600;
407
+ margin-bottom: 18px;
408
+ }
409
+ .atelic-ui .form-error {
410
+ background: var(--primary-tint);
411
+ border: 1.5px solid var(--primary);
412
+ color: var(--primary-deep);
413
+ padding: 20px 22px;
414
+ border-radius: var(--radius-md);
415
+ font-weight: 600;
416
+ margin-bottom: 18px;
417
+ }
418
+ /* Honeypot: off-canvas rather than display:none so naive bots still fill it. */
419
+ .atelic-ui .hp-field {
420
+ position: absolute;
421
+ left: -9999px;
422
+ width: 1px;
423
+ height: 1px;
424
+ overflow: hidden;
425
+ }
426
+
427
+ /* ---- ContactInfoCard (contact-info-card.css) ---- */
428
+ .atelic-ui .contact-info-card {
429
+ background: var(--surface-dark);
430
+ color: var(--surface);
431
+ border-radius: var(--radius-lg);
432
+ padding: clamp(28px, 5vw, 40px);
433
+ }
434
+ .atelic-ui .contact-info-card h3 {
435
+ color: #fff;
436
+ }
437
+ .atelic-ui .contact-info-card .ci-rows {
438
+ margin-top: 18px;
439
+ }
440
+ .atelic-ui .contact-info-card .ci-row {
441
+ display: flex;
442
+ gap: 14px;
443
+ align-items: flex-start;
444
+ padding: 16px 0;
445
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
446
+ }
447
+ .atelic-ui .contact-info-card .ci-row.last {
448
+ border-bottom: none;
449
+ }
450
+ .atelic-ui .contact-info-card .ci-row .k {
451
+ font-family: var(--font-mono);
452
+ font-size: 0.72rem;
453
+ letter-spacing: 0.1em;
454
+ text-transform: uppercase;
455
+ color: var(--primary-bright);
456
+ flex: 0 0 84px;
457
+ padding-top: 3px;
458
+ }
459
+ .atelic-ui .contact-info-card a {
460
+ color: #fff;
461
+ font-weight: 600;
462
+ }
463
+ .atelic-ui .contact-info-card .ci-row .v {
464
+ color: var(--neutral-200);
465
+ /* A long email address breaks inside its column on a phone rather than
466
+ pushing the card, and the page, wider than the screen (found moving
467
+ the card into the package, 0.19.0). */
468
+ min-width: 0;
469
+ overflow-wrap: anywhere;
470
+ }
471
+
472
+ /* ---- CredentialList (credential-list.css) ---- */
473
+ .atelic-ui .cert-list {
474
+ display: grid;
475
+ gap: 14px;
476
+ margin-top: 8px;
477
+ }
478
+ /* Two-up on wide screens so a long credential stack stays compact;
479
+ single column below 900px keeps each card full-width on mobile. */
480
+ @media (min-width: 900px) {
481
+ .atelic-ui .cert-list {
482
+ grid-template-columns: 1fr 1fr;
483
+ align-items: stretch;
484
+ }
485
+ }
486
+ .atelic-ui .cert-list li {
487
+ display: flex;
488
+ gap: 14px;
489
+ align-items: flex-start;
490
+ padding: 16px 18px;
491
+ background: var(--card);
492
+ border-radius: var(--radius-md);
493
+ box-shadow: var(--shadow-sm);
494
+ border: 1px solid var(--hairline);
495
+ }
496
+ .atelic-ui .cert-list .ci {
497
+ flex: 0 0 auto;
498
+ font-family: var(--font-mono);
499
+ font-size: 0.78rem;
500
+ color: var(--primary);
501
+ font-weight: 600;
502
+ padding-top: 2px;
503
+ }
504
+ .atelic-ui .cert-list strong {
505
+ display: block;
506
+ }
507
+ .atelic-ui .cert-list small {
508
+ color: var(--neutral-600);
509
+ font-size: 0.9rem;
510
+ }
511
+
512
+ /* ---- DeviceShowcase (device-showcase.css) ---- */
513
+ /* Device mockups: a desktop browser window with a phone overlapping its
514
+ lower-left. Tokens only. */
515
+ .atelic-ui .devices {
516
+ position: relative;
517
+ width: 100%;
518
+ max-width: 640px;
519
+ padding-bottom: 42px;
520
+ padding-left: 40px;
521
+ perspective: 1600px;
522
+ }
523
+
524
+ /* Desktop browser window */
525
+ .atelic-ui .dv-desktop {
526
+ border-radius: 14px;
527
+ overflow: hidden;
528
+ background: var(--card);
529
+ box-shadow: var(--shadow-lg);
530
+ border: 1px solid var(--hairline-strong);
531
+ }
532
+ .atelic-ui .dv-bar {
533
+ height: 34px;
534
+ background: var(--surface-alt);
535
+ display: flex;
536
+ align-items: center;
537
+ gap: 7px;
538
+ padding: 0 14px;
539
+ border-bottom: 1px solid var(--hairline-strong);
540
+ }
541
+ .atelic-ui .dv-bar i {
542
+ width: 10px;
543
+ height: 10px;
544
+ border-radius: 50%;
545
+ background: var(--neutral-300);
546
+ }
547
+ .atelic-ui .dv-screen {
548
+ line-height: 0;
549
+ }
550
+ .atelic-ui .dv-screen img {
551
+ width: 100%;
552
+ height: auto;
553
+ display: block;
554
+ }
555
+
556
+ /* Phone, overlapping the lower-left corner, tilted out for a 3D feel. */
557
+ .atelic-ui .dv-phone {
558
+ position: absolute;
559
+ left: 0;
560
+ bottom: 0;
561
+ width: 30%;
562
+ max-width: 172px;
563
+ border-radius: 26px;
564
+ border: 5px solid var(--ink);
565
+ background: var(--ink);
566
+ overflow: hidden;
567
+ line-height: 0;
568
+ transform: rotateY(-20deg) rotateX(3deg) rotateZ(-1deg);
569
+ transform-origin: center center;
570
+ box-shadow: -22px 26px 46px rgba(20, 16, 12, 0.4);
571
+ }
572
+ .atelic-ui .dv-phone img {
573
+ width: 100%;
574
+ height: auto;
575
+ display: block;
576
+ border-radius: 21px;
577
+ }
578
+
579
+ @media (max-width: 900px) {
580
+ .atelic-ui .devices {
581
+ max-width: 460px;
582
+ margin-inline: auto;
583
+ padding-left: 20px;
584
+ }
585
+ }
586
+
587
+ /* ---- ExpandList (expand-list.css) ---- */
588
+ /* ExpandList: numbered fold-out rows — mono index, title, chevron, and a
589
+ collapsing body. The light sibling of the FAQBrowser's card rows. */
590
+ .atelic-ui .expand-list {
591
+ border-top: 1px solid var(--hairline-strong);
592
+ }
593
+ .atelic-ui .xl-row {
594
+ border-bottom: 1px solid var(--hairline-strong);
595
+ }
596
+ .atelic-ui .xl-head {
597
+ display: flex;
598
+ align-items: baseline;
599
+ gap: 18px;
600
+ width: 100%;
601
+ padding: 18px 2px;
602
+ background: none;
603
+ border: 0;
604
+ cursor: pointer;
605
+ text-align: left;
606
+ font: inherit;
607
+ color: var(--ink);
608
+ }
609
+ .atelic-ui .xl-num {
610
+ font-family: var(--font-mono);
611
+ font-size: 0.78rem;
612
+ font-weight: 500;
613
+ color: var(--primary);
614
+ letter-spacing: 0.08em;
615
+ }
616
+ .atelic-ui .xl-title {
617
+ flex: 1;
618
+ min-width: 0;
619
+ font-weight: 600;
620
+ font-size: 1.02rem;
621
+ }
622
+ .atelic-ui .xl-chevron {
623
+ flex-shrink: 0;
624
+ align-self: center;
625
+ color: var(--neutral-500);
626
+ transition: transform 0.25s ease;
627
+ }
628
+ .atelic-ui .xl-row.open .xl-chevron {
629
+ transform: rotate(180deg);
630
+ }
631
+ .atelic-ui .xl-body {
632
+ overflow: hidden;
633
+ max-height: 0;
634
+ transition: max-height 0.3s ease;
635
+ }
636
+ .atelic-ui .xl-body-inner {
637
+ padding: 0 2px 20px;
638
+ padding-left: calc(0.78rem * 2 + 18px + 2px);
639
+ color: var(--ink-soft);
640
+ max-width: 68ch;
641
+ }
642
+ @media (prefers-reduced-motion: reduce) {
643
+ .atelic-ui .xl-chevron,
644
+ .atelic-ui .xl-body {
645
+ transition: none;
646
+ }
647
+ }
648
+ @media (max-width: 560px) {
649
+ .atelic-ui .xl-body-inner {
650
+ padding-left: 2px;
651
+ }
652
+ }
653
+
654
+ /* ---- JumpRail (jump-rail.css) ---- */
655
+ /* Jump rail: the FAQ's categories, and any long page's stops. Sticky under
656
+ the fixed header, one tab per section anchor, the active one underlined in
657
+ the primary by scroll spy. */
658
+ .atelic-ui .jump-rail {
659
+ position: sticky;
660
+ top: var(--nav-height);
661
+ z-index: 90;
662
+ background: color-mix(in srgb, var(--surface) 92%, transparent);
663
+ backdrop-filter: blur(10px);
664
+ -webkit-backdrop-filter: blur(10px);
665
+ border-bottom: 1px solid var(--hairline-strong);
666
+ }
667
+ .atelic-ui .jump-rail-inner {
668
+ display: flex;
669
+ gap: 26px;
670
+ overflow-x: auto;
671
+ scrollbar-width: none;
672
+ }
673
+ .atelic-ui .jump-rail-inner::-webkit-scrollbar {
674
+ display: none;
675
+ }
676
+ .atelic-ui .jump-rail a {
677
+ flex: 0 0 auto;
678
+ padding: 15px 0 13px;
679
+ font-weight: 600;
680
+ font-size: 0.95rem;
681
+ color: var(--ink-soft);
682
+ border-bottom: 2px solid transparent;
683
+ transition:
684
+ color 0.15s,
685
+ border-color 0.15s;
686
+ }
687
+ .atelic-ui .jump-rail a:hover {
688
+ color: var(--ink);
689
+ }
690
+ .atelic-ui .jump-rail a.active {
691
+ color: var(--primary);
692
+ border-bottom-color: var(--primary);
693
+ }
694
+
695
+ /* ---- PageHero (page-hero.css) ---- */
696
+ .atelic-ui .page-hero {
697
+ padding-top: calc(var(--nav-height) + clamp(40px, 7vw, 86px));
698
+ padding-bottom: clamp(28px, 5vw, 60px);
699
+ background: var(--surface-alt);
700
+ }
701
+ .atelic-ui .page-hero h1 {
702
+ font-size: clamp(2.4rem, 7vw, 4.2rem);
703
+ margin: 16px 0 0;
704
+ }
705
+ .atelic-ui .page-hero .lead {
706
+ margin-top: 22px;
707
+ max-width: 56ch;
708
+ }
709
+
710
+ /* ---- FAQBrowser (faq-browser.css) ---- */
711
+ /* =================================================================
712
+ FAQ BROWSER — help hero search, sticky category tabs, card groups
713
+ ================================================================= */
714
+
715
+ /* ---- Find block in the page hero ----
716
+ The page header stays left-aligned like every other section header on
717
+ the site; the find block (search pill + browse-all beneath it) centers
718
+ on a comfortable reading width so the input never runs the full page. */
719
+ .atelic-ui .faq-find {
720
+ max-width: 34rem;
721
+ margin: 30px auto 0;
722
+ text-align: center;
723
+ }
724
+ .atelic-ui .faq-search {
725
+ position: relative;
726
+ display: flex;
727
+ align-items: center;
728
+ margin: 0;
729
+ background: var(--card);
730
+ border: 1.5px solid var(--neutral-200);
731
+ border-radius: var(--radius-pill);
732
+ padding: 0 20px;
733
+ transition:
734
+ border-color 0.15s,
735
+ box-shadow 0.15s;
736
+ }
737
+ .atelic-ui .faq-search:focus-within {
738
+ border-color: var(--primary);
739
+ box-shadow: 0 0 0 4px var(--primary-focus-ring);
740
+ }
741
+ .atelic-ui .faq-search > svg {
742
+ width: 18px;
743
+ height: 18px;
744
+ flex: 0 0 auto;
745
+ color: var(--neutral-500);
746
+ }
747
+ .atelic-ui .faq-search input {
748
+ flex: 1;
749
+ font: inherit;
750
+ font-size: 1rem;
751
+ padding: 15px 14px;
752
+ border: none;
753
+ background: none;
754
+ color: var(--ink);
755
+ outline: none;
756
+ min-width: 0;
757
+ }
758
+ .atelic-ui .faq-search input::placeholder {
759
+ color: var(--neutral-500);
760
+ }
761
+ .atelic-ui .faq-search input::-webkit-search-cancel-button {
762
+ display: none;
763
+ }
764
+ .atelic-ui .faq-search-clear {
765
+ flex: 0 0 auto;
766
+ width: 28px;
767
+ height: 28px;
768
+ border-radius: 50%;
769
+ display: grid;
770
+ place-items: center;
771
+ font-size: 1.2rem;
772
+ line-height: 1;
773
+ color: var(--neutral-500);
774
+ }
775
+ .atelic-ui .faq-search-clear:hover {
776
+ color: var(--ink);
777
+ background: var(--surface-alt);
778
+ }
779
+ .atelic-ui .faq-browse-all {
780
+ display: inline-block;
781
+ margin-top: 16px;
782
+ font-weight: 700;
783
+ font-size: 0.95rem;
784
+ color: var(--primary);
785
+ }
786
+
787
+ /* ---- Sticky category tabs ---- */
788
+ /* The sticky category tab bar is the shared jump rail now; its styles
789
+ live in jump-rail.css beside JumpRail. */
790
+
791
+ /* ---- Category sections ---- */
792
+ .atelic-ui .faq-cat {
793
+ padding-block: clamp(20px, 2.5vw, 32px);
794
+ scroll-margin-top: calc(var(--nav-height) + 56px);
795
+ }
796
+ .atelic-ui .faq-cats {
797
+ padding-block: clamp(8px, 1.5vw, 16px) clamp(16px, 2.5vw, 32px);
798
+ }
799
+ /* Category head: stacked on small screens (description, then the utility
800
+ links) so the description keeps its full measure; from 720px up the
801
+ description sits left and the utilities right, bottom-aligned so a
802
+ wrapping description keeps the links pinned just above the questions. */
803
+ .atelic-ui .faq-cat-head {
804
+ display: flex;
805
+ flex-direction: column;
806
+ align-items: flex-start;
807
+ gap: 14px;
808
+ margin: 10px 0 14px;
809
+ }
810
+ .atelic-ui .faq-cat-desc {
811
+ margin: 0;
812
+ color: var(--ink-soft);
813
+ max-width: 60ch;
814
+ }
815
+ .atelic-ui .faq-utils {
816
+ display: flex;
817
+ gap: 22px;
818
+ flex: 0 0 auto;
819
+ white-space: nowrap;
820
+ }
821
+ @media (min-width: 720px) {
822
+ .atelic-ui .faq-cat-head {
823
+ flex-direction: row;
824
+ justify-content: space-between;
825
+ align-items: flex-end;
826
+ gap: 24px;
827
+ }
828
+ .atelic-ui .faq-utils {
829
+ margin-left: auto;
830
+ }
831
+ }
832
+ .atelic-ui .faq-util {
833
+ font-family: var(--font-mono);
834
+ font-size: 0.76rem;
835
+ letter-spacing: 0.06em;
836
+ text-transform: uppercase;
837
+ color: var(--neutral-600);
838
+ padding: 4px 0;
839
+ }
840
+ .atelic-ui .faq-util:hover {
841
+ color: var(--ink);
842
+ }
843
+ .atelic-ui .faq-util:first-child {
844
+ text-decoration: underline;
845
+ text-underline-offset: 3px;
846
+ }
847
+
848
+ /* ---- Card group of question rows ---- */
849
+ .atelic-ui .faq-group {
850
+ background: var(--card);
851
+ border: 1px solid var(--hairline-strong);
852
+ border-radius: var(--radius-md);
853
+ box-shadow: var(--shadow-sm);
854
+ overflow: hidden;
855
+ }
856
+ .atelic-ui .faq-row {
857
+ border-top: 1px solid var(--hairline);
858
+ }
859
+ .atelic-ui .faq-row:first-child {
860
+ border-top: none;
861
+ }
862
+ .atelic-ui .faq-row-head {
863
+ display: flex;
864
+ align-items: center;
865
+ gap: 12px;
866
+ padding: 0 18px 0 0;
867
+ }
868
+ .atelic-ui .faq-row-q {
869
+ flex: 1;
870
+ text-align: left;
871
+ font-weight: 700;
872
+ font-size: 1.02rem;
873
+ letter-spacing: -0.01em;
874
+ padding: 20px 0 20px 22px;
875
+ min-width: 0;
876
+ }
877
+ .atelic-ui .faq-row-icons {
878
+ display: flex;
879
+ align-items: center;
880
+ gap: 4px;
881
+ flex: 0 0 auto;
882
+ }
883
+ .atelic-ui .faq-icon-btn {
884
+ width: 34px;
885
+ height: 34px;
886
+ border-radius: 50%;
887
+ display: grid;
888
+ place-items: center;
889
+ color: var(--neutral-500);
890
+ transition:
891
+ color 0.15s,
892
+ background 0.15s,
893
+ transform 0.25s;
894
+ }
895
+ .atelic-ui .faq-icon-btn svg {
896
+ width: 16px;
897
+ height: 16px;
898
+ }
899
+ .atelic-ui .faq-icon-btn:hover {
900
+ color: var(--ink);
901
+ background: var(--surface-alt);
902
+ }
903
+ .atelic-ui .faq-link-btn {
904
+ color: var(--primary);
905
+ }
906
+ .atelic-ui .faq-link-btn.copied {
907
+ color: var(--secondary);
908
+ }
909
+ .atelic-ui .faq-row.open .faq-chevron {
910
+ transform: rotate(180deg);
911
+ }
912
+ .atelic-ui .faq-row-a {
913
+ max-height: 0;
914
+ overflow: hidden;
915
+ transition: max-height 0.35s ease;
916
+ }
917
+ .atelic-ui .faq-row-a-inner {
918
+ padding: 2px 22px 24px;
919
+ color: var(--ink-soft);
920
+ line-height: 1.65;
921
+ }
922
+ .atelic-ui .faq-answer-cta {
923
+ display: inline-flex;
924
+ align-items: center;
925
+ gap: 6px;
926
+ margin-top: 14px;
927
+ font-weight: 700;
928
+ font-size: 0.95rem;
929
+ color: var(--primary);
930
+ }
931
+
932
+ /* ---- Per-category CTA line ---- */
933
+ .atelic-ui .faq-cat-cta {
934
+ display: inline-flex;
935
+ align-items: center;
936
+ gap: 6px;
937
+ margin-top: 20px;
938
+ font-weight: 700;
939
+ font-size: 0.95rem;
940
+ color: var(--primary);
941
+ }
942
+ .atelic-ui .faq-cat-cta .arrow,
943
+ .atelic-ui .faq-answer-cta .arrow {
944
+ transition: transform 0.2s ease;
945
+ }
946
+ .atelic-ui .faq-cat-cta:hover .arrow,
947
+ .atelic-ui .faq-answer-cta:hover .arrow {
948
+ transform: translateX(3px);
949
+ }
950
+
951
+ /* ---- Empty search state ---- */
952
+ .atelic-ui .faq-empty {
953
+ padding-block: clamp(40px, 6vw, 72px);
954
+ text-align: center;
955
+ color: var(--ink-soft);
956
+ }
957
+ .atelic-ui .faq-empty a {
958
+ color: var(--primary);
959
+ font-weight: 700;
960
+ }
961
+
962
+ /* ---- FeatureDetail (feature-detail.css) ---- */
963
+ /* Alternating copy-and-media feature rows. */
964
+ .atelic-ui .feature-detail {
965
+ display: grid;
966
+ gap: 36px;
967
+ align-items: center;
968
+ padding-block: clamp(40px, 6vw, 72px);
969
+ border-top: 1px solid var(--neutral-200);
970
+ scroll-margin-top: calc(var(--nav-height) + 20px);
971
+ }
972
+ .atelic-ui .feature-detail:first-of-type {
973
+ border-top: none;
974
+ }
975
+ @media (min-width: 900px) {
976
+ .atelic-ui .feature-detail {
977
+ grid-template-columns: 1fr 1fr;
978
+ gap: 64px;
979
+ }
980
+ .atelic-ui .feature-detail.flip .feature-detail-media {
981
+ order: -1;
982
+ }
983
+ }
984
+ .atelic-ui .feature-detail .feature-num {
985
+ display: block;
986
+ font-family: var(--font-mono);
987
+ font-size: 0.8rem;
988
+ color: var(--primary);
989
+ letter-spacing: 0.1em;
990
+ margin-bottom: 10px;
991
+ }
992
+ .atelic-ui .feature-detail h2 {
993
+ font-size: clamp(1.8rem, 4vw, 2.6rem);
994
+ }
995
+ .atelic-ui .feature-detail .tag-row {
996
+ gap: 8px;
997
+ margin: 18px 0 20px;
998
+ }
999
+ .atelic-ui .feature-detail .detail-ticks {
1000
+ margin-top: 18px;
1001
+ }
1002
+
1003
+ /* ---- FeatureGrid (feature-grid.css) ---- */
1004
+ /* Numbered feature/service card grid. */
1005
+ .atelic-ui .feature-grid {
1006
+ display: grid;
1007
+ gap: 16px;
1008
+ margin-top: 44px;
1009
+ grid-template-columns: 1fr;
1010
+ }
1011
+ @media (min-width: 560px) {
1012
+ .atelic-ui .feature-grid {
1013
+ grid-template-columns: 1fr 1fr;
1014
+ }
1015
+ }
1016
+ @media (min-width: 980px) {
1017
+ .atelic-ui .feature-grid {
1018
+ /* Cards per row; the component sets --fg-cols from its `columns` prop. */
1019
+ grid-template-columns: repeat(var(--fg-cols, 4), 1fr);
1020
+ }
1021
+ }
1022
+ .atelic-ui .feature-card {
1023
+ background: var(--card);
1024
+ border-radius: var(--radius-lg);
1025
+ padding: 28px 24px 24px;
1026
+ box-shadow: var(--shadow-sm);
1027
+ border: 1px solid var(--hairline);
1028
+ display: flex;
1029
+ flex-direction: column;
1030
+ min-height: 240px;
1031
+ transition:
1032
+ transform 0.25s ease,
1033
+ box-shadow 0.25s ease;
1034
+ }
1035
+ .atelic-ui .feature-card:hover {
1036
+ transform: translateY(-4px);
1037
+ box-shadow: var(--shadow-md);
1038
+ }
1039
+ .atelic-ui .feature-num {
1040
+ font-family: var(--font-mono);
1041
+ font-size: 0.8rem;
1042
+ color: var(--primary);
1043
+ letter-spacing: 0.1em;
1044
+ }
1045
+ .atelic-ui .feature-card h3 {
1046
+ margin: 14px 0 10px;
1047
+ }
1048
+ .atelic-ui .feature-card p {
1049
+ color: var(--ink-soft);
1050
+ font-size: 0.98rem;
1051
+ flex: 1;
1052
+ }
1053
+ .atelic-ui .feature-link {
1054
+ margin-top: 18px;
1055
+ font-weight: 700;
1056
+ color: var(--primary);
1057
+ font-size: 0.95rem;
1058
+ display: inline-flex;
1059
+ align-items: center;
1060
+ gap: 6px;
1061
+ }
1062
+ .atelic-ui .feature-link .arrow {
1063
+ transition: transform 0.2s ease;
1064
+ }
1065
+ .atelic-ui .feature-card:hover .feature-link .arrow {
1066
+ transform: translateX(4px);
1067
+ }
1068
+
1069
+ /* ---- Gallery (gallery.css) ---- */
1070
+ /* Gallery — a captioned wall of the client's own work photos. */
1071
+
1072
+ .atelic-ui .gallery-section h2 {
1073
+ margin: 10px 0 14px;
1074
+ }
1075
+
1076
+ .atelic-ui .gallery-grid {
1077
+ list-style: none;
1078
+ margin: 34px 0 0;
1079
+ padding: 0;
1080
+ display: grid;
1081
+ grid-template-columns: minmax(0, 1fr);
1082
+ gap: 22px;
1083
+ }
1084
+
1085
+ @media (min-width: 620px) {
1086
+ .atelic-ui .gallery-grid {
1087
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1088
+ }
1089
+ }
1090
+
1091
+ @media (min-width: 960px) {
1092
+ .atelic-ui .gallery-grid.cols-3 {
1093
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1094
+ }
1095
+ }
1096
+
1097
+ .atelic-ui .gallery-item figure {
1098
+ margin: 0;
1099
+ }
1100
+
1101
+ .atelic-ui .gallery-frame {
1102
+ overflow: hidden;
1103
+ border-radius: var(--radius-md);
1104
+ background: var(--surface-inset);
1105
+ aspect-ratio: 4 / 3;
1106
+ box-shadow: var(--shadow-sm);
1107
+ }
1108
+
1109
+ .atelic-ui .gallery-frame img {
1110
+ width: 100%;
1111
+ height: 100%;
1112
+ object-fit: cover;
1113
+ display: block;
1114
+ }
1115
+
1116
+ /* A tile with no photograph yet borrows the shared placeholder block. Both
1117
+ selectors carry two classes, so the radius is restated at three to beat
1118
+ `.ph`'s own regardless of bundle order. */
1119
+ .atelic-ui .gallery-frame.ph {
1120
+ border-radius: var(--radius-md);
1121
+ box-shadow: inset 0 0 0 1px rgba(138, 124, 104, 0.2);
1122
+ }
1123
+
1124
+ .atelic-ui .gallery-item figcaption {
1125
+ margin-top: 12px;
1126
+ font-size: 0.92rem;
1127
+ line-height: 1.5;
1128
+ color: var(--ink-soft);
1129
+ }
1130
+
1131
+ .atelic-ui .gallery-footnote {
1132
+ margin-top: 28px;
1133
+ font-size: 0.85rem;
1134
+ }
1135
+
1136
+ /* ---- Hero (hero.css) ---- */
1137
+ /* Full-bleed image hero. */
1138
+ .atelic-ui .hero {
1139
+ position: relative;
1140
+ min-height: 100svh;
1141
+ display: flex;
1142
+ align-items: flex-end;
1143
+ color: #fff;
1144
+ overflow: hidden;
1145
+ }
1146
+ .atelic-ui .hero-media {
1147
+ position: absolute;
1148
+ inset: 0;
1149
+ z-index: 0;
1150
+ }
1151
+ .atelic-ui .hero-media img {
1152
+ width: 100%;
1153
+ height: 100%;
1154
+ object-fit: cover;
1155
+ object-position: center 35%;
1156
+ }
1157
+ .atelic-ui .hero-media-fallback {
1158
+ width: 100%;
1159
+ height: 100%;
1160
+ background: linear-gradient(
1161
+ 160deg,
1162
+ var(--surface-dark) 0%,
1163
+ var(--primary-deep) 70%,
1164
+ var(--primary) 110%
1165
+ );
1166
+ }
1167
+ .atelic-ui .hero-scrim {
1168
+ position: absolute;
1169
+ inset: 0;
1170
+ background: linear-gradient(
1171
+ 180deg,
1172
+ rgba(20, 15, 11, 0.45) 0%,
1173
+ rgba(20, 15, 11, 0.12) 30%,
1174
+ rgba(20, 15, 11, 0.55) 78%,
1175
+ rgba(20, 15, 11, 0.86) 100%
1176
+ );
1177
+ }
1178
+ .atelic-ui .hero-content {
1179
+ position: relative;
1180
+ z-index: 2;
1181
+ padding-bottom: clamp(48px, 9vh, 110px);
1182
+ padding-top: calc(var(--nav-height) + 30px);
1183
+ }
1184
+ .atelic-ui .hero h1 {
1185
+ color: #fff;
1186
+ margin: 18px 0 0;
1187
+ text-shadow: 0 2px 30px rgba(0, 0, 0, 0.25);
1188
+ }
1189
+ .atelic-ui .hero h1 .serif {
1190
+ color: var(--primary-bright);
1191
+ }
1192
+ .atelic-ui .hero-sub {
1193
+ font-size: clamp(1.05rem, 2.2vw, 1.35rem);
1194
+ max-width: 52ch;
1195
+ margin-top: 22px;
1196
+ color: rgba(255, 255, 255, 0.92);
1197
+ line-height: 1.55;
1198
+ }
1199
+ .atelic-ui .hero-trust {
1200
+ display: flex;
1201
+ flex-wrap: wrap;
1202
+ gap: 14px 36px;
1203
+ margin-top: 40px;
1204
+ }
1205
+ .atelic-ui .hero-trust li {
1206
+ display: flex;
1207
+ flex-direction: column;
1208
+ }
1209
+ .atelic-ui .hero-trust strong {
1210
+ font-size: 1.7rem;
1211
+ font-weight: 800;
1212
+ letter-spacing: -0.02em;
1213
+ line-height: 1;
1214
+ }
1215
+ .atelic-ui .hero-trust span {
1216
+ font-family: var(--font-mono);
1217
+ font-size: 0.72rem;
1218
+ letter-spacing: 0.04em;
1219
+ color: rgba(255, 255, 255, 0.72);
1220
+ margin-top: 5px;
1221
+ text-transform: uppercase;
1222
+ }
1223
+ .atelic-ui .hero-scroll {
1224
+ position: absolute;
1225
+ right: var(--gutter);
1226
+ bottom: 26px;
1227
+ z-index: 2;
1228
+ width: 46px;
1229
+ height: 46px;
1230
+ border-radius: 50%;
1231
+ display: none;
1232
+ align-items: center;
1233
+ justify-content: center;
1234
+ font-size: 1.1rem;
1235
+ color: #fff;
1236
+ box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.4);
1237
+ animation: bob 2.4s ease-in-out infinite;
1238
+ }
1239
+ @keyframes bob {
1240
+ 0%,
1241
+ 100% {
1242
+ transform: translateY(0);
1243
+ }
1244
+ 50% {
1245
+ transform: translateY(6px);
1246
+ }
1247
+ }
1248
+ @media (min-width: 900px) {
1249
+ .atelic-ui .hero-scroll {
1250
+ display: inline-flex;
1251
+ }
1252
+ }
1253
+
1254
+ /* ---- HoursTable (hours-table.css) ---- */
1255
+ .atelic-ui .hours-row {
1256
+ display: flex;
1257
+ justify-content: space-between;
1258
+ gap: 16px;
1259
+ padding: 9px 0;
1260
+ border-bottom: 1px dashed var(--neutral-200);
1261
+ font-size: 0.95rem;
1262
+ }
1263
+ .atelic-ui .hours-row.closed {
1264
+ color: var(--neutral-500);
1265
+ }
1266
+ .atelic-ui .hours-row .day {
1267
+ font-weight: 600;
1268
+ }
1269
+ .atelic-ui .hours-row .time {
1270
+ font-family: var(--font-mono);
1271
+ font-size: 0.85rem;
1272
+ }
1273
+
1274
+ /* ---- LegalPage (legal-page.css) ---- */
1275
+ /* Legal documents share their body styling with every other ported document
1276
+ (see primitives/prose-blocks.css). Only the dateline is particular to them:
1277
+ a legal page leads with when it was last revised, because that is the first
1278
+ thing anyone checking one wants to know. */
1279
+
1280
+ .atelic-ui .legal-updated {
1281
+ margin: 0 0 32px;
1282
+ font-size: 0.85rem;
1283
+ letter-spacing: 0.04em;
1284
+ text-transform: uppercase;
1285
+ color: var(--neutral-500);
1286
+ }
1287
+
1288
+ /* ---- MapEmbed (map-embed.css) ---- */
1289
+ .atelic-ui .map-frame {
1290
+ border-radius: var(--radius-lg);
1291
+ overflow: hidden;
1292
+ box-shadow: var(--shadow-md);
1293
+ aspect-ratio: 1 / 1;
1294
+ background: var(--surface-inset);
1295
+ }
1296
+ .atelic-ui .map-frame iframe {
1297
+ width: 100%;
1298
+ height: 100%;
1299
+ border: 0;
1300
+ display: block;
1301
+ }
1302
+ .atelic-ui .map-facade {
1303
+ width: 100%;
1304
+ height: 100%;
1305
+ display: flex;
1306
+ flex-direction: column;
1307
+ align-items: center;
1308
+ justify-content: center;
1309
+ gap: 10px;
1310
+ padding: 24px;
1311
+ border: 0;
1312
+ background: var(--surface-inset);
1313
+ color: var(--ink-soft);
1314
+ cursor: pointer;
1315
+ font-family: inherit;
1316
+ text-align: center;
1317
+ }
1318
+ .atelic-ui .map-facade svg {
1319
+ color: var(--primary);
1320
+ }
1321
+ .atelic-ui .map-facade-address {
1322
+ font-size: 15px;
1323
+ font-weight: 600;
1324
+ color: var(--ink);
1325
+ max-width: 24ch;
1326
+ }
1327
+ .atelic-ui .map-facade-hint {
1328
+ font-size: 13px;
1329
+ color: var(--neutral-600);
1330
+ border-bottom: 1px solid currentColor;
1331
+ padding-bottom: 1px;
1332
+ }
1333
+ .atelic-ui .map-facade:hover .map-facade-hint,
1334
+ .atelic-ui .map-facade:focus-visible .map-facade-hint {
1335
+ color: var(--primary);
1336
+ }
1337
+ .atelic-ui .map-facade:focus-visible {
1338
+ outline: 2px solid var(--primary);
1339
+ outline-offset: -2px;
1340
+ }
1341
+ @media (min-width: 900px) {
1342
+ .atelic-ui .map-frame {
1343
+ aspect-ratio: 4 / 5;
1344
+ }
1345
+ }
1346
+
1347
+ /* Static map screenshot: shows the whole map at its natural ratio (no crop),
1348
+ one image request, links to directions. */
1349
+ .atelic-ui .map-frame.map-static {
1350
+ aspect-ratio: auto;
1351
+ position: relative;
1352
+ display: block;
1353
+ line-height: 0;
1354
+ }
1355
+ @media (min-width: 900px) {
1356
+ .atelic-ui .map-frame.map-static {
1357
+ aspect-ratio: auto;
1358
+ }
1359
+ }
1360
+ .atelic-ui .map-static img {
1361
+ width: 100%;
1362
+ height: auto;
1363
+ display: block;
1364
+ }
1365
+ .atelic-ui .map-directions {
1366
+ position: absolute;
1367
+ right: 12px;
1368
+ bottom: 12px;
1369
+ display: inline-flex;
1370
+ align-items: center;
1371
+ gap: 6px;
1372
+ font-family: var(--font-sans);
1373
+ font-size: 0.82rem;
1374
+ font-weight: 600;
1375
+ line-height: 1;
1376
+ color: #fff;
1377
+ background: var(--primary);
1378
+ padding: 9px 14px;
1379
+ border-radius: var(--radius-pill);
1380
+ box-shadow: var(--shadow-md);
1381
+ }
1382
+ .atelic-ui .map-static:hover .map-directions,
1383
+ .atelic-ui .map-static:focus-visible .map-directions {
1384
+ background: var(--primary-deep);
1385
+ }
1386
+ .atelic-ui .map-static:focus-visible {
1387
+ outline: 3px solid var(--primary);
1388
+ outline-offset: 2px;
1389
+ }
1390
+
1391
+ /* ---- LocationSection (location-section.css) ---- */
1392
+ /* Location / local SEO section. */
1393
+ .atelic-ui .location-grid {
1394
+ display: grid;
1395
+ gap: 44px;
1396
+ align-items: start;
1397
+ }
1398
+ @media (min-width: 900px) {
1399
+ .atelic-ui .location-grid {
1400
+ grid-template-columns: 1fr 1fr;
1401
+ gap: 64px;
1402
+ }
1403
+ }
1404
+ .atelic-ui .location-grid h2 {
1405
+ margin: 10px 0 18px;
1406
+ }
1407
+ .atelic-ui .loc-areas {
1408
+ margin-top: 14px;
1409
+ color: var(--neutral-600);
1410
+ font-size: 0.95rem;
1411
+ max-width: 46ch;
1412
+ }
1413
+ .atelic-ui .loc-block {
1414
+ margin: 30px 0;
1415
+ max-width: 420px;
1416
+ }
1417
+ .atelic-ui .loc-block h4 {
1418
+ font-family: var(--font-mono);
1419
+ font-size: 0.74rem;
1420
+ letter-spacing: 0.16em;
1421
+ text-transform: uppercase;
1422
+ color: var(--neutral-600);
1423
+ margin-bottom: 10px;
1424
+ }
1425
+ .atelic-ui .loc-actions {
1426
+ display: flex;
1427
+ flex-wrap: wrap;
1428
+ gap: 12px;
1429
+ }
1430
+
1431
+ /* ---- Locations (locations.css) ---- */
1432
+ /* Multi-location block: static map beside a grid of location cards. The map
1433
+ cell stretches to match the cards' height (no sticky scroll oddity); on
1434
+ desktop the map image fills that height and crops, so the two columns are
1435
+ the same size. */
1436
+ .atelic-ui .locs-layout {
1437
+ display: grid;
1438
+ grid-template-columns: 1.05fr 1fr;
1439
+ gap: 40px;
1440
+ align-items: stretch;
1441
+ margin-top: 36px;
1442
+ }
1443
+ @media (max-width: 860px) {
1444
+ .atelic-ui .locs-layout {
1445
+ grid-template-columns: 1fr;
1446
+ gap: 28px;
1447
+ }
1448
+ }
1449
+ .atelic-ui .locs-map {
1450
+ position: relative;
1451
+ }
1452
+ @media (min-width: 861px) {
1453
+ /* The map is absolutely filled so it doesn't drive the row height; the
1454
+ cards do, and the map matches them. */
1455
+ .atelic-ui .locs-map .map-frame.map-static {
1456
+ position: absolute;
1457
+ inset: 0;
1458
+ height: 100%;
1459
+ }
1460
+ .atelic-ui .locs-map .map-static img {
1461
+ height: 100%;
1462
+ object-fit: cover;
1463
+ object-position: center;
1464
+ }
1465
+ }
1466
+ .atelic-ui .locs-cards {
1467
+ display: flex;
1468
+ flex-direction: column;
1469
+ gap: 16px;
1470
+ }
1471
+ .atelic-ui .loc-card {
1472
+ background: var(--card);
1473
+ border: 1px solid var(--hairline-strong);
1474
+ border-radius: var(--radius-md);
1475
+ padding: 20px 22px;
1476
+ box-shadow: var(--shadow-sm);
1477
+ }
1478
+ .atelic-ui .loc-card h3 {
1479
+ margin: 0;
1480
+ font-size: 1.12rem;
1481
+ }
1482
+ .atelic-ui .loc-note {
1483
+ margin: 3px 0 0;
1484
+ font-family: var(--font-mono);
1485
+ font-size: 0.72rem;
1486
+ letter-spacing: 0.06em;
1487
+ text-transform: uppercase;
1488
+ color: var(--primary);
1489
+ }
1490
+ .atelic-ui .loc-addr {
1491
+ margin: 10px 0 0;
1492
+ color: var(--ink-soft);
1493
+ font-size: 0.98rem;
1494
+ }
1495
+ .atelic-ui .loc-hours {
1496
+ display: flex;
1497
+ flex-direction: column;
1498
+ margin-top: 8px;
1499
+ color: var(--neutral-600);
1500
+ font-size: 0.9rem;
1501
+ }
1502
+ .atelic-ui .loc-links {
1503
+ display: flex;
1504
+ flex-wrap: wrap;
1505
+ gap: 18px;
1506
+ margin-top: 14px;
1507
+ padding-top: 14px;
1508
+ border-top: 1px solid var(--hairline);
1509
+ }
1510
+ .atelic-ui .loc-links a {
1511
+ display: inline-flex;
1512
+ align-items: center;
1513
+ gap: 6px;
1514
+ font-size: 0.9rem;
1515
+ font-weight: 600;
1516
+ color: var(--ink);
1517
+ }
1518
+ .atelic-ui .loc-links a:hover {
1519
+ color: var(--primary);
1520
+ }
1521
+ .atelic-ui .loc-links svg {
1522
+ color: var(--primary);
1523
+ }
1524
+
1525
+ /* ---- LogoMarquee (logo-marquee.css) ---- */
1526
+ /* Dark credentials band with infinite marquee. */
1527
+ .atelic-ui .creds {
1528
+ background: var(--surface-dark);
1529
+ padding-block: 22px;
1530
+ }
1531
+ .atelic-ui .creds .chip {
1532
+ background: rgba(255, 255, 255, 0.06);
1533
+ color: #efe7da;
1534
+ box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
1535
+ }
1536
+ .atelic-ui .marquee {
1537
+ overflow: hidden;
1538
+ -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
1539
+ mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
1540
+ }
1541
+ .atelic-ui .marquee-track {
1542
+ display: flex;
1543
+ gap: 14px;
1544
+ width: max-content;
1545
+ animation: scroll-x 32s linear infinite;
1546
+ }
1547
+ @keyframes scroll-x {
1548
+ to {
1549
+ transform: translateX(-50%);
1550
+ }
1551
+ }
1552
+ @media (prefers-reduced-motion: reduce) {
1553
+ .atelic-ui .marquee-track {
1554
+ animation: none;
1555
+ flex-wrap: wrap;
1556
+ width: auto;
1557
+ justify-content: center;
1558
+ }
1559
+ }
1560
+
1561
+ /* ---- MediaBand (media-band.css) ---- */
1562
+ /* Full-bleed image band: spans the viewport, crops from center. */
1563
+ .atelic-ui .media-band {
1564
+ width: 100%;
1565
+ max-height: 72vh;
1566
+ overflow: hidden;
1567
+ }
1568
+ .atelic-ui .media-band img {
1569
+ width: 100%;
1570
+ height: 100%;
1571
+ object-fit: cover;
1572
+ }
1573
+
1574
+ /* ---- MenuList (menu-list.css) ---- */
1575
+ /* A priced menu group, plus the two layouts that stack groups on a
1576
+ location or menu page. */
1577
+ .atelic-ui .menu-list h3 {
1578
+ margin: 0 0 6px;
1579
+ font-size: 16px;
1580
+ font-weight: 800;
1581
+ text-transform: uppercase;
1582
+ letter-spacing: 0.08em;
1583
+ color: var(--ink);
1584
+ border-bottom: 2px solid var(--primary);
1585
+ padding-bottom: 8px;
1586
+ }
1587
+ .atelic-ui .menu-list ul {
1588
+ list-style: none;
1589
+ margin: 0;
1590
+ padding: 0;
1591
+ }
1592
+ .atelic-ui .menu-list li {
1593
+ display: flex;
1594
+ justify-content: space-between;
1595
+ align-items: baseline;
1596
+ gap: 20px;
1597
+ padding: 8px 0;
1598
+ border-bottom: 1px dotted var(--neutral-300);
1599
+ }
1600
+ .atelic-ui .ml-item {
1601
+ display: flex;
1602
+ flex-direction: column;
1603
+ gap: 2px;
1604
+ }
1605
+ .atelic-ui .ml-name {
1606
+ font-weight: 600;
1607
+ font-size: 14px;
1608
+ color: var(--ink);
1609
+ }
1610
+ .atelic-ui .ml-note {
1611
+ color: var(--neutral-500);
1612
+ font-size: 12px;
1613
+ line-height: 1.45;
1614
+ }
1615
+ .atelic-ui .ml-price {
1616
+ color: var(--primary);
1617
+ font-weight: 600;
1618
+ font-size: 13px;
1619
+ white-space: nowrap;
1620
+ text-align: right;
1621
+ }
1622
+ .atelic-ui .ml-foot {
1623
+ color: var(--neutral-500);
1624
+ font-size: 12px;
1625
+ font-style: italic;
1626
+ margin: 8px 0 0;
1627
+ }
1628
+ .atelic-ui .menu-stack {
1629
+ display: flex;
1630
+ flex-direction: column;
1631
+ gap: 36px;
1632
+ }
1633
+ /* Two column menu layout for a fuller board; collapses to one column on
1634
+ phones. Each column track zeroes its min-width so a long dish note can't
1635
+ force the grid wider than the viewport. */
1636
+ .atelic-ui .menu-cols {
1637
+ display: grid;
1638
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1639
+ gap: 36px 56px;
1640
+ margin-top: 40px;
1641
+ }
1642
+ @media (max-width: 720px) {
1643
+ .atelic-ui .menu-cols {
1644
+ grid-template-columns: 1fr;
1645
+ }
1646
+ }
1647
+
1648
+ /* ---- PressQuotes (press-quotes.css) ---- */
1649
+ .atelic-ui .press-quotes {
1650
+ list-style: none;
1651
+ margin: 8px 0 0;
1652
+ padding: 0;
1653
+ }
1654
+ .atelic-ui .press-quotes li {
1655
+ border-bottom: 1px solid var(--hairline-strong);
1656
+ }
1657
+ .atelic-ui .press-quotes .pq-row {
1658
+ display: flex;
1659
+ flex-direction: column;
1660
+ align-items: flex-start;
1661
+ gap: 8px;
1662
+ padding: 18px 0;
1663
+ color: inherit;
1664
+ text-decoration: none;
1665
+ }
1666
+ .atelic-ui .press-quotes .pq-quote {
1667
+ font-family: var(--font-serif);
1668
+ font-size: 1.2rem;
1669
+ font-weight: 600;
1670
+ font-style: italic;
1671
+ transition: color 0.15s ease;
1672
+ }
1673
+ .atelic-ui .press-quotes a.pq-row:hover .pq-quote,
1674
+ .atelic-ui .press-quotes a.pq-row:focus-visible .pq-quote {
1675
+ color: var(--primary);
1676
+ }
1677
+ .atelic-ui .press-quotes .pq-src {
1678
+ font-family: var(--font-mono);
1679
+ font-size: 0.78rem;
1680
+ letter-spacing: 0.08em;
1681
+ text-transform: uppercase;
1682
+ color: var(--neutral-600);
1683
+ }
1684
+
1685
+ /* ---- PricingBand (pricing-band.css) ---- */
1686
+ /* Brand-colored pricing band. */
1687
+ .atelic-ui .price-band {
1688
+ background: var(--primary);
1689
+ color: #fff;
1690
+ padding-block: clamp(56px, 8vw, 100px);
1691
+ }
1692
+ .atelic-ui .price-band h2 {
1693
+ color: #fff;
1694
+ }
1695
+ .atelic-ui .price-band .price-lead {
1696
+ color: rgba(255, 255, 255, 0.82);
1697
+ max-width: 48ch;
1698
+ }
1699
+ .atelic-ui .price-band .eyebrow.on-dark {
1700
+ color: #fff;
1701
+ }
1702
+ .atelic-ui .price-inner {
1703
+ display: grid;
1704
+ gap: 40px;
1705
+ align-items: center;
1706
+ }
1707
+ @media (min-width: 880px) {
1708
+ .atelic-ui .price-inner {
1709
+ grid-template-columns: 1.3fr 0.7fr;
1710
+ gap: 64px;
1711
+ }
1712
+ }
1713
+ .atelic-ui .price-card {
1714
+ background: rgba(255, 255, 255, 0.1);
1715
+ border: 1px solid rgba(255, 255, 255, 0.22);
1716
+ border-radius: var(--radius-xl);
1717
+ padding: 38px 32px;
1718
+ text-align: center;
1719
+ backdrop-filter: blur(6px);
1720
+ display: flex;
1721
+ flex-direction: column;
1722
+ align-items: center;
1723
+ gap: 8px;
1724
+ }
1725
+ .atelic-ui .price-fig {
1726
+ font-size: clamp(3.4rem, 9vw, 5rem);
1727
+ font-weight: 800;
1728
+ letter-spacing: -0.03em;
1729
+ line-height: 1;
1730
+ }
1731
+ .atelic-ui .price-unit {
1732
+ font-family: var(--font-mono);
1733
+ font-size: 0.9rem;
1734
+ color: rgba(255, 255, 255, 0.8);
1735
+ letter-spacing: 0.06em;
1736
+ margin-bottom: 20px;
1737
+ }
1738
+ .atelic-ui .price-detail {
1739
+ margin-top: 14px;
1740
+ font-family: var(--font-mono);
1741
+ font-size: 0.78rem;
1742
+ letter-spacing: 0.04em;
1743
+ color: rgba(255, 255, 255, 0.85);
1744
+ text-decoration: underline;
1745
+ text-underline-offset: 3px;
1746
+ }
1747
+
1748
+ /* ---- PricingCard (pricing-card.css) ---- */
1749
+ /* Detailed pricing card. */
1750
+ .atelic-ui .cost-card {
1751
+ max-width: 520px;
1752
+ margin-inline: auto;
1753
+ text-align: center;
1754
+ background: var(--card);
1755
+ border-radius: var(--radius-xl);
1756
+ padding: clamp(32px, 6vw, 56px);
1757
+ box-shadow: var(--shadow-lg);
1758
+ border: 1px solid var(--hairline);
1759
+ position: relative;
1760
+ }
1761
+ .atelic-ui .cost-card .ribbon {
1762
+ font-family: var(--font-mono);
1763
+ font-size: 0.72rem;
1764
+ letter-spacing: 0.14em;
1765
+ text-transform: uppercase;
1766
+ color: var(--primary);
1767
+ }
1768
+ .atelic-ui .cost-card .big {
1769
+ font-size: clamp(4rem, 12vw, 6rem);
1770
+ font-weight: 800;
1771
+ letter-spacing: -0.04em;
1772
+ line-height: 1;
1773
+ margin: 10px 0 2px;
1774
+ }
1775
+ .atelic-ui .cost-card .per {
1776
+ font-family: var(--font-mono);
1777
+ color: var(--neutral-600);
1778
+ letter-spacing: 0.04em;
1779
+ margin-bottom: 26px;
1780
+ }
1781
+ .atelic-ui .cost-card ul.ticks {
1782
+ text-align: left;
1783
+ max-width: 360px;
1784
+ margin: 0 auto 30px;
1785
+ }
1786
+ .atelic-ui .cost-secondary {
1787
+ display: inline-block;
1788
+ margin-top: 16px;
1789
+ font-family: var(--font-mono);
1790
+ font-size: 0.78rem;
1791
+ letter-spacing: 0.04em;
1792
+ color: var(--neutral-600);
1793
+ text-decoration: underline;
1794
+ text-underline-offset: 3px;
1795
+ }
1796
+
1797
+ /* ---- ProcessSteps (process-steps.css) ---- */
1798
+ /* Numbered process steps on a dark band. */
1799
+ .atelic-ui .process {
1800
+ background: var(--surface-dark);
1801
+ color: var(--surface);
1802
+ }
1803
+ .atelic-ui .process h2 {
1804
+ color: #fff;
1805
+ }
1806
+ .atelic-ui .process-grid {
1807
+ display: grid;
1808
+ gap: 44px;
1809
+ align-items: center;
1810
+ }
1811
+ @media (min-width: 920px) {
1812
+ .atelic-ui .process-grid {
1813
+ grid-template-columns: 1.05fr 0.95fr;
1814
+ gap: 72px;
1815
+ }
1816
+ }
1817
+ .atelic-ui .steps {
1818
+ margin-top: 36px;
1819
+ display: flex;
1820
+ flex-direction: column;
1821
+ gap: 30px;
1822
+ list-style: none;
1823
+ padding: 0;
1824
+ }
1825
+ .atelic-ui .steps li {
1826
+ display: flex;
1827
+ gap: 20px;
1828
+ align-items: flex-start;
1829
+ }
1830
+ .atelic-ui .step-n {
1831
+ flex: 0 0 auto;
1832
+ width: 46px;
1833
+ height: 46px;
1834
+ border-radius: 50%;
1835
+ display: grid;
1836
+ place-items: center;
1837
+ font-family: var(--font-mono);
1838
+ font-weight: 600;
1839
+ font-size: 1.05rem;
1840
+ color: var(--primary-bright);
1841
+ box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.22);
1842
+ }
1843
+ .atelic-ui .steps h4 {
1844
+ color: #fff;
1845
+ margin-bottom: 6px;
1846
+ font-size: 1.25rem;
1847
+ }
1848
+ .atelic-ui .steps p {
1849
+ color: rgba(248, 244, 237, 0.74);
1850
+ max-width: 46ch;
1851
+ }
1852
+ .atelic-ui .process-media .imgframe,
1853
+ .atelic-ui .process-media .ph {
1854
+ aspect-ratio: 4 / 5;
1855
+ }
1856
+ @media (max-width: 919px) {
1857
+ .atelic-ui .process-media .imgframe,
1858
+ .atelic-ui .process-media .ph {
1859
+ aspect-ratio: 16 / 10;
1860
+ }
1861
+ }
1862
+
1863
+ /* ---- ProfileCards (profile-cards.css) ---- */
1864
+ /* Equal-weight horizontal profile cards (rosters, teams). */
1865
+ .atelic-ui .profile-cards {
1866
+ display: grid;
1867
+ gap: 16px;
1868
+ margin-top: 44px;
1869
+ grid-template-columns: 1fr;
1870
+ }
1871
+ @media (min-width: 900px) {
1872
+ .atelic-ui .profile-cards {
1873
+ grid-template-columns: 1fr 1fr;
1874
+ }
1875
+ }
1876
+ .atelic-ui .profile-card {
1877
+ display: flex;
1878
+ gap: 20px;
1879
+ align-items: stretch;
1880
+ height: 100%;
1881
+ background: var(--card);
1882
+ border: 1px solid var(--hairline);
1883
+ border-radius: var(--radius-lg);
1884
+ box-shadow: var(--shadow-sm);
1885
+ padding: 18px;
1886
+ transition:
1887
+ transform 0.25s ease,
1888
+ box-shadow 0.25s ease;
1889
+ }
1890
+ .atelic-ui a.profile-card:hover {
1891
+ transform: translateY(-4px);
1892
+ box-shadow: var(--shadow-md);
1893
+ }
1894
+ .atelic-ui .profile-media {
1895
+ flex: 0 0 clamp(110px, 26%, 168px);
1896
+ border-radius: var(--radius-md);
1897
+ overflow: hidden;
1898
+ background: var(--surface-inset);
1899
+ display: flex;
1900
+ align-items: center;
1901
+ justify-content: center;
1902
+ min-height: 140px;
1903
+ }
1904
+ .atelic-ui .profile-media img {
1905
+ width: 100%;
1906
+ height: 100%;
1907
+ object-fit: cover;
1908
+ }
1909
+ .atelic-ui .profile-placeholder {
1910
+ font-family: var(--font-mono);
1911
+ font-size: 0.72rem;
1912
+ color: var(--neutral-500);
1913
+ text-align: center;
1914
+ padding: 12px;
1915
+ background: repeating-linear-gradient(
1916
+ -45deg,
1917
+ transparent 0 10px,
1918
+ var(--hairline-strong) 10px 11px
1919
+ );
1920
+ width: 100%;
1921
+ height: 100%;
1922
+ display: flex;
1923
+ align-items: center;
1924
+ justify-content: center;
1925
+ }
1926
+ .atelic-ui .profile-body {
1927
+ display: flex;
1928
+ flex-direction: column;
1929
+ min-width: 0;
1930
+ }
1931
+ .atelic-ui .profile-body h3 {
1932
+ font-size: 1.3rem;
1933
+ }
1934
+ .atelic-ui .profile-meta {
1935
+ font-family: var(--font-mono);
1936
+ font-size: 0.75rem;
1937
+ letter-spacing: 0.04em;
1938
+ color: var(--primary);
1939
+ margin-top: 4px;
1940
+ }
1941
+ .atelic-ui .profile-body p {
1942
+ margin-top: 10px;
1943
+ font-size: 0.95rem;
1944
+ color: var(--ink-soft);
1945
+ }
1946
+ .atelic-ui .profile-link {
1947
+ margin-top: auto;
1948
+ padding-top: 14px;
1949
+ font-weight: 700;
1950
+ font-size: 0.92rem;
1951
+ color: var(--primary);
1952
+ }
1953
+
1954
+ /* ---- RevealSlider (reveal-slider.css) ---- */
1955
+ /* Drag-to-compare before/after slider. Tokens only. */
1956
+ .atelic-ui .rslider {
1957
+ position: relative;
1958
+ width: 100%;
1959
+ border-radius: var(--radius-lg);
1960
+ overflow: hidden;
1961
+ box-shadow: var(--shadow-lg);
1962
+ background: var(--surface-inset);
1963
+ user-select: none;
1964
+ /* The frame takes up a good part of a phone's screen, so a vertical
1965
+ swipe across it has to scroll the page. A drag starts on the handle
1966
+ alone, which keeps every touch for itself (touch-action: none below);
1967
+ the frame only follows the pointer once that drag is under way. */
1968
+ touch-action: pan-y;
1969
+ cursor: ew-resize;
1970
+ }
1971
+ .atelic-ui .rslider-layer {
1972
+ position: absolute;
1973
+ inset: 0;
1974
+ width: 100%;
1975
+ height: 100%;
1976
+ display: block;
1977
+ pointer-events: none;
1978
+ }
1979
+ .atelic-ui .rslider-img {
1980
+ object-fit: cover;
1981
+ object-position: top center;
1982
+ }
1983
+
1984
+ /* A side with no photograph yet renders its shot brief instead. The two
1985
+ briefs must not look alike: a matched pair of grey blocks makes dragging
1986
+ the handle look broken, since nothing visibly changes as the divider
1987
+ crosses. So the before is the plain inset well every other placeholder
1988
+ uses, warm neutral with warm neutral hatching, and the after is the primary
1989
+ tint hatched in the primary. Both the fill and the stripe carry the
1990
+ difference, since a tint swap on its own is too quiet to notice in motion.
1991
+
1992
+ Each brief also sits against its own outer edge rather than in the middle of
1993
+ the frame. Both layers are full width and the before one is clipped, so two
1994
+ centered briefs would print on top of each other behind the divider. */
1995
+ .atelic-ui .rslider-ph {
1996
+ display: grid;
1997
+ align-items: center;
1998
+ padding: 24px 6%;
1999
+ font-family: var(--font-mono);
2000
+ font-size: 0.72rem;
2001
+ line-height: 1.7;
2002
+ letter-spacing: 0.09em;
2003
+ text-transform: uppercase;
2004
+ }
2005
+ .atelic-ui .rslider-ph span {
2006
+ max-width: 22ch;
2007
+ }
2008
+ /* On a phone each half is barely wider than the brief itself, so the briefs
2009
+ shrink rather than run under the divider and get cut mid word. */
2010
+ @media (max-width: 719px) {
2011
+ .atelic-ui .rslider-ph {
2012
+ font-size: 0.6rem;
2013
+ line-height: 1.6;
2014
+ letter-spacing: 0.06em;
2015
+ padding: 16px 5%;
2016
+ }
2017
+ .atelic-ui .rslider-ph span {
2018
+ max-width: 15ch;
2019
+ }
2020
+ }
2021
+ .atelic-ui .rslider-ph.is-before {
2022
+ justify-items: start;
2023
+ text-align: left;
2024
+ background:
2025
+ repeating-linear-gradient(135deg, var(--hairline-strong) 0 10px, transparent 10px 20px),
2026
+ var(--surface-inset);
2027
+ color: var(--neutral-600);
2028
+ }
2029
+ .atelic-ui .rslider-ph.is-after {
2030
+ justify-items: end;
2031
+ text-align: right;
2032
+ background:
2033
+ repeating-linear-gradient(135deg, var(--primary-focus-ring) 0 10px, transparent 10px 20px),
2034
+ var(--primary-tint);
2035
+ color: var(--primary-deep);
2036
+ }
2037
+ .atelic-ui .rslider-label {
2038
+ position: absolute;
2039
+ top: 14px;
2040
+ font-family: var(--font-mono);
2041
+ font-size: 0.68rem;
2042
+ letter-spacing: 0.1em;
2043
+ text-transform: uppercase;
2044
+ padding: 5px 11px;
2045
+ border-radius: var(--radius-pill);
2046
+ backdrop-filter: blur(6px);
2047
+ -webkit-backdrop-filter: blur(6px);
2048
+ z-index: 3;
2049
+ }
2050
+ .atelic-ui .rslider-label-before {
2051
+ left: 14px;
2052
+ background: rgba(20, 16, 12, 0.62);
2053
+ color: #fff;
2054
+ }
2055
+ .atelic-ui .rslider-label-after {
2056
+ right: 14px;
2057
+ background: var(--primary);
2058
+ color: #fff;
2059
+ }
2060
+ .atelic-ui .rslider-line {
2061
+ position: absolute;
2062
+ top: 0;
2063
+ bottom: 0;
2064
+ width: 3px;
2065
+ margin-left: -1.5px;
2066
+ background: #fff;
2067
+ box-shadow: 0 0 0 1px rgba(20, 16, 12, 0.15);
2068
+ z-index: 4;
2069
+ pointer-events: none;
2070
+ }
2071
+ .atelic-ui .rslider-handle {
2072
+ position: absolute;
2073
+ top: 50%;
2074
+ transform: translate(-50%, -50%);
2075
+ z-index: 5;
2076
+ width: 46px;
2077
+ height: 46px;
2078
+ border-radius: var(--radius-pill);
2079
+ border: none;
2080
+ background: #fff;
2081
+ color: var(--ink);
2082
+ box-shadow: var(--shadow-md);
2083
+ display: grid;
2084
+ place-items: center;
2085
+ cursor: ew-resize;
2086
+ touch-action: none;
2087
+ }
2088
+ .atelic-ui .rslider-handle:focus-visible {
2089
+ outline: 3px solid var(--primary);
2090
+ outline-offset: 2px;
2091
+ }
2092
+ .atelic-ui .rslider-grip {
2093
+ display: inline-flex;
2094
+ align-items: center;
2095
+ color: var(--primary);
2096
+ }
2097
+ .atelic-ui .rslider-grip svg {
2098
+ margin: 0 -3px;
2099
+ }
2100
+
2101
+ /* ---- ReviewWall (review-wall.css) ---- */
2102
+ /* =================================================================
2103
+ REVIEW WALL — header, filter + sort controls, uniform review cards
2104
+ ================================================================= */
2105
+
2106
+ /* ---- Filter and sort controls ---- */
2107
+ .atelic-ui .rw-controls {
2108
+ display: flex;
2109
+ flex-wrap: wrap;
2110
+ align-items: center;
2111
+ gap: 12px;
2112
+ margin-top: clamp(24px, 3vw, 36px);
2113
+ }
2114
+ .atelic-ui .rw-select {
2115
+ position: relative;
2116
+ display: inline-flex;
2117
+ align-items: center;
2118
+ }
2119
+ .atelic-ui .rw-select-end {
2120
+ margin-left: auto;
2121
+ }
2122
+ /* The control's own label is visually hidden — the selected option
2123
+ already reads as the label ("All services", "Newest") — but screen
2124
+ readers still get a name for each dropdown. */
2125
+ .atelic-ui .rw-select-label {
2126
+ position: absolute;
2127
+ width: 1px;
2128
+ height: 1px;
2129
+ padding: 0;
2130
+ margin: -1px;
2131
+ overflow: hidden;
2132
+ clip-path: inset(50%);
2133
+ white-space: nowrap;
2134
+ }
2135
+ .atelic-ui .rw-select select {
2136
+ appearance: none;
2137
+ font: inherit;
2138
+ font-size: 0.9rem;
2139
+ color: var(--ink);
2140
+ background: var(--card);
2141
+ border: 1px solid var(--neutral-200);
2142
+ border-radius: var(--radius-sm);
2143
+ padding: 10px 38px 10px 14px;
2144
+ cursor: pointer;
2145
+ min-width: 168px;
2146
+ }
2147
+ .atelic-ui .rw-select::after {
2148
+ content: "";
2149
+ position: absolute;
2150
+ right: 15px;
2151
+ width: 8px;
2152
+ height: 8px;
2153
+ border-right: 1.6px solid var(--neutral-500);
2154
+ border-bottom: 1.6px solid var(--neutral-500);
2155
+ transform: translateY(-2px) rotate(45deg);
2156
+ pointer-events: none;
2157
+ }
2158
+ .atelic-ui .rw-select select:hover {
2159
+ border-color: var(--neutral-300);
2160
+ }
2161
+ .atelic-ui .rw-select select:focus-visible {
2162
+ outline: none;
2163
+ border-color: var(--primary);
2164
+ box-shadow: 0 0 0 4px var(--primary-focus-ring);
2165
+ }
2166
+
2167
+ /* ---- The grid ---- */
2168
+ .atelic-ui .review-wall {
2169
+ display: grid;
2170
+ grid-template-columns: 1fr;
2171
+ gap: 18px;
2172
+ margin-top: clamp(28px, 4vw, 44px);
2173
+ }
2174
+ @media (min-width: 680px) {
2175
+ .atelic-ui .review-wall {
2176
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2177
+ }
2178
+ }
2179
+ @media (min-width: 1020px) {
2180
+ .atelic-ui .review-wall {
2181
+ grid-template-columns: repeat(3, minmax(0, 1fr));
2182
+ }
2183
+ }
2184
+
2185
+ .atelic-ui .rw-card {
2186
+ display: flex;
2187
+ flex-direction: column;
2188
+ align-items: flex-start;
2189
+ margin: 0;
2190
+ min-width: 0;
2191
+ padding: clamp(20px, 2.6vw, 28px);
2192
+ background: var(--card);
2193
+ border: 1px solid var(--hairline-strong);
2194
+ border-radius: var(--radius-lg);
2195
+ box-shadow: var(--shadow-sm);
2196
+ }
2197
+
2198
+ /* ---- Card top row: stars left, date right ---- */
2199
+ .atelic-ui .rw-top {
2200
+ display: flex;
2201
+ align-items: center;
2202
+ justify-content: space-between;
2203
+ gap: 12px;
2204
+ width: 100%;
2205
+ margin-bottom: 12px;
2206
+ }
2207
+ .atelic-ui .rw-date {
2208
+ display: inline-flex;
2209
+ align-items: center;
2210
+ gap: 3px;
2211
+ margin-left: auto;
2212
+ font-family: var(--font-mono);
2213
+ font-size: 0.76rem;
2214
+ color: var(--neutral-500);
2215
+ }
2216
+ .atelic-ui a.rw-date:hover {
2217
+ color: var(--primary);
2218
+ }
2219
+
2220
+ .atelic-ui .rw-quote {
2221
+ margin: 0 0 16px;
2222
+ font-size: 0.98rem;
2223
+ line-height: 1.62;
2224
+ color: var(--ink-soft);
2225
+ }
2226
+ .atelic-ui .rw-quote.clamped {
2227
+ display: -webkit-box;
2228
+ -webkit-line-clamp: 6;
2229
+ -webkit-box-orient: vertical;
2230
+ overflow: hidden;
2231
+ }
2232
+
2233
+ .atelic-ui .rw-more {
2234
+ margin: -6px 0 16px;
2235
+ font-family: var(--font-mono);
2236
+ font-size: 0.74rem;
2237
+ letter-spacing: 0.06em;
2238
+ text-transform: uppercase;
2239
+ color: var(--primary);
2240
+ text-decoration: underline;
2241
+ text-underline-offset: 3px;
2242
+ padding: 2px 0;
2243
+ }
2244
+ .atelic-ui .rw-more:hover {
2245
+ color: var(--ink);
2246
+ }
2247
+
2248
+ /* ---- Tag chips ---- */
2249
+ .atelic-ui .rw-tags {
2250
+ display: flex;
2251
+ flex-wrap: wrap;
2252
+ gap: 6px;
2253
+ margin: 0 0 16px;
2254
+ }
2255
+ .atelic-ui .rw-tag {
2256
+ display: inline-flex;
2257
+ align-items: center;
2258
+ padding: 4px 10px;
2259
+ border-radius: var(--radius-pill);
2260
+ background: var(--surface-alt);
2261
+ color: var(--neutral-600);
2262
+ font-size: 0.74rem;
2263
+ line-height: 1.4;
2264
+ }
2265
+
2266
+ .atelic-ui .rw-who {
2267
+ display: flex;
2268
+ align-items: center;
2269
+ gap: 12px;
2270
+ width: 100%;
2271
+ margin-top: auto;
2272
+ padding-top: 16px;
2273
+ border-top: 1px solid var(--hairline);
2274
+ }
2275
+ .atelic-ui .rw-avatar {
2276
+ flex: 0 0 auto;
2277
+ width: 38px;
2278
+ height: 38px;
2279
+ border-radius: 50%;
2280
+ display: grid;
2281
+ place-items: center;
2282
+ background: var(--primary-tint);
2283
+ color: var(--primary);
2284
+ font-family: var(--font-mono);
2285
+ font-size: 0.78rem;
2286
+ font-weight: 700;
2287
+ letter-spacing: 0.04em;
2288
+ }
2289
+ .atelic-ui .rw-name-block {
2290
+ display: flex;
2291
+ flex-direction: column;
2292
+ gap: 2px;
2293
+ min-width: 0;
2294
+ }
2295
+ .atelic-ui .rw-name {
2296
+ font-weight: 700;
2297
+ font-size: 0.92rem;
2298
+ color: var(--ink);
2299
+ }
2300
+ .atelic-ui .rw-detail {
2301
+ font-size: 0.8rem;
2302
+ color: var(--neutral-500);
2303
+ }
2304
+
2305
+ /* ---- ReviewCarousel (review-carousel.css) ---- */
2306
+ /* =================================================================
2307
+ REVIEW CAROUSEL — aggregate rating beside one review card at a time
2308
+ ================================================================= */
2309
+
2310
+ .atelic-ui .rc-grid {
2311
+ display: grid;
2312
+ grid-template-columns: 1fr;
2313
+ gap: clamp(32px, 4vw, 48px);
2314
+ align-items: center;
2315
+ }
2316
+ @media (min-width: 940px) {
2317
+ .atelic-ui .rc-grid {
2318
+ grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
2319
+ gap: clamp(40px, 5vw, 72px);
2320
+ }
2321
+ }
2322
+
2323
+ /* ---- Left column: the aggregate ---- */
2324
+ .atelic-ui .rc-aggregate {
2325
+ min-width: 0;
2326
+ }
2327
+ .atelic-ui .rc-score {
2328
+ display: flex;
2329
+ align-items: baseline;
2330
+ gap: 10px;
2331
+ margin: 6px 0 0;
2332
+ }
2333
+ .atelic-ui .rc-score-num {
2334
+ font-size: clamp(4.2rem, 8vw, 6.6rem);
2335
+ font-weight: 800;
2336
+ line-height: 0.95;
2337
+ letter-spacing: -0.045em;
2338
+ color: var(--ink);
2339
+ }
2340
+ .atelic-ui .rc-score-out {
2341
+ font-size: clamp(1.2rem, 2vw, 1.7rem);
2342
+ font-weight: 500;
2343
+ color: var(--neutral-300);
2344
+ }
2345
+ .atelic-ui .rc-rating {
2346
+ display: flex;
2347
+ align-items: center;
2348
+ flex-wrap: wrap;
2349
+ gap: 10px;
2350
+ margin: 16px 0 0;
2351
+ }
2352
+ .atelic-ui .rc-caption {
2353
+ font-size: 0.95rem;
2354
+ color: var(--ink-soft);
2355
+ }
2356
+ /* The caption as a link out to the live profile: the same quiet idiom as
2357
+ the wall's dated source link (trailing arrow, new tab), plus a hairline
2358
+ underline so it reads as a link inside an otherwise static block. */
2359
+ .atelic-ui a.rc-caption {
2360
+ display: inline-flex;
2361
+ align-items: center;
2362
+ gap: 3px;
2363
+ text-decoration: underline;
2364
+ text-decoration-color: var(--neutral-300);
2365
+ text-underline-offset: 3px;
2366
+ transition:
2367
+ color 0.2s ease,
2368
+ text-decoration-color 0.2s ease;
2369
+ }
2370
+ .atelic-ui a.rc-caption:hover {
2371
+ color: var(--primary);
2372
+ text-decoration-color: currentColor;
2373
+ }
2374
+ .atelic-ui a.rc-caption:focus-visible {
2375
+ outline: 2px solid var(--primary);
2376
+ outline-offset: 3px;
2377
+ border-radius: var(--radius-sm);
2378
+ }
2379
+ .atelic-ui .rc-lead {
2380
+ margin: 20px 0 0;
2381
+ max-width: 46ch;
2382
+ font-size: 1.02rem;
2383
+ line-height: 1.65;
2384
+ color: var(--ink-soft);
2385
+ }
2386
+
2387
+ /* ---- Optional mini stat row ---- */
2388
+ .atelic-ui .rc-stats {
2389
+ display: flex;
2390
+ flex-wrap: wrap;
2391
+ gap: 0;
2392
+ margin: clamp(24px, 3vw, 34px) 0 0;
2393
+ }
2394
+ .atelic-ui .rc-stat {
2395
+ padding: 2px 22px 2px 0;
2396
+ margin-right: 22px;
2397
+ border-right: 1px solid var(--hairline-strong);
2398
+ }
2399
+ .atelic-ui .rc-stat:last-child {
2400
+ border-right: none;
2401
+ margin-right: 0;
2402
+ padding-right: 0;
2403
+ }
2404
+ .atelic-ui .rc-stat-value {
2405
+ font-size: 1.35rem;
2406
+ font-weight: 800;
2407
+ letter-spacing: -0.02em;
2408
+ color: var(--ink);
2409
+ }
2410
+ .atelic-ui .rc-stat-label {
2411
+ margin: 2px 0 0;
2412
+ font-size: 0.8rem;
2413
+ color: var(--neutral-500);
2414
+ }
2415
+
2416
+ /* ---- Right column: the card ---- */
2417
+ .atelic-ui .rc-viewport {
2418
+ min-width: 0;
2419
+ padding: clamp(24px, 3vw, 40px);
2420
+ background: var(--card);
2421
+ border: 1px solid var(--hairline-strong);
2422
+ border-radius: var(--radius-lg);
2423
+ box-shadow: var(--shadow-md);
2424
+ }
2425
+
2426
+ /* Every slide sits in the same grid cell: all quotes stay in the static
2427
+ HTML, the card is as tall as the longest one, and stepping through
2428
+ never shifts the page. Inactive slides are hidden (and so are dropped
2429
+ from the tab order and the accessibility tree) rather than unmounted. */
2430
+ .atelic-ui .rc-stage {
2431
+ display: grid;
2432
+ }
2433
+ .atelic-ui .rc-slide {
2434
+ grid-area: 1 / 1;
2435
+ display: flex;
2436
+ flex-direction: column;
2437
+ align-items: flex-start;
2438
+ /* The card is as tall as the longest quote, so a short one centers in
2439
+ it rather than floating above a hole. */
2440
+ justify-content: center;
2441
+ margin: 0;
2442
+ min-width: 0;
2443
+ opacity: 0;
2444
+ visibility: hidden;
2445
+ transition: opacity 0.35s ease;
2446
+ }
2447
+ .atelic-ui .rc-slide.is-active {
2448
+ opacity: 1;
2449
+ visibility: visible;
2450
+ }
2451
+ @media (prefers-reduced-motion: reduce) {
2452
+ .atelic-ui .rc-slide {
2453
+ transition: none;
2454
+ }
2455
+ }
2456
+ .atelic-ui .rc-slide .star-row {
2457
+ margin-bottom: 18px;
2458
+ }
2459
+
2460
+ .atelic-ui .rc-quote {
2461
+ margin: 0;
2462
+ font-size: clamp(1.15rem, 1.5vw, 1.42rem);
2463
+ font-weight: 500;
2464
+ line-height: 1.5;
2465
+ letter-spacing: -0.01em;
2466
+ color: var(--ink);
2467
+ }
2468
+ /* Longer quotes set smaller, so one paragraph-length review doesn't drive
2469
+ the shared card height past what the page can hold (see quoteSize). */
2470
+ .atelic-ui .rc-quote.is-medium {
2471
+ font-size: clamp(1.05rem, 1.25vw, 1.2rem);
2472
+ line-height: 1.55;
2473
+ }
2474
+ .atelic-ui .rc-quote.is-compact {
2475
+ font-size: clamp(0.98rem, 1.1vw, 1.06rem);
2476
+ line-height: 1.6;
2477
+ letter-spacing: 0;
2478
+ }
2479
+
2480
+ .atelic-ui .rc-who {
2481
+ display: flex;
2482
+ flex-direction: column;
2483
+ gap: 3px;
2484
+ width: 100%;
2485
+ padding-top: clamp(20px, 2.4vw, 28px);
2486
+ }
2487
+ .atelic-ui .rc-who::before {
2488
+ content: "";
2489
+ display: block;
2490
+ height: 1px;
2491
+ background: var(--hairline-strong);
2492
+ margin-bottom: clamp(18px, 2.2vw, 24px);
2493
+ }
2494
+ .atelic-ui .rc-name {
2495
+ font-weight: 700;
2496
+ font-size: 1rem;
2497
+ color: var(--ink);
2498
+ }
2499
+ .atelic-ui .rc-detail {
2500
+ font-size: 0.86rem;
2501
+ color: var(--neutral-500);
2502
+ }
2503
+
2504
+ /* ---- Pagination and arrows ---- */
2505
+ .atelic-ui .rc-controls {
2506
+ display: flex;
2507
+ align-items: center;
2508
+ justify-content: space-between;
2509
+ gap: 16px;
2510
+ margin-top: clamp(20px, 2.4vw, 28px);
2511
+ }
2512
+ .atelic-ui .rc-dots {
2513
+ display: flex;
2514
+ align-items: center;
2515
+ gap: 8px;
2516
+ }
2517
+ .atelic-ui .rc-dot {
2518
+ width: 8px;
2519
+ height: 8px;
2520
+ padding: 0;
2521
+ border-radius: var(--radius-pill);
2522
+ background: var(--neutral-200);
2523
+ transition:
2524
+ width 0.25s ease,
2525
+ background 0.2s ease;
2526
+ }
2527
+ .atelic-ui .rc-dot:hover {
2528
+ background: var(--neutral-500);
2529
+ }
2530
+ .atelic-ui .rc-dot.is-active {
2531
+ width: 26px;
2532
+ background: var(--ink);
2533
+ }
2534
+ .atelic-ui .rc-arrows {
2535
+ display: flex;
2536
+ align-items: center;
2537
+ gap: 8px;
2538
+ }
2539
+ .atelic-ui .rc-arrow {
2540
+ width: 40px;
2541
+ height: 40px;
2542
+ display: grid;
2543
+ place-items: center;
2544
+ border-radius: 50%;
2545
+ border: 1px solid var(--neutral-200);
2546
+ color: var(--ink);
2547
+ background: var(--card);
2548
+ transition:
2549
+ background 0.2s ease,
2550
+ border-color 0.2s ease,
2551
+ color 0.2s ease;
2552
+ }
2553
+ .atelic-ui .rc-arrow:hover {
2554
+ background: var(--surface-alt);
2555
+ border-color: var(--neutral-300);
2556
+ }
2557
+ .atelic-ui .rc-arrow:focus-visible,
2558
+ .atelic-ui .rc-dot:focus-visible {
2559
+ outline: 2px solid var(--primary);
2560
+ outline-offset: 3px;
2561
+ }
2562
+
2563
+ /* ---- SocialStrip (social-strip.css) ---- */
2564
+ /* SocialStrip — a static grid of the business's own social photos. */
2565
+
2566
+ /* A 2x2 anchor photo plus four square tiles fills the 4-column grid exactly;
2567
+ pass five photos for a clean rectangle. */
2568
+ .atelic-ui .social-strip {
2569
+ display: grid;
2570
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2571
+ gap: 14px;
2572
+ margin-top: 34px;
2573
+ }
2574
+
2575
+ .atelic-ui .social-strip .social-tile:first-child {
2576
+ grid-column: span 2;
2577
+ grid-row: span 2;
2578
+ }
2579
+
2580
+ @media (min-width: 760px) {
2581
+ .atelic-ui .social-strip {
2582
+ grid-template-columns: repeat(4, minmax(0, 1fr));
2583
+ }
2584
+ }
2585
+
2586
+ .atelic-ui .social-tile {
2587
+ display: block;
2588
+ position: relative;
2589
+ overflow: hidden;
2590
+ border-radius: var(--radius-md);
2591
+ background: var(--surface-inset);
2592
+ aspect-ratio: 1;
2593
+ box-shadow: var(--shadow-sm);
2594
+ transition:
2595
+ transform 180ms ease,
2596
+ box-shadow 180ms ease;
2597
+ }
2598
+
2599
+ .atelic-ui .social-tile img {
2600
+ width: 100%;
2601
+ height: 100%;
2602
+ object-fit: cover;
2603
+ display: block;
2604
+ }
2605
+
2606
+ .atelic-ui .social-tile:hover,
2607
+ .atelic-ui .social-tile:focus-visible {
2608
+ transform: translateY(-3px);
2609
+ box-shadow: var(--shadow-md);
2610
+ }
2611
+
2612
+ @media (prefers-reduced-motion: reduce) {
2613
+ .atelic-ui .social-tile,
2614
+ .atelic-ui .social-tile:hover {
2615
+ transition: none;
2616
+ transform: none;
2617
+ }
2618
+ }
2619
+
2620
+ .atelic-ui .social-follow {
2621
+ display: flex;
2622
+ justify-content: center;
2623
+ margin-top: 30px;
2624
+ }
2625
+
2626
+ .atelic-ui .social-follow .btn svg {
2627
+ margin-right: 8px;
2628
+ }
2629
+
2630
+ /* ---- SplitSection (split-section.css) ---- */
2631
+ /* Two-column split used across empathy, about, cost, and location sections. */
2632
+ .atelic-ui .split {
2633
+ display: grid;
2634
+ gap: 40px;
2635
+ }
2636
+ @media (min-width: 920px) {
2637
+ .atelic-ui .split.ratio-even {
2638
+ grid-template-columns: 1fr 1fr;
2639
+ gap: 64px;
2640
+ }
2641
+ .atelic-ui .split.ratio-narrow-first {
2642
+ grid-template-columns: 0.9fr 1.1fr;
2643
+ gap: 72px;
2644
+ }
2645
+ }
2646
+ .atelic-ui .split.align-start {
2647
+ align-items: start;
2648
+ }
2649
+ .atelic-ui .split.align-center {
2650
+ align-items: center;
2651
+ }
2652
+ }