Skip to main content

max / makenotwork

8.9 KB · 252 lines History Blame Raw
1 /* ============================================================================
2 LAYER HANDOFFS
3
4 Everything below gives a property back to @layer makeover rather than
5 setting one. This file is in @layer components and the order statement puts
6 it after `makeover`, so every rule here wins over the design system whatever
7 the specificity -- including the bare `button`, `a` and `input` rules further
8 up, which carry no class and so reach every described component the site
9 renders. That is the whole reason this section exists: without it a described
10 act takes this file's chrome instead of the one makeover drew for it, and the
11 difference is invisible in the source of either file.
12
13 `revert-layer` is the deferral. It names no value, so the design system can
14 change what a chip looks like without this file learning about it.
15
16 Two rules govern how these are written, and both are load-bearing:
17
18 - Hand a property back on the arms makeover actually paints, not on the
19 plain class. Makeover gives a chip a colour only when it is disabled, so
20 `.chip { color: revert-layer }` would roll a live chip back past this
21 file's `button { color }` to the UA default rather than to anything
22 makeover chose.
23 - Outrank the rule being deferred past. Both rules are this file's and both
24 are in the same layer, so that contest is decided by specificity and then
25 by source order. `.field` does not beat `input[type="text"]`, which is
26 why the field handoffs are element-qualified, and this section sits at
27 the end of the file so an equal-specificity handoff still wins.
28
29 makeover-build's check_vocabulary reads both halves and fails the build on a
30 pair that has neither a handoff nor a reviewed exception, so this section
31 cannot fall behind the design system without somebody being told.
32 ============================================================================ */
33
34 /* The surfaces a bare `button` was taking. `.card`, `.tab` and the two facet
35 controls are all rendered as buttons by the described screens. */
36 .card,
37 .tab,
38 .facet-take,
39 .facet-prune {
40 /* respec-ok: a layer handoff, not a value. */
41 background: revert-layer;
42 box-shadow: revert-layer;
43 }
44
45 .card:hover,
46 .tab:hover,
47 .facet-take:hover,
48 .facet-prune:hover {
49 /* respec-ok: a layer handoff, not a value. */
50 background: revert-layer;
51 }
52
53 .card:active,
54 .tab:active,
55 .facet-take:active,
56 .facet-prune:active {
57 /* respec-ok: a layer handoff, not a value. */
58 background: revert-layer;
59 box-shadow: revert-layer;
60 }
61
62 /* A facet control's colour is makeover's in every state: muted when disabled,
63 secondary when the value it names is not standing, inherited otherwise.
64 There is no arm of it this file has an opinion about. */
65 .facet-take,
66 .facet-prune {
67 /* respec-ok: a layer handoff, not a value. */
68 color: revert-layer;
69 }
70
71 /* The disabled arm. Makeover paints all four properties here -- muted text, the
72 not-allowed cursor, and the surface it keeps rather than dropping -- and this
73 file's `button:disabled` was taking every one of them. */
74 .button:disabled,
75 .button[aria-disabled="true"],
76 .card:disabled,
77 .card[aria-disabled="true"],
78 .chip:disabled,
79 .chip[aria-disabled="true"],
80 .tab:disabled,
81 .tab[aria-disabled="true"],
82 .segment:disabled,
83 .segment[aria-disabled="true"],
84 .toggle:disabled,
85 .toggle[aria-disabled="true"],
86 .field:disabled,
87 .field[aria-disabled="true"],
88 .facet-take:disabled,
89 .facet-take[aria-disabled="true"],
90 .facet-prune:disabled,
91 .facet-prune[aria-disabled="true"] {
92 /* respec-ok: a layer handoff, not a value. */
93 background: revert-layer;
94 box-shadow: revert-layer;
95 color: revert-layer;
96 cursor: revert-layer;
97 }
98
99 /* The focus ring. Makeover insets a field's so it does not collide with the
100 bevel and leaves every other one outside, and this file's `:focus-visible`
101 rules were flattening the distinction on every described control. */
102 .button:focus-visible,
103 .card:focus-visible,
104 .chip:focus-visible,
105 .link:focus-visible,
106 .tab:focus-visible,
107 .segment:focus-visible,
108 .toggle:focus-visible,
109 .facet-take:focus-visible,
110 .facet-prune:focus-visible {
111 /* respec-ok: a layer handoff, not a value. */
112 outline: revert-layer;
113 outline-offset: revert-layer;
114 }
115
116 /* A described field is an `<input>`, a `<select>` or a `<textarea>`, and the
117 rules for those three carry an attribute, so the handoff has to as well: a
118 bare `.field` is the weaker selector and loses inside this layer. The `:focus`
119 arm is here because this file sets `outline: none` on it, which removes the
120 ring makeover draws on `:focus-visible` rather than replacing it. */
121 input.field,
122 select.field,
123 textarea.field,
124 input.field:hover,
125 select.field:hover,
126 textarea.field:hover,
127 input.field:active,
128 select.field:active,
129 textarea.field:active {
130 /* respec-ok: a layer handoff, not a value. */
131 background: revert-layer;
132 box-shadow: revert-layer;
133 }
134
135 input.field:focus,
136 select.field:focus,
137 textarea.field:focus,
138 input.field:focus-visible,
139 select.field:focus-visible,
140 textarea.field:focus-visible {
141 /* respec-ok: a layer handoff, not a value. */
142 outline: revert-layer;
143 outline-offset: revert-layer;
144 }
145
146 /* A described toggle is an `<input>` too. The hover and active arms are here
147 for the same reason as the field's: this file dresses `input[type="submit"]`
148 as a raised button in every state, and a toggle is an input. */
149 input.toggle,
150 input.toggle:hover,
151 input.toggle:active,
152 input.toggle:focus,
153 input.toggle:focus-visible {
154 /* respec-ok: a layer handoff, not a value. */
155 background: revert-layer;
156 box-shadow: revert-layer;
157 outline: revert-layer;
158 outline-offset: revert-layer;
159 }
160
161 /* A described link on hover. `.link` above hands the resting colour back; this
162 file's `a:hover` is the more specific of the two and was taking the hover
163 colour and the underline with it. */
164 .link:hover {
165 /* respec-ok: a layer handoff, not a value. */
166 color: revert-layer;
167 text-decoration: revert-layer;
168 }
169
170 /* Text makeover mutes: a facet's name, and the line a placeholder shows when
171 there is nothing to list. This file's bare `p` rule was giving both the body
172 colour. */
173 .facet-name,
174 .placeholder-text {
175 /* respec-ok: a layer handoff, not a value. */
176 color: revert-layer;
177 }
178
179 /* ===========================================
180 DESCRIBED MODAL (quasi RegionKind::Modal)
181 ===========================================
182 The first described modal on this host is the media picker; these two rules
183 are what "modal" means here, and every one after it gets them for free. The
184 description says the region IS a modal and says nothing about where it sits,
185 which is the division the vocabulary draws: `role="dialog" aria-modal="true"`
186 comes off the renderer, and a dialog that lays out in flow would make that
187 attribute a lie.
188
189 Two boxes because a scrim and a panel are two boxes: the modal region covers
190 the viewport and takes the presses the page behind it must not get, and the
191 region inside it is the panel. */
192 .region.modal {
193 position: fixed;
194 inset: 0;
195 z-index: var(--z-overlay);
196 display: flex;
197 align-items: center;
198 justify-content: center;
199 background: var(--overlay);
200 }
201
202 .region.modal > .region {
203 position: relative;
204 z-index: var(--z-modal);
205 width: 90%;
206 max-width: 700px;
207 max-height: 80vh;
208 overflow-y: auto;
209 padding: var(--gap-section);
210 background: var(--surface-overlay);
211 box-shadow: var(--elevation-overlay);
212 }
213
214 /* ===========================================
215 MEDIA PICKER (crate::quasi::media_picker)
216 ===========================================
217 Addressed by the widget names the description carries, not by ids: a document
218 holds one picker per markdown editor and their ids differ by destination,
219 while what they are drawn like is the same assembly every time. */
220 [data-widget="media-picker-grid"] {
221 display: grid;
222 grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
223 gap: var(--gap-peer);
224 margin-top: var(--gap-section);
225 }
226
227 /* The tile IS the control, since quasi 0.69.0 (`Act::shows`). It was a
228 `media-tile` region holding a picture and a button as siblings, and only the
229 button answered a press; a reader aiming at the thumbnail hit nothing. The
230 widget name went with the region, so the tile is addressed as the button
231 inside the grid. */
232 [data-widget="media-picker-grid"] .button {
233 display: flex;
234 flex-direction: column;
235 gap: var(--gap-peer);
236 min-width: 0;
237 /* The file name wraps rather than pushing the tile wide. */
238 overflow-wrap: anywhere;
239 text-align: left;
240 font-size: var(--text-note);
241 }
242
243 /* A cap, not a height, and never a bare `img`. The design system already sets
244 the picture's width, height and background, and an app rule taking any of
245 those wins over `@layer makeover` silently — which is what `makeover-build`'s
246 drift check refuses, and it is right to. `max-height` is not one of them, and
247 it is all this needs: `Fit::Contain` is in the description, so a capped
248 picture letterboxes inside the cap rather than being cropped or stretched. */
249 [data-widget="media-picker-grid"] .picture-img {
250 max-height: 80px;
251 }
252