-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpointer.css
More file actions
237 lines (177 loc) · 11.7 KB
/
Copy pathpointer.css
File metadata and controls
237 lines (177 loc) · 11.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/* Pointer-reactive specimens. The CSS here only builds the parts; every value
that moves is written by pointer.js each frame, so nothing has a transition
on the property JavaScript drives. Same base, same palette, same rest state. */
.fx[data-p]{transition:none}
.fx .ink{position:absolute;background:#000;z-index:1;pointer-events:none}
/* 37 Magnet, 43 Pointer tilt, 44 Wobble tilt, 45 Squash: transform only */
.fx-magnet,.fx-ptilt,.fx-wobble,.fx-squash{will-change:transform}
.fx-ptilt,.fx-wobble{transform-style:preserve-3d}
/* 38 Label magnet, 46 Label lag, 49 Speed tracking: the label alone moves */
.fx-maglabel .label,.fx-lag .label,.fx-speed .label{will-change:transform}
.fx-speed .label{letter-spacing:.08em;padding-left:.08em}
/* 39 Ink bleed: a full black plate, clipped to a disc at the entry point */
.fx-bleed .ink{inset:-2px;clip-path:circle(0 at 50% 50%)}
/* 40 Follow disc */
.fx-disc .ink{left:0;top:0;width:68px;height:68px;border-radius:50%;transform:scale(0)}
/* 41 Direction fill, 42 Direction out */
.fx-dirfill .ink,.fx-dirout .ink{inset:0;transform:translate(-101%,0)}
/* 47 Edge bulge, 48 Elastic frame: the drawn border replaces the CSS one */
.fx-bulge,.fx-cloth{border-color:transparent}
.fx-bulge svg,.fx-cloth svg{overflow:visible;stroke-linejoin:round}
/* 50 Press ripple: a ring, not a fade, so no grey enters the palette */
.fx-ripple{overflow:hidden}
.fx-ripple .ink{left:50%;top:50%;width:96px;height:96px;border-radius:50%;background:none;border:2px solid #000;transform:translate(-50%,-50%) scale(0);visibility:hidden}
/* 51 Proximity wake: the rule itself thickens as --near rises from 0 to 1.
Border-box, so nothing shifts; at rest it is the same 2px as every specimen. */
.fx-awake{--near:0;border-width:calc(2px + var(--near) * 4px)}
/* 52 Cast shadow: box-shadow offset is written per frame */
.fx-cast{will-change:box-shadow}
/* 53 Label repel, 56 Slinky: the label, or its letters, move */
.fx-repel .label{will-change:transform}
.fx-slinky .label i{display:inline-block;font-style:normal;will-change:transform}
/* 54 Lean, 55 Sway, 57 Dimple, 71 Swell, 72 Rise to meet: transform only */
.fx-lean,.fx-sway,.fx-dimple,.fx-swell,.fx-rise{will-change:transform}
/* 58 Fill to pointer, 66 Dwell bloom: a full plate, clipped. Plates that are
clipped sit at inset:-2px, under the rule, so the clip edge never antialiases
against the border and border-box coordinates (ex ey lx ly) land exactly */
.fx-reach .ink{inset:-2px;clip-path:inset(0 100% 0 0)}
.fx-dwell .ink{inset:-2px;clip-path:circle(0 at 50% 50%)}
/* 59 Angle wipe: a plate large enough to cover at any angle, parked outside */
.fx-angle .ink{left:50%;top:50%;width:320px;height:320px;transform:translate(-50%,-50%) rotate(180deg) translateX(260px)}
/* 60 Momentum */
.fx-momentum .ink{inset:0;transform:translate(-101%,0)}
/* 61 Pinhole: black plate, white hole under the label */
.fx-pinhole .ink{inset:0;visibility:hidden}
.fx-pinhole .hole{position:absolute;left:0;top:0;width:44px;height:44px;border-radius:50%;background:#fff;z-index:2;pointer-events:none;transform:scale(0)}
/* 62 Reticle: hollow ring */
.fx-reticle .ink{left:0;top:0;width:36px;height:36px;border-radius:50%;background:none;border:2px solid #000;transform:scale(0)}
/* 63 Crosshair */
.fx-xhair .hx,.fx-xhair .vy{position:absolute;left:0;top:0;background:#000;z-index:1;pointer-events:none}
.fx-xhair .hx{width:100%;height:2px;transform:scaleX(0)}
.fx-xhair .vy{width:2px;height:100%;transform:scaleY(0)}
/* 64 Scanner bar */
.fx-scan .ink{left:0;top:0;width:20px;height:100%;transform:scaleY(0)}
/* 65 Comet: four discs, largest leads */
.fx-comet .dot{position:absolute;left:0;top:0;border-radius:50%;background:#000;z-index:1;pointer-events:none;transform:scale(0)}
.fx-comet .d1{width:40px;height:40px}
.fx-comet .d2{width:28px;height:28px}
.fx-comet .d3{width:18px;height:18px}
.fx-comet .d4{width:10px;height:10px}
/* 67 Corner pull, 68 Push in: drawn border replaces the CSS one */
.fx-cpull,.fx-push{border-color:transparent}
.fx-cpull svg,.fx-push svg{overflow:visible;stroke-linejoin:round}
/* 69 Gap follows, 70 Bead: drawn border; the gap or bead rides on it */
.fx-gap,.fx-bead{border-color:transparent}
.fx-gap svg,.fx-bead svg{overflow:visible}
.fx-bead circle{fill:#000;stroke:none}
/* ---- variable font. Inter is loaded as a variable font (wght 100..900,
opsz 14..32); weight and optical size are written per frame. Per-letter
specimens split the label into <i> elements. ---- */
.fx .label i{display:inline-block;font-style:normal;font-weight:inherit;transform-origin:50% 100%;will-change:transform}
.fx-bolden .label,.fx-weightx .label,.fx-wspeed .label,.fx-wdwell .label,.fx-holdw .label,.fx-wkeys .label i,.fx-wripple .label i{font-weight:600}
.fx-opsz .label{font-variation-settings:"opsz" 14}
.fx-xtrack .label{letter-spacing:.08em}
.fx-holdw .label{letter-spacing:1.12px}
.fx-face .label i{transform-origin:50% 60%}
/* ---- hatching and halftone. Fills built from lines, dots and dither cells,
all black on the white plate; the pointer writes sizes, never colours. ---- */
/* 87 Hatch fill: the ink plate carries a repeating-linear-gradient written per frame */
.fx-hatch .ink{inset:0;background:none}
/* 89 Stipple bleed: the solid core is the ink plate clipped to a disc at the entry point */
.fx-stipple .ink{inset:-2px;clip-path:circle(0 at 50% 50%)}
/* 88 Halftone bloom, 89 Stipple bleed, 90 Dither wipe: an SVG the size of the
inner plate; circles and rects are created once and resized per frame */
.fx-halftone svg,.fx-stipple svg,.fx-dither svg{left:0;top:0;width:100%;height:100%;fill:#000;stroke:none;z-index:1}
.fx-dither svg{shape-rendering:crispEdges}
/* ---- intent and prediction. Timing and heading decide the fill; the ink
plate is the same full black plate, clipped or rotated per frame. ---- */
/* Anticipation: full plate, clipped to a disc at the predicted landing point */
.fx-predict .ink{inset:0;clip-path:circle(0px at 50% 50%)}
/* Hover intent: full plate, clipped to nothing at the centre until committed */
.fx-intent .ink{inset:0;clip-path:inset(24px 80px)}
/* Exit grace: full plate, clipped to a zero-height band at the middle */
.fx-linger .ink{inset:0;clip-path:inset(24px 0px)}
/* Approach angle: a plate large enough to cover at any angle, parked outside */
.fx-heading .ink{left:50%;top:50%;width:320px;height:320px;transform:translate(-50%,-50%) rotate(0deg) translateX(260px)}
/* ---- press, hold and release. Everything here runs from pointerdown; a hover
alone writes nothing, so the rest state is the plain button. ---- */
/* Hold to confirm: a plate clipped from the right, opening left to right. It
overhangs the padding box by 2px so the clip-path edge never anti-aliases
against the border; the button's overflow clip trims it. */
.fx-confirm .ink{inset:-2px;clip-path:inset(0 100% 0 0)}
/* Press depth by pressure: scale and inner shadow are written per frame */
.fx-depth{will-change:transform,box-shadow}
/* Drag-off cancel: a full plate parked below the box */
.fx-dragoff .ink{inset:0;transform:translate(0,101%)}
/* Release bounce, Throw: transform only */
.fx-rebound,.fx-throw{will-change:transform}
/* ---- keyboard and focus. Nothing here responds to hover: focus, Tab
direction and Space or Enter drive the values, written per frame. The
base focus ring stays as it is; the effect sits alongside it. ---- */
/* Direction-aware focus: a full plate parked off the left edge; the frame writes the side */
.fx-tabfill .ink{inset:0;transform:translate(-101%,0)}
/* Key press: transform and inner shadow are written per frame */
.fx-spacebar{will-change:transform,box-shadow}
/* Focus dwell: weight written per frame, 600 at rest */
.fx-fdwell .label{font-weight:600}
/* ---- shape morph: the CSS border is transparent and the rule is an SVG
path redrawn per frame, so the 2px stroke follows the changed outline.
Miter joins, not round, so the rest rectangle has the same square corners
as the CSS border; every join in these shapes is wider than 45 degrees. ---- */
.fx-tail,.fx-notch,.fx-chamfer,.fx-rounds,.fx-shear{border-color:transparent}
.fx-tail svg,.fx-notch svg,.fx-chamfer svg,.fx-rounds svg,.fx-shear svg{overflow:visible}
/* ---- physics beyond springs. Masses, gravity and elastic ties; every value
is written per frame and cleared at rest. ---- */
/* Jelly: the drawn outline replaces the CSS border */
.fx-jelly{border-color:transparent}
.fx-jelly svg{overflow:visible;stroke-linejoin:round}
/* Pendulum: hangs from the middle of the top edge */
.fx-pendulum{transform-origin:50% 0;will-change:transform}
/* Rubber band, Weight drop: the label alone moves */
.fx-rubber .label,.fx-thud .label{will-change:transform}
/* ---- cursor. The pointer itself is the effect: the system cursor is hidden
over these three stages and a drawn cursor, a child of the button, takes
its place. It may leave the box, so none of these clip. The dot is hidden
at rest and shown by pointer.js only while the pointer is over the stage. ---- */
/* Cursor becomes button: an 8px dot that is resized into the full plate */
.stage:has(.fx-become){cursor:none}
.fx-become{cursor:none}
.fx-become .cur{position:absolute;left:0;top:0;width:8px;height:8px;border-radius:50%;background:#000;z-index:1;pointer-events:none;visibility:hidden}
/* Sticky cursor: the same dot, moved by transform only */
.stage:has(.fx-sticky){cursor:none}
.fx-sticky{cursor:none}
.fx-sticky .cur{position:absolute;left:0;top:0;width:8px;height:8px;border-radius:50%;background:#000;z-index:1;pointer-events:none;visibility:hidden;will-change:transform}
/* Inverting cursor: a white disc in difference blend. The button drops its
isolation so the disc blends with the page and reads black on the stage;
the label keeps its own difference blend and stays legible over the disc. */
.stage:has(.fx-lens){cursor:none}
.fx-lens{cursor:none;isolation:auto}
.fx-lens .ink{inset:0;visibility:hidden}
.fx-lens .cur{position:absolute;left:0;top:0;width:24px;height:24px;border-radius:50%;background:#fff;mix-blend-mode:difference;z-index:2;pointer-events:none;visibility:hidden;will-change:transform}
/* Reduced motion turns the engine off, so the system cursor must come back */
@media (prefers-reduced-motion:reduce){
.stage:has(.fx-become),.stage:has(.fx-sticky),.stage:has(.fx-lens){cursor:auto}
.fx-become,.fx-sticky,.fx-lens{cursor:pointer}
}
/* ---- SVG filters. Each specimen carries its own <filter> in a zero-size SVG
inside the button, referenced by url(#id). The primitive's attribute is
written per frame; the filter property is cleared at rest so the resting
render is the plain button, pixel for pixel. ---- */
.fx-displace .fdef,.fx-dilate .fdef,.fx-thresh .fdef{position:absolute;left:0;top:0;width:0;height:0;overflow:hidden}
.fx-displace,.fx-thresh{will-change:filter}
.fx-dilate .label{will-change:filter}
/* ---- after the press. States that begin on a completed click and return to
rest on their own; hovering or resting the pointer does nothing. ---- */
/* Pending fill: a full plate clipped to the progress band, nothing at rest */
.fx-pending .ink{inset:0;clip-path:inset(0 100% 0 0)}
/* Success check: one path holds the border run, the connector and the check;
a zero-length dash hides all of it at rest. The label slides, so it is clipped */
.fx-check path{stroke-dasharray:0 1000}
.fx-check .label{will-change:transform}
/* Error settle: transform only */
.fx-shake{will-change:transform}
/* Undo countdown: a bar along the bottom edge, scaled from its left end */
.fx-undo .ink{left:0;right:0;bottom:0;height:5px;transform:scaleX(0);transform-origin:0 50%}
/* ---- label content. The word changes, not the box: pointer.js fixes each
letter at its rest width once fonts load; glyphs are centred inside it. ---- */
.fx-scramble .label i,.fx-type .label i,.fx-swap .label i,.fx-case .label i{text-align:center}