luckiest-co 1.0.13 → 1.0.14
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/skills/luckiest-design-website/ATTRIBUTION.md +38 -0
- package/skills/luckiest-design-website/CHANGELOG.md +104 -0
- package/skills/luckiest-design-website/LICENSE +21 -0
- package/skills/luckiest-design-website/SKILL.md +372 -0
- package/skills/luckiest-design-website/UPSTREAM-CHANGELOG.md +526 -0
- package/skills/luckiest-design-website/engine/scrollcraft.css +432 -0
- package/skills/luckiest-design-website/engine/scrollcraft.js +1167 -0
- package/skills/luckiest-design-website/evals/evals.json +33 -0
- package/skills/luckiest-design-website/references/assets.md +286 -0
- package/skills/luckiest-design-website/references/device-diag.html +214 -0
- package/skills/luckiest-design-website/references/devices.md +466 -0
- package/skills/luckiest-design-website/references/feel.md +277 -0
- package/skills/luckiest-design-website/references/registry-examples.md +305 -0
- package/skills/luckiest-design-website/references/taste.md +304 -0
- package/skills/luckiest-design-website/references/template.html +138 -0
- package/skills/luckiest-design-website/references/uniqueness.md +480 -0
- package/skills/luckiest-design-website/references/verify.md +381 -0
- package/skills/luckiest-design-website/references/worldflight.md +349 -0
- package/skills/luckiest-design-website/references/worlds.md +178 -0
- package/skills/luckiest-design-website/scripts/doctor.mjs +177 -0
- package/skills/luckiest-design-website/scripts/encode.sh +80 -0
- package/skills/luckiest-design-website/scripts/kie.mjs +202 -0
- package/skills/luckiest-design-website/scripts/serve.mjs +52 -0
- package/skills/luckiest-design-website/scripts/shoot.mjs +644 -0
- package/skills/luckiest-design-website/scripts/workspace.mjs +106 -0
- package/skills/luckiest-design-website/scripts/worldflight-assert.mjs +273 -0
- package/skills/luckiest-design-website/templates/FINGERPRINTS.md +65 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# The taste floor
|
|
2
|
+
|
|
3
|
+
Read this before writing markup, not after. Build without announcing the
|
|
4
|
+
checklist.
|
|
5
|
+
|
|
6
|
+
Everything here is a check on the **rendered result**, not on intention. "I used
|
|
7
|
+
a spacing scale" is not evidence; a computed value is.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Spacing
|
|
12
|
+
|
|
13
|
+
Rhythm comes from the contrast between tight and generous, never from one value
|
|
14
|
+
repeated until everything weighs the same. If you can't point at which intervals
|
|
15
|
+
are the tight ones and which are the breaks, the page has no rhythm.
|
|
16
|
+
|
|
17
|
+
- Use the 4px-base scale (`--sc-1` … `--sc-11`). A 4-base gives the useful
|
|
18
|
+
middle steps an 8-only scale misses.
|
|
19
|
+
- **More space above a heading than below it.** The gap belongs to the boundary
|
|
20
|
+
between sections, not to the heading-and-body pair. Getting this backwards is
|
|
21
|
+
the single most common spacing error, and it makes a page read as a list.
|
|
22
|
+
- Section padding is fluid (`--sc-section`). A phone should not inherit desktop
|
|
23
|
+
air; 8rem of padding on a 375px screen is a scroll tax.
|
|
24
|
+
- Group by proximity before reaching for a container. If you added a border to
|
|
25
|
+
show two things are related, the spacing was wrong first.
|
|
26
|
+
- Gutters scale with viewport (`--sc-gutter`). Full-bleed media goes edge to
|
|
27
|
+
edge; text never does.
|
|
28
|
+
|
|
29
|
+
**Optical, not mathematical.** Equal computed padding around a shape with
|
|
30
|
+
uneven visual weight looks wrong. Correct against the render, not the number.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Typography
|
|
35
|
+
|
|
36
|
+
- **Two families maximum.** Display carries voice, text carries prose. A third
|
|
37
|
+
is a costume.
|
|
38
|
+
- **Tracking tightens as size grows.** A face set at 6rem with default tracking
|
|
39
|
+
reads loose and amateur. The ramp handles this: `--sc-track-tight` on display,
|
|
40
|
+
`--sc-track-normal` on body. This is optical correction, not decoration.
|
|
41
|
+
- **Body measure 45 to 75ch.** `--sc-measure` is 62ch. A full-width paragraph on
|
|
42
|
+
a 1600px monitor is unreadable regardless of font size.
|
|
43
|
+
- **Line height inverse to measure.** Wider lines need more leading. Display at
|
|
44
|
+
0.94 to 1.06, body at 1.6.
|
|
45
|
+
- **Light text on dark needs compensation on three axes**: slightly more line
|
|
46
|
+
height, a touch more tracking, one step more weight. Dark-mode type set with
|
|
47
|
+
light-mode metrics looks thin and blurry, and this is why.
|
|
48
|
+
- `text-wrap: balance` on headings, `pretty` on body. Free, and it removes the
|
|
49
|
+
orphan word that makes a headline look accidental.
|
|
50
|
+
- Display max ~6rem outside a genuine hero moment. Bigger is not more confident.
|
|
51
|
+
- **Step the hero down one rung below ~700px.** `--sc-t-4xl` floors at 3.4rem,
|
|
52
|
+
which is a *desktop* floor: at 390px it wraps a normal hero headline to six
|
|
53
|
+
lines. `--sc-t-2xl` on the hero inside a phone media query fixes it. The
|
|
54
|
+
portrait crop of the image is covered in assets.md; this is the portrait crop
|
|
55
|
+
of the type, and it is missed more often.
|
|
56
|
+
|
|
57
|
+
**Font choice.** Inter is discouraged as a default: it is the most-used face in
|
|
58
|
+
AI-generated pages and it reads as a non-decision. Reach first for Geist,
|
|
59
|
+
Archivo, Outfit, Satoshi, Cabinet Grotesk, or the brand's own face. Inter is
|
|
60
|
+
correct when the brand asks for neutral, or when accessibility is the brief.
|
|
61
|
+
|
|
62
|
+
**Serif is not a synonym for premium.** "It feels editorial" is not a reason.
|
|
63
|
+
Use one only when the brand names it, or when the work is genuinely editorial,
|
|
64
|
+
luxury, or heritage and you can say why *this* serif fits *this* brand.
|
|
65
|
+
|
|
66
|
+
**Emphasis inside a headline** uses italic or bold of the same family. Dropping
|
|
67
|
+
a serif word into a sans headline for visual interest is amateur.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Colour
|
|
72
|
+
|
|
73
|
+
- **Six roles, one accent.** Canvas, surface, ink, ink-soft, accent, accent-ink.
|
|
74
|
+
The accent owns a region or a role; scattered tiny accents are confetti.
|
|
75
|
+
- **Lock the accent for the whole page.** A warm-grey site does not grow a blue
|
|
76
|
+
CTA in section seven. **The one exception is a page that hard-cuts between
|
|
77
|
+
light and dark grounds**, which physically cannot clear 4.5:1 on both with a
|
|
78
|
+
single stop. That page carries a two-stop accent: one hue, two lightnesses,
|
|
79
|
+
keyed to the ground family, redefined per section alongside the ink. Still one
|
|
80
|
+
accent per ground, and still one hue for the page. Two different hues is not
|
|
81
|
+
what this licenses.
|
|
82
|
+
- **Secondary text is tinted, never flat gray.** Derive it from the foreground
|
|
83
|
+
or surface hue. `#888` on a warm dark ground looks dirty.
|
|
84
|
+
- **No pure black.** `#000` has no air in it. Off-black at minimum.
|
|
85
|
+
- Contrast, measured on the render: body ≥4.5:1, large text ≥3:1, controls and
|
|
86
|
+
focus indicators ≥3:1.
|
|
87
|
+
- Drift keeps the whole page in one theme family. See devices.md §10.
|
|
88
|
+
|
|
89
|
+
**Redefining `--sc-ink` on a subtree does not re-ink the text under it.**
|
|
90
|
+
`color` is inherited as a *computed value*, so text whose `color` already
|
|
91
|
+
resolved on `<body>` keeps the body's ink no matter what the section redefines
|
|
92
|
+
the token to. Every page that inverts a ground mid-page hits this, and it fails
|
|
93
|
+
silently: an inverted section renders bone type on concrete at 1.15:1 while the
|
|
94
|
+
harness correctly classifies the line as light-on-dark and grades it in the
|
|
95
|
+
wrong direction. The fix is one declaration on the same subtree:
|
|
96
|
+
|
|
97
|
+
```css
|
|
98
|
+
.section--light { --sc-ink: #14110C; --sc-ink-soft: #4A443A; color: var(--sc-ink); }
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Restate `color` wherever you restate the token. The same applies to any other
|
|
102
|
+
inherited property you drive from a token on a subtree.
|
|
103
|
+
|
|
104
|
+
**The premium-consumer palette trap.** Warm cream background, brass or clay
|
|
105
|
+
accent, espresso near-black text is the default reach for every artisan, food,
|
|
106
|
+
wellness and craft brief, and it makes every such brand look identical. Do not
|
|
107
|
+
default to it. Rotate: cold silver and chrome; deep forest with bone and amber;
|
|
108
|
+
true off-black with warm tan; cobalt against a single neutral; olive with brick.
|
|
109
|
+
Use cream-and-brass only when the brand names those colours.
|
|
110
|
+
|
|
111
|
+
**The AI-purple trap.** Violet-to-blue gradients, neon glow, glowing buttons.
|
|
112
|
+
Not unless the brand asks.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Text over media
|
|
117
|
+
|
|
118
|
+
"No full-frame overlay" is the rule. Here is what to do instead, because the
|
|
119
|
+
rule on its own sends people to a slightly weaker full-frame overlay.
|
|
120
|
+
|
|
121
|
+
There are three shapes, and which one is right depends only on where the copy is:
|
|
122
|
+
|
|
123
|
+
1. **A corner** of density, sized to the copy block. `.sc-scrim--lead` /
|
|
124
|
+
`.sc-scrim--trail`. Right when the copy is anchored to a corner on a wide
|
|
125
|
+
screen. An edge gradient has to darken a whole band across the frame to cover
|
|
126
|
+
one corner; a corner gradient puts the density where the text is and leaves
|
|
127
|
+
the photograph alone.
|
|
128
|
+
2. **A band**, `.sc-scrim--band`, transparent above roughly 58%. Right whenever
|
|
129
|
+
the copy spans the full width of the frame, which is what *both* corner
|
|
130
|
+
anchors become below 860px. The engine already switches `.sc-scrim--trail` to
|
|
131
|
+
a band there for exactly that reason.
|
|
132
|
+
3. **A column** of density under a text column, on an act where the copy holds
|
|
133
|
+
one side of a full-bleed image. Leaves the other half of the frame untouched.
|
|
134
|
+
|
|
135
|
+
**`width` and `height` attributes are presentational hints, and they come in
|
|
136
|
+
pairs.** The reference template ships every `<img>` with both, correctly, because
|
|
137
|
+
they reserve the aspect ratio and stop the page reflowing as media arrives. The
|
|
138
|
+
trap is that overriding only one of them in CSS leaves the other resolving to the
|
|
139
|
+
attribute's raw pixel value, so `width: 100%` on a 1920x1080 image inside a
|
|
140
|
+
narrow column renders it 1080px tall and pushes everything under it off the fold.
|
|
141
|
+
It looks like a layout bug three elements away from its cause. **Override both or
|
|
142
|
+
neither**, usually `width: 100%; height: auto`, or an explicit height plus
|
|
143
|
+
`object-fit: cover` when the frame's shape is the design.
|
|
144
|
+
|
|
145
|
+
And the positive case behind all three: when a photographic ground sits behind a
|
|
146
|
+
text column, **mask the image away from the text** rather than laying anything
|
|
147
|
+
over it. A `mask-image` or a clip that ends where the column begins gives the
|
|
148
|
+
type a clean ground and gives the photograph its full contrast back, and it is
|
|
149
|
+
better than any scrim.
|
|
150
|
+
|
|
151
|
+
**A scrim must not be a child of the text it protects.** The verification pass
|
|
152
|
+
hides the copy element and everything inside it to photograph the frame
|
|
153
|
+
underneath, so a `::before` on the copy block is hidden too and the scrim is
|
|
154
|
+
never measured. Put it in a sibling element. See verify.md.
|
|
155
|
+
|
|
156
|
+
Then measure it. A scrim tuned by eye is routinely 9:1 where 4.5:1 was needed,
|
|
157
|
+
which is a photograph thrown away for nothing, or 2.8:1 on the one frame the
|
|
158
|
+
clip brightens under the copy. Both are invisible until the harness reports the
|
|
159
|
+
number.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Depth
|
|
164
|
+
|
|
165
|
+
Depth is the axis that separates a premium page from a styled document, and it
|
|
166
|
+
is not one property. Five tools, used together:
|
|
167
|
+
|
|
168
|
+
1. **Shadow with offset and blur.** Real raised things cast light downward.
|
|
169
|
+
A zero-offset coloured halo is decoration, not depth. Tint the shadow to the
|
|
170
|
+
canvas hue; pure black shadows on a coloured ground look like dirt.
|
|
171
|
+
2. **Edge light.** A 1px top highlight (`--sc-edge`) sells a raised surface
|
|
172
|
+
better than any amount of blur, because real lips catch light.
|
|
173
|
+
3. **Scale and blur as distance.** Things further away are smaller, softer, and
|
|
174
|
+
lower contrast. Parallax without those reads as sliding, not depth.
|
|
175
|
+
4. **Overlap.** One element crossing another's boundary establishes more depth
|
|
176
|
+
than any shadow. Free, and underused.
|
|
177
|
+
5. **Grain.** A flat dark ground bands on real displays. `.sc-grain` at 4-5%
|
|
178
|
+
opacity is the difference between "a dark page" and "a lit room".
|
|
179
|
+
|
|
180
|
+
Three elevation steps (`--sc-e1/2/3`) and no more. If everything is elevated,
|
|
181
|
+
nothing is.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Cards
|
|
186
|
+
|
|
187
|
+
Cards are the lazy container. Before using one, ask what it is doing that
|
|
188
|
+
proximity, a hairline, or space could not.
|
|
189
|
+
|
|
190
|
+
- **Never a grid of identical icon + heading + text cards as the page
|
|
191
|
+
structure.** It is the most recognisable AI-page tell there is.
|
|
192
|
+
- **Never nest cards.**
|
|
193
|
+
- **Never three equal columns of feature cards.** Use an asymmetric grid, a
|
|
194
|
+
two-column zigzag (max two in a row), a rail, or plain type on space.
|
|
195
|
+
- If a multi-cell grid has an empty trailing cell, the grid was planned wrong.
|
|
196
|
+
Reshape it; do not paste a blank tile.
|
|
197
|
+
- Pick one corner-radius scale and hold it across the page. Pill buttons on a
|
|
198
|
+
square-card page is broken, not eclectic.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Motion
|
|
203
|
+
|
|
204
|
+
The scroll devices are the page's motion. Everything else is small and fast.
|
|
205
|
+
|
|
206
|
+
- `transform` and `opacity` only for anything continuous. `clip-path` is the
|
|
207
|
+
sanctioned third for wipes. Never animate width, height, margin, padding, top
|
|
208
|
+
or left, and never `transition: all`.
|
|
209
|
+
- **Never `ease-in` on UI.** It delays the moment the eye is already on.
|
|
210
|
+
`ease-out` at 200ms feels faster than `ease-in` at 200ms.
|
|
211
|
+
- Built-in CSS easings are too weak. Use `--sc-ease-out`
|
|
212
|
+
(`cubic-bezier(0.23, 1, 0.32, 1)`).
|
|
213
|
+
- **UI transitions under 300ms.** Hover 120-180ms, buttons 100-160ms. Scroll
|
|
214
|
+
devices are exempt: they are paced by the hand, not by a duration.
|
|
215
|
+
- **Never `scale(0)`.** Enter from `scale(0.95)` + `opacity: 0`. Nothing in the
|
|
216
|
+
real world appears from nothing.
|
|
217
|
+
- Press feedback on anything pressable: `scale(0.97)` or `translateY(1px)`.
|
|
218
|
+
- Stagger group entrances 30 to 80ms. Longer feels slow.
|
|
219
|
+
- Gate hover motion to `(hover: hover) and (pointer: fine)`; touch fires false
|
|
220
|
+
hovers on tap.
|
|
221
|
+
- Reduced motion means **fewer and gentler, not zero**. Keep the opacity that
|
|
222
|
+
carries comprehension, drop every position change.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## States and content
|
|
227
|
+
|
|
228
|
+
- Every interactive element gets hover, focus-visible, active and disabled.
|
|
229
|
+
A page with only the resting state is half-built.
|
|
230
|
+
- **Focus-visible must be visible.** Themed to the accent, with offset.
|
|
231
|
+
- **Button text fits on one line at desktop.** A wrapped CTA is broken. Primary
|
|
232
|
+
CTA labels are one to three words.
|
|
233
|
+
- **One label per intent.** "Get in touch" in the nav and "Let's talk" in the
|
|
234
|
+
footer are the same button with two names. Pick one and use it everywhere.
|
|
235
|
+
- **Check button contrast.** White text on a light button, or a ghost button on
|
|
236
|
+
a photo with no scrim, fails.
|
|
237
|
+
- Real copy, not lorem. Real names, not "John Doe". Real numbers or no numbers.
|
|
238
|
+
- **No invented statistics.** Fake precision (`4.1×`, `92%`, `48k`) is a legal
|
|
239
|
+
and credibility liability, not a design element.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Browser surfaces
|
|
244
|
+
|
|
245
|
+
The parts you did not draw still carry the design, and this is the cheapest
|
|
246
|
+
signal that a page was built rather than assembled. It is also the step that
|
|
247
|
+
gets skipped most reliably. `scrollcraft.css` themes all of these; if you fork
|
|
248
|
+
it, keep them:
|
|
249
|
+
|
|
250
|
+
selection colour, caret colour, focus ring, scrollbar, underline offset and
|
|
251
|
+
thickness, tabular numerals in anything that counts or tabulates.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## The refuse list
|
|
256
|
+
|
|
257
|
+
Category defaults, not bans on principle. The brief's own words can earn any of
|
|
258
|
+
them; reaching for one when the axis is free means you were not deciding.
|
|
259
|
+
|
|
260
|
+
**Structure**
|
|
261
|
+
- Identical cards as page structure. Nested cards. Three equal feature columns.
|
|
262
|
+
- The hero-metric template: big number, small label, supporting stats, accent.
|
|
263
|
+
- More than two consecutive image-left / text-right zigzag sections.
|
|
264
|
+
- The same layout family twice on one page.
|
|
265
|
+
- A split header: giant headline left, small explainer paragraph floating right.
|
|
266
|
+
|
|
267
|
+
**Labels**
|
|
268
|
+
- An eyebrow above every section heading. At most one per three sections.
|
|
269
|
+
- Section numbers (`01 / 06`, `002 · Capabilities`) unless the sequence itself
|
|
270
|
+
is information the reader needs.
|
|
271
|
+
- Scroll cues: "scroll", "↓ scroll", "scroll to explore", animated mouse icons.
|
|
272
|
+
They are looking at the hero. They know.
|
|
273
|
+
- Decoration text strips (`BRAND. MOTION. SPATIAL.`) across the hero bottom.
|
|
274
|
+
- Locale, time and weather strips unless the brand is genuinely about a place.
|
|
275
|
+
- Pills and tags overlaid on photos. Version stamps on a marketing page.
|
|
276
|
+
|
|
277
|
+
**Surface**
|
|
278
|
+
- Gradient text. Neon and outer glows. Hard offset zero-blur shadows outside a
|
|
279
|
+
world that is actually neobrutalist.
|
|
280
|
+
- Glass and blur as decoration rather than as a specific effect.
|
|
281
|
+
- Coloured `border-left` above 1px on cards, callouts or list items.
|
|
282
|
+
- Monospace as a costume for "technical" rather than for code, data, or labels.
|
|
283
|
+
- Emoji standing in for an icon system. Use a real icon library.
|
|
284
|
+
- Custom cursors.
|
|
285
|
+
|
|
286
|
+
**Content**
|
|
287
|
+
- Em dash anywhere visible. Period, comma, colon, or parentheses.
|
|
288
|
+
- Div-built fake screenshots, fake dashboards, fake terminals.
|
|
289
|
+
- Text baked into a generated image. Real markup, always.
|
|
290
|
+
- Filler verbs: elevate, seamless, unleash, next-gen, revolutionize, supercharge.
|
|
291
|
+
- A hero that overflows the viewport. Headline max two lines, subtext max 20
|
|
292
|
+
words, CTA visible without scrolling.
|
|
293
|
+
- More than four text elements in the hero. Trust logos, pricing teasers and
|
|
294
|
+
micro-taglines move to their own section below it.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## The squint test
|
|
299
|
+
|
|
300
|
+
Blur the page until detail is gone. You should still be able to name the
|
|
301
|
+
primary element, the secondary element, and the major groups, in that order.
|
|
302
|
+
|
|
303
|
+
If everything greys into one even field, the problem is hierarchy, and no amount
|
|
304
|
+
of shadow, gradient or motion will fix it.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<!--
|
|
3
|
+
luckiest-design-website skeleton.
|
|
4
|
+
|
|
5
|
+
Start here, then delete what you do not need and write your own markup for
|
|
6
|
+
what you keep. This is a starting point, not a layout: a page that keeps this
|
|
7
|
+
structure verbatim will look like every other page that kept it verbatim,
|
|
8
|
+
which is the failure this skill exists to avoid.
|
|
9
|
+
|
|
10
|
+
The act order below is one score (scrub > pin > flow > scrub > pan > pin).
|
|
11
|
+
Score YOUR journey per SKILL.md Step 2 and rearrange accordingly. The rules
|
|
12
|
+
that do carry over: four or more device families, never the same one twice in
|
|
13
|
+
a row, at most two scrub acts, and the closing act is the last element on the
|
|
14
|
+
page.
|
|
15
|
+
-->
|
|
16
|
+
<html lang="en">
|
|
17
|
+
<head>
|
|
18
|
+
<meta charset="utf-8">
|
|
19
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
20
|
+
<title>BRAND · the one-line promise</title>
|
|
21
|
+
<meta name="description" content="One sentence a search result would show.">
|
|
22
|
+
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='7' fill='%230A0807'/></svg>">
|
|
23
|
+
<link rel="stylesheet" href="scrollcraft.css">
|
|
24
|
+
<style>
|
|
25
|
+
/* The whole rebrand: six colours and two faces. Everything else in
|
|
26
|
+
scrollcraft.css derives from these. */
|
|
27
|
+
:root {
|
|
28
|
+
--sc-canvas: #08090b;
|
|
29
|
+
--sc-surface: #101217;
|
|
30
|
+
--sc-ink: #f4f2ef;
|
|
31
|
+
--sc-ink-soft: #9a9ba1;
|
|
32
|
+
--sc-accent: #d8ff3e;
|
|
33
|
+
--sc-accent-ink: #08090b;
|
|
34
|
+
--sc-font-display: "Archivo", system-ui, sans-serif;
|
|
35
|
+
--sc-font-text: "Geist", system-ui, sans-serif;
|
|
36
|
+
}
|
|
37
|
+
/* Your page's own classes go here. Do not restyle .sc-stage, .sc-copy or any
|
|
38
|
+
[data-sc-*] selector: those are the mechanism. */
|
|
39
|
+
</style>
|
|
40
|
+
</head>
|
|
41
|
+
<body>
|
|
42
|
+
|
|
43
|
+
<span data-sc-progress></span>
|
|
44
|
+
<div class="sc-grain" aria-hidden="true"></div>
|
|
45
|
+
|
|
46
|
+
<header class="site-bar"><!-- mark + ONE cta label, used everywhere --></header>
|
|
47
|
+
|
|
48
|
+
<main id="top">
|
|
49
|
+
|
|
50
|
+
<!-- 1 · RECOGNITION: scrub -->
|
|
51
|
+
<section data-sc-act="scrub" data-sc-span="2.6" data-sc-dwell="0.34" data-sc-drift="#08090b">
|
|
52
|
+
<div data-sc-stage>
|
|
53
|
+
<img class="sc-stage__poster" src="assets/01-poster.webp" alt="">
|
|
54
|
+
<video data-sc-scrub data-sc-src="assets/01.mp4"
|
|
55
|
+
data-sc-src-mobile="assets/01-m.mp4" muted playsinline></video>
|
|
56
|
+
<div class="sc-scrim sc-scrim--lead" aria-hidden="true"></div>
|
|
57
|
+
<!-- third value 0 = greet: on screen the instant the page lands -->
|
|
58
|
+
<div class="sc-copy sc-copy--lead" data-sc-cue="0 0.78 0">
|
|
59
|
+
<h1 class="sc-display sc-display--xl" data-sc-kinetic="lines">The promise, in under nine words.</h1>
|
|
60
|
+
<p class="sc-body">One plain sentence. Twenty words at the outside.</p>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</section>
|
|
64
|
+
|
|
65
|
+
<!-- 2 · TENSION: pin. Overlap the windows ~15% so there is never a gap. -->
|
|
66
|
+
<section data-sc-act="pin" data-sc-span="3.4" data-sc-drift="#101217">
|
|
67
|
+
<div data-sc-stage class="argument">
|
|
68
|
+
<p data-sc-cue="0 0.32 0">The situation they recognise.</p>
|
|
69
|
+
<p data-sc-cue="0.26 0.60">What it actually costs them.</p>
|
|
70
|
+
<p data-sc-cue="0.54 0.88">Why it keeps happening.</p>
|
|
71
|
+
<p data-sc-cue="0.82">The line that turns it.</p>
|
|
72
|
+
</div>
|
|
73
|
+
</section>
|
|
74
|
+
|
|
75
|
+
<!-- 3 · TURN: flow + reveal -->
|
|
76
|
+
<section class="sc-section" data-sc-act="flow" data-sc-drift="#0b0c0f">
|
|
77
|
+
<div class="sc-wrap split">
|
|
78
|
+
<div class="sc-stack" data-sc-in data-sc-stagger="70">
|
|
79
|
+
<h2 class="sc-display sc-display--lg">What changes.</h2>
|
|
80
|
+
<p class="sc-body">Two short paragraphs. This is the only act that reads like a document, which is exactly why it belongs here.</p>
|
|
81
|
+
</div>
|
|
82
|
+
<figure data-sc-reveal="left" data-sc-reveal-at="0.18 0.62">
|
|
83
|
+
<img src="assets/03.webp" width="1920" height="1080" alt="Describe the image, not the brand.">
|
|
84
|
+
</figure>
|
|
85
|
+
</div>
|
|
86
|
+
</section>
|
|
87
|
+
|
|
88
|
+
<!-- 4 · SUBSTANCE: scrub. The second and LAST clip. -->
|
|
89
|
+
<section data-sc-act="scrub" data-sc-span="2.2" data-sc-dwell="0.28" data-sc-drift="#0e0f13">
|
|
90
|
+
<div data-sc-stage>
|
|
91
|
+
<img class="sc-stage__poster" src="assets/04-poster.webp" alt="">
|
|
92
|
+
<video data-sc-scrub data-sc-src="assets/04.mp4"
|
|
93
|
+
data-sc-src-mobile="assets/04-m.mp4" muted playsinline></video>
|
|
94
|
+
<div class="sc-scrim sc-scrim--trail" aria-hidden="true"></div>
|
|
95
|
+
<div class="sc-copy sc-copy--trail" data-sc-cue="0.14 0.86">
|
|
96
|
+
<h2 class="sc-display sc-display--lg" data-sc-kinetic="lines">The proof, in one line.</h2>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</section>
|
|
100
|
+
|
|
101
|
+
<!-- 5 · RANGE: pan. Span ≈ one viewport-height per item, plus one. -->
|
|
102
|
+
<section data-sc-act="pan" data-sc-span="3.2" data-sc-drift="#0a0b0d">
|
|
103
|
+
<div data-sc-stage>
|
|
104
|
+
<div class="rail" data-sc-pan="0.06">
|
|
105
|
+
<div class="rail__lead sc-stack">
|
|
106
|
+
<h2 class="sc-display sc-display--md">The set.</h2>
|
|
107
|
+
<p class="sc-body">One line on how to choose.</p>
|
|
108
|
+
</div>
|
|
109
|
+
<article class="item"><div data-sc-tilt="6"><img src="assets/item-1.webp" alt=""></div><h3>One</h3><p>…</p></article>
|
|
110
|
+
<article class="item"><div data-sc-tilt="6"><img src="assets/item-2.webp" alt=""></div><h3>Two</h3><p>…</p></article>
|
|
111
|
+
<article class="item"><div data-sc-tilt="6"><img src="assets/item-3.webp" alt=""></div><h3>Three</h3><p>…</p></article>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</section>
|
|
115
|
+
|
|
116
|
+
<!-- 6 · COMMITMENT: pin + pointer. LAST element on the page, short span,
|
|
117
|
+
one-value cues so nothing fades out before the page ends, footer inside
|
|
118
|
+
the stage so there is no dead tail after the CTA. -->
|
|
119
|
+
<section id="join" data-sc-act="pin" data-sc-span="1.15" data-sc-drift="#08090b">
|
|
120
|
+
<div data-sc-stage class="close" data-sc-spotlight>
|
|
121
|
+
<div class="close__inner">
|
|
122
|
+
<h2 class="sc-display sc-display--lg" data-sc-cue="0.06" data-sc-kinetic="lines">The last thing you want them to feel.</h2>
|
|
123
|
+
<!-- magnet and cue both write transform, and the magnet writes it every
|
|
124
|
+
frame. data-sc-rise="0" makes the cue's rise a no-op so the
|
|
125
|
+
entrance is not silently lost to the race. Opens early so a
|
|
126
|
+
keyboard user cannot land on it at opacity 0. -->
|
|
127
|
+
<a class="cta" href="#" data-sc-magnet="0.26" data-sc-cue="0.06" data-sc-rise="0">Same label as the nav</a>
|
|
128
|
+
</div>
|
|
129
|
+
<footer class="foot"><!-- mark + the small print --></footer>
|
|
130
|
+
</div>
|
|
131
|
+
</section>
|
|
132
|
+
|
|
133
|
+
</main>
|
|
134
|
+
|
|
135
|
+
<script src="scrollcraft.js"></script>
|
|
136
|
+
<script>ScrollCraft.mount(document.body);</script>
|
|
137
|
+
</body>
|
|
138
|
+
</html>
|