PluginProbe
Hash Form – Drag & Drop Form Builder / trunk
Hash Form – Drag & Drop Form Builder vtrunk
1.4.4 1.4.3 1.4.2 1.4.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.6.1 1.2.7 1.2.8 1.2.9 1.3.0 All 47 releases
hash-form / css / builder.css

builder.css in Hash Form – Drag & Drop Form Builder trunk, at css/builder.css

1,359 lines 37.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Form builder.
3 *
4 * Loaded after admin-style.css so these rules win, letting the builder move to
5 * the token system without unpicking 2,600 lines of legacy CSS in one go. The
6 * remaining screens follow the same pattern as they are reworked.
7 */
8
9 /* ---------- Shell ---------- */
10
11 /* The workspace sits a shade darker than the panels on it, which is what lets
12 the header, sidebar and canvas read as separate surfaces without needing a
13 border between every pair. */
14 .hf-content {
15 --hf-workspace: #eef1f6;
16 background: var(--hf-workspace);
17 }
18
19 .hf-content .hf-body {
20 align-items: stretch;
21 background: var(--hf-workspace);
22 display: flex;
23 gap: var(--hf-space-3);
24 height: 100%;
25 overflow: hidden;
26 padding: var(--hf-space-3);
27 }
28
29 .hf-content .hf-fields-sidebar {
30 background: var(--hf-surface);
31 border: 1px solid var(--hf-border);
32 border-radius: var(--hf-radius-lg);
33 box-shadow: var(--hf-shadow-md);
34 flex: 0 0 360px;
35 overflow: hidden auto;
36 scrollbar-width: thin;
37 width: 360px;
38 }
39
40 .hf-content .hf-fields-sidebar::-webkit-scrollbar {
41 width: 8px;
42 }
43
44 .hf-content .hf-fields-sidebar::-webkit-scrollbar-track {
45 background: transparent;
46 }
47
48 .hf-content .hf-fields-sidebar::-webkit-scrollbar-thumb {
49 background: var(--hf-border-strong);
50 border-radius: var(--hf-radius-pill);
51 }
52
53 .hf-content #hf-form-panel {
54 background: transparent;
55 flex-grow: 1;
56 overflow: hidden auto;
57 padding: 0;
58 scrollbar-width: thin;
59 }
60
61 .hf-content #hf-form-panel::-webkit-scrollbar {
62 width: 10px;
63 }
64
65 .hf-content #hf-form-panel::-webkit-scrollbar-track {
66 background: transparent;
67 }
68
69 .hf-content #hf-form-panel::-webkit-scrollbar-thumb {
70 background: var(--hf-border-strong);
71 border-radius: var(--hf-radius-pill);
72 }
73
74 /* ---------- Sidebar tabs ---------- */
75
76 /* A segmented control rather than underlined tabs: it reads as one component,
77 matches the language of the header, and makes the active panel obvious
78 without a second border under an already bordered sidebar. */
79 .hf-content .hf-fields-tabs {
80 background: var(--hf-surface);
81 border-bottom: 1px solid var(--hf-border);
82 border-radius: var(--hf-radius-lg) var(--hf-radius-lg) 0 0;
83 border-top: 0;
84 display: flex;
85 gap: 0;
86 margin: 0;
87 padding: var(--hf-space-3);
88 position: sticky;
89 top: 0;
90 z-index: 9;
91 }
92
93 .hf-content .hf-fields-tabs::before {
94 background: rgba(16, 24, 40, .05);
95 border-radius: var(--hf-radius-sm);
96 content: "";
97 inset: var(--hf-space-3);
98 position: absolute;
99 }
100
101 .hf-content .hf-fields-tabs li {
102 flex: 1 1 0;
103 font-size: var(--hf-font-base);
104 margin: 0;
105 position: relative;
106 text-align: center;
107 z-index: 1;
108 }
109
110 .hf-content .hf-fields-tabs li a {
111 border: 0;
112 border-radius: 3px;
113 box-shadow: none;
114 color: var(--hf-text-muted);
115 display: block;
116 font-size: var(--hf-font-sm);
117 font-weight: 500;
118 margin: 2px;
119 outline: 0;
120 padding: var(--hf-space-2) var(--hf-space-1);
121 position: relative;
122 text-decoration: none;
123 text-transform: none;
124 transition: background-color var(--hf-transition), color var(--hf-transition), box-shadow var(--hf-transition);
125 /* Three tabs in a 300px rail: keep them on one line. */
126 white-space: nowrap;
127 }
128
129 .hf-content .hf-fields-tabs li a:hover {
130 color: var(--hf-text);
131 }
132
133 .hf-content .hf-fields-tabs li.hf-active-tab a {
134 background: var(--hf-surface);
135 border: 0;
136 box-shadow: var(--hf-shadow-sm);
137 color: var(--hf-text);
138 font-weight: 600;
139 }
140
141 /* ---------- Sidebar sections ---------- */
142
143 .hf-content .ht-fields-panel {
144 padding: var(--hf-space-4);
145 }
146
147 .hf-content .hf-layout-section {
148 margin-bottom: var(--hf-space-5);
149 }
150
151 .hf-content .hf-layout-heading {
152 color: var(--hf-text-faint);
153 font-size: var(--hf-font-xs);
154 font-weight: 600;
155 letter-spacing: .06em;
156 margin: 0 0 var(--hf-space-2);
157 text-transform: uppercase;
158 }
159
160 .hf-content .hf-layout-help {
161 color: var(--hf-text-muted);
162 font-size: var(--hf-font-sm);
163 line-height: 1.5;
164 margin: 0 0 var(--hf-space-3);
165 }
166
167 .hf-content .hf-search-fields {
168 margin-bottom: var(--hf-space-4);
169 position: relative;
170 }
171
172 .hf-content .hf-search-fields .mdi-magnify {
173 color: var(--hf-text-faint);
174 left: var(--hf-space-3);
175 position: absolute;
176 top: 50%;
177 transform: translateY(-50%);
178 }
179
180 .hf-content .hf-search-fields input[type="search"] {
181 background: var(--hf-surface-sunken);
182 border-radius: var(--hf-radius-pill);
183 padding-left: var(--hf-space-6);
184 }
185
186 .hf-content .hf-search-fields input[type="search"]:focus {
187 background: var(--hf-surface);
188 }
189
190 /* ---------- Panel controls ---------- */
191
192 /* WordPress gives selects a line-height of their own, which our min-height
193 does not override — so a select came out 43px against a 34px input sitting
194 right beside it. Matching the line-height puts them on the same height. */
195 .hf-content .hf-form-row select,
196 .hf-content .hf-settings-row select,
197 .hf-content .hf-fields-settings select {
198 line-height: 1.5;
199 min-height: 34px;
200 }
201
202 /* Rows in these panels are grid children, so the grid's own gap already
203 separates them; the inherited margin was adding a second gap on top and
204 leaving about 31px between every field. */
205 .hf-content .hf-grid-container > .hf-form-row {
206 margin-bottom: 0;
207 }
208
209 /* ---------- Settings tab ---------- */
210
211 /* Every field in these sections is marked hf-grid-3 — half of the six column
212 grid — and each sits alone on its row, so in a 900px card each input had an
213 equal patch of nothing beside it. The card narrows to a readable measure and
214 the fields fill it. */
215 .hf-content .hf-form-wrap:has(#hf-settings-form) {
216 max-width: 760px;
217 }
218
219 .hf-content #hf-settings-form .hf-grid-3 {
220 grid-column: span 6;
221 }
222
223 /* Adding another recipient is a secondary action; it was styled as the
224 screen's primary button. */
225 .hf-content #hf-settings-form .hf-add-email {
226 background: var(--hf-surface);
227 border: 1px solid var(--hf-border-strong);
228 border-radius: var(--hf-radius-sm);
229 color: var(--hf-text);
230 font-size: var(--hf-font-base);
231 font-weight: 500;
232 min-height: 34px;
233 padding: 0 var(--hf-space-4);
234 text-shadow: none;
235 }
236
237 .hf-content #hf-settings-form .hf-add-email:hover,
238 .hf-content #hf-settings-form .hf-add-email:focus {
239 background: var(--hf-surface-sunken);
240 border-color: var(--hf-text-faint);
241 color: var(--hf-text);
242 }
243
244 .hf-content .hf-email-row {
245 background: var(--hf-surface-sunken);
246 border: 1px solid var(--hf-border);
247 border-radius: var(--hf-radius-sm);
248 gap: var(--hf-space-2);
249 padding: var(--hf-space-2);
250 }
251
252 /* A saturated red circle for every row read as an error state. Quiet until
253 you reach for it, destructive when you do. */
254 .hf-content .hf-delete-email-row {
255 background: none;
256 border-radius: var(--hf-radius-sm);
257 color: var(--hf-text-faint);
258 flex: 0 0 auto;
259 font-size: 16px;
260 height: 28px;
261 transition: background-color var(--hf-transition), color var(--hf-transition);
262 width: 28px;
263 }
264
265 .hf-content .hf-delete-email-row:hover {
266 background: #fdf2f2;
267 color: var(--hf-danger);
268 }
269
270 /* Was inline style="color:red" on a description paragraph. */
271 .hf-content .hf-settings-note {
272 background: #fcf5e6;
273 border-left: 3px solid var(--hf-warning);
274 border-radius: var(--hf-radius-sm);
275 color: #6b4c0f;
276 font-size: var(--hf-font-sm);
277 line-height: 1.5;
278 margin: var(--hf-space-2) 0 0;
279 padding: var(--hf-space-2) var(--hf-space-3);
280 }
281
282 /* The tag picker sat right-aligned above one field and left-aligned below
283 another; it now always follows its label on the same line. */
284 .hf-content #hf-settings-form .hf-label-with-attr {
285 align-items: center;
286 display: flex;
287 flex-wrap: wrap;
288 gap: var(--hf-space-2);
289 justify-content: flex-start;
290 }
291
292 .hf-content #hf-settings-form .hf-label-with-attr .hf-attr-field {
293 margin-left: auto;
294 }
295
296 /* ---------- Style tab: mode cards ---------- */
297
298 /* The select these replace is still in the markup, hidden: it carries the
299 value on save and the data-condition rules key off it. */
300 .hf-content .hf-style-mode-value {
301 display: none;
302 }
303
304 .hf-content .hf-style-modes {
305 border: 0;
306 margin: 0;
307 padding: 0;
308 }
309
310 /* Carries .hf-layout-heading for its type; a legend needs the padding reset
311 on top of that. */
312 .hf-content .hf-style-modes-legend {
313 padding: 0;
314 }
315
316 .hf-content .hf-style-mode {
317 align-items: flex-start;
318 background: var(--hf-surface);
319 border: 1px solid var(--hf-border);
320 border-radius: var(--hf-radius);
321 cursor: pointer;
322 display: flex;
323 gap: var(--hf-space-2);
324 margin: 0 0 var(--hf-space-2);
325 padding: var(--hf-space-3);
326 transition: border-color var(--hf-transition), background-color var(--hf-transition), box-shadow var(--hf-transition);
327 }
328
329 .hf-content .hf-style-mode:hover {
330 border-color: var(--hf-border-strong);
331 }
332
333 .hf-content .hf-style-mode.hf-selected {
334 background: var(--hf-accent-soft);
335 border-color: var(--hf-accent);
336 box-shadow: var(--hf-shadow-sm);
337 }
338
339 .hf-content .hf-style-mode:focus-within {
340 outline: 2px solid var(--hf-accent);
341 outline-offset: 1px;
342 }
343
344 .hf-content .hf-style-mode-input {
345 /* Native radios draw themselves in the admin colour scheme, which is the
346 one thing on this screen that still was not the brand accent. */
347 accent-color: var(--hf-accent);
348 flex: 0 0 auto;
349 margin: 2px 0 0;
350 }
351
352 .hf-content .hf-style-mode-text {
353 display: flex;
354 flex-direction: column;
355 gap: 2px;
356 min-width: 0;
357 }
358
359 .hf-content .hf-style-mode-name {
360 color: var(--hf-text);
361 font-size: var(--hf-font-base);
362 font-weight: 600;
363 }
364
365 .hf-content .hf-style-mode-desc {
366 color: var(--hf-text-muted);
367 font-size: var(--hf-font-sm);
368 line-height: 1.45;
369 }
370
371 /* ---------- Style tab: template prompt ---------- */
372
373 .hf-content .hf-style-template-cta {
374 background: var(--hf-surface-sunken);
375 border: 1px dashed var(--hf-border-strong);
376 border-radius: var(--hf-radius);
377 padding: var(--hf-space-4);
378 }
379
380 .hf-content .hf-style-template-cta-text {
381 color: var(--hf-text-muted);
382 font-size: var(--hf-font-sm);
383 line-height: 1.5;
384 margin: 0 0 var(--hf-space-3);
385 }
386
387 /* A secondary action, styled like the rest of the sidebar rather than left as
388 a bare wp-admin button in the admin colour scheme. */
389 .hf-content .hf-style-template-cta .button {
390 background: var(--hf-surface);
391 border: 1px solid var(--hf-border-strong);
392 border-radius: var(--hf-radius-sm);
393 box-shadow: none;
394 color: var(--hf-text);
395 font-size: var(--hf-font-base);
396 font-weight: 500;
397 line-height: 34px;
398 margin: 0;
399 min-height: 34px;
400 padding: 0 var(--hf-space-3);
401 text-shadow: none;
402 }
403
404 .hf-content .hf-style-template-cta .button:hover,
405 .hf-content .hf-style-template-cta .button:focus {
406 background: var(--hf-surface-sunken);
407 border-color: var(--hf-text-faint);
408 color: var(--hf-text);
409 }
410
411 /* The label above the template select, under its own section heading. */
412 .hf-content .hf-style-template-label {
413 color: var(--hf-text);
414 display: block;
415 font-size: var(--hf-font-base);
416 font-weight: 500;
417 margin: 0 0 var(--hf-space-2);
418 }
419
420 /* ---------- Style tab: preview canvas ---------- */
421
422 /* The same canvas header the builder carries, so the two tabs read as one
423 surface. The builder pulls it out over the wrap's 24px padding with
424 negative margins; this panel is deliberately full bleed so the preview
425 reports a true width, so here the header just sits at the top of the card
426 and keeps its own padding. */
427 .hf-content .hf-style-form-panel .hf-canvas-header {
428 margin: 0;
429 }
430
431 .hf-content .hf-style-form-panel .hf-form-preview {
432 min-height: 200px;
433 }
434
435 /* The style editor's demo form is markup in the page rather than the Style
436 tab's width-accurate iframe, so it can have room to breathe without
437 misrepresenting anything. */
438 .hf-content .hf-style-form-panel .hf-template-preview {
439 padding: var(--hf-space-5, 24px);
440 height: calc(100% - 55px);
441 }
442
443 /* ---------- Payment field preview ---------- */
444
445 /* Every enabled gateway is a method tile, and with twenty of them switched on
446 the field ran the height of the canvas and pushed the rest of the form out
447 of view. The tiles are what gets columned — putting the grid on the
448 container instead spread the summary card, the tiles and the secure note
449 into three columns of their own, which is not the field the visitor sees. */
450 .hf-content .hf-editor-field-elements .hf-payment-container {
451 display: block;
452 }
453
454 .hf-content .hf-editor-field-elements .hf-payment-options {
455 display: grid;
456 gap: 8px;
457 grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
458 }
459
460 .hf-content .hf-editor-field-elements .hf-payment-option {
461 min-width: 0;
462 }
463
464 .hf-content .hf-editor-field-elements .hf-payment-option-label {
465 align-items: center;
466 display: flex;
467 gap: var(--hf-space-2);
468 overflow: hidden;
469 text-overflow: ellipsis;
470 white-space: nowrap;
471 }
472
473 /* The "no gateway enabled" note, which points at the Modules screen. */
474 .hf-content .hf-editor-field-elements .hf-payment-desc {
475 color: var(--hf-text-muted);
476 font-size: var(--hf-font-sm);
477 margin: 0;
478 }
479
480 /* ---------- Builder header ---------- */
481
482 /* Two rows: identity and actions on top, navigation beneath. The old header
483 put a form name, four tabs and four buttons on one line, all uppercase, so
484 nothing had priority and a long form name had nowhere to go.
485 admin-style.css still carries the single-row rules, so these reset the
486 parts that would otherwise fight it. */
487 /* The chrome floats above a tinted page as rounded panels, so depth does the
488 separating rather than a grid of hairlines.
489 Not sticky: the builder shell gives the sidebar and the canvas their own
490 scroll, and a sticky header here overlapped the sidebar's own sticky tab
491 bar. */
492 .hf-content .hf-header-nav {
493 align-items: stretch;
494 background: var(--hf-surface);
495 border: 1px solid var(--hf-border);
496 border-radius: var(--hf-radius-lg);
497 box-shadow: 0 10px 24px -10px rgba(16, 24, 40, .28);
498 display: block;
499 flex: 0 0 auto;
500 justify-content: normal;
501 margin: var(--hf-space-3) var(--hf-space-3) 0;
502 }
503
504 .hf-content .hf-header-bottom {
505 border-top: 1px solid var(--hf-border);
506 }
507
508 .hf-content .hf-header-top {
509 align-items: center;
510 display: flex;
511 gap: var(--hf-space-3);
512 padding: var(--hf-space-4) var(--hf-space-5);
513 }
514
515 .hf-content .hf-header-back {
516 align-items: center;
517 border: 1px solid transparent;
518 border-radius: var(--hf-radius-sm);
519 color: var(--hf-text-muted);
520 display: inline-flex;
521 flex: 0 0 auto;
522 font-size: 20px;
523 height: 32px;
524 justify-content: center;
525 text-decoration: none;
526 transition: background-color var(--hf-transition), color var(--hf-transition);
527 width: 32px;
528 }
529
530 .hf-content .hf-header-back:hover {
531 background: var(--hf-surface-sunken);
532 border-color: var(--hf-border);
533 color: var(--hf-text);
534 }
535
536 .hf-content .hf-header-identity {
537 align-items: center;
538 display: flex;
539 flex: 1 1 auto;
540 gap: var(--hf-space-3);
541 min-width: 0;
542 }
543
544 /* A mark for the form, so the title has something to sit against and the
545 header has an anchor of its own. */
546 .hf-content .hf-header-mark {
547 align-items: center;
548 background: var(--hf-accent-soft);
549 border: 1px solid var(--hf-accent);
550 border-radius: 9px;
551 color: var(--hf-accent-text, #a3591b);
552 display: inline-flex;
553 flex: 0 0 auto;
554 font-size: 19px;
555 height: 36px;
556 justify-content: center;
557 width: 36px;
558 }
559
560 /* Sentence case at a readable size, and free to take the width it needs —
561 the old rule fixed it to 360px, centred and uppercase. */
562 .hf-content .hf-header-nav .hf-header-title {
563 color: var(--hf-text);
564 font-size: 22px;
565 font-weight: 600;
566 letter-spacing: -.02em;
567 margin: 0;
568 overflow: hidden;
569 padding: 0;
570 text-align: left;
571 text-overflow: ellipsis;
572 text-transform: none;
573 white-space: nowrap;
574 width: auto;
575 line-height: 1.3;
576 }
577
578 .hf-content .hf-header-status {
579 align-items: center;
580 background: var(--hf-surface-sunken);
581 border: 1px solid var(--hf-border);
582 border-radius: var(--hf-radius-pill);
583 color: var(--hf-text-muted);
584 display: inline-flex;
585 flex: 0 0 auto;
586 font-size: var(--hf-font-xs);
587 font-weight: 600;
588 gap: var(--hf-space-1);
589 padding: 2px var(--hf-space-2);
590 }
591
592 .hf-content .hf-header-status::before {
593 background: var(--hf-text-faint);
594 border-radius: 50%;
595 content: "";
596 height: 6px;
597 width: 6px;
598 }
599
600 .hf-content .hf-header-status.hf-is-published::before {
601 background: var(--hf-success);
602 }
603
604 .hf-content .hf-header-actions {
605 align-items: center;
606 display: flex;
607 flex: 0 0 auto;
608 gap: var(--hf-space-2);
609 }
610
611 /* Three actions, three weights: primary, outline, quiet. */
612 .hf-content .hf-header-nav .hashform-ajax-udpate-button {
613 background: var(--hf-accent);
614 border: 1px solid var(--hf-accent);
615 border-radius: var(--hf-radius-sm);
616 box-shadow: none;
617 color: var(--hf-text-inverse);
618 font-size: var(--hf-font-base);
619 font-weight: 600;
620 gap: var(--hf-space-2);
621 margin: 0;
622 min-height: 34px;
623 padding: 0 var(--hf-space-4);
624 text-transform: none;
625 transition: background-color var(--hf-transition);
626 }
627
628 .hf-content .hf-header-nav .hashform-ajax-udpate-button:hover {
629 background: var(--hf-accent-hover);
630 border-color: var(--hf-accent-hover);
631 }
632
633 .hf-content .hf-header-nav .hf-embed-button {
634 font-size: var(--hf-font-base);
635 font-weight: 500;
636 gap: var(--hf-space-2);
637 min-height: 34px;
638 padding: 0 var(--hf-space-3);
639 text-transform: none;
640 }
641
642 .hf-content .hf-header-nav .hf-preview-button {
643 align-items: center;
644 background: none;
645 border: 1px solid transparent;
646 border-radius: var(--hf-radius-sm);
647 color: var(--hf-text-muted);
648 display: inline-flex;
649 font-size: var(--hf-font-base);
650 font-weight: 500;
651 gap: var(--hf-space-2);
652 min-height: 34px;
653 padding: 0 var(--hf-space-3);
654 text-decoration: none;
655 text-transform: none;
656 transition: background-color var(--hf-transition), color var(--hf-transition);
657 }
658
659 .hf-content .hf-header-nav .hf-preview-button:hover {
660 background: var(--hf-surface-sunken);
661 color: var(--hf-text);
662 }
663
664 .hf-content .hf-header-nav .hf-preview-button span,
665 .hf-content .hf-header-nav .hf-embed-button span,
666 .hf-content .hf-header-nav .hashform-ajax-udpate-button span {
667 font-size: 16px;
668 height: auto;
669 width: auto;
670 }
671
672 /* ---------- Builder tabs ---------- */
673
674 /* Centred and raised into a segmented control: the four sections are the main
675 way around the builder, so they get the middle of the header rather than
676 trailing off to one side, and the active one is a card rather than a line. */
677 .hf-content .hf-header-bottom {
678 background: var(--hf-surface-sunken);
679 border-radius: 0 0 var(--hf-radius-lg) var(--hf-radius-lg);
680 display: flex;
681 justify-content: center;
682 padding: var(--hf-space-3) var(--hf-space-5);
683 }
684
685 .hf-content .hf-header-nav .hf-main-nav {
686 background: rgba(16, 24, 40, .06);
687 border-radius: var(--hf-radius);
688 display: inline-flex;
689 flex-grow: 0;
690 gap: 0;
691 justify-content: center;
692 margin: 0;
693 padding: 3px;
694 }
695
696 .hf-content .hf-main-nav li {
697 margin: 0;
698 padding: 0;
699 text-transform: none;
700 }
701
702 .hf-content .hf-main-nav li a {
703 border: 0;
704 border-radius: 6px;
705 color: var(--hf-text-muted);
706 display: block;
707 font-size: var(--hf-font-base);
708 font-weight: 500;
709 line-height: 1.4;
710 margin: 0;
711 padding: var(--hf-space-2) var(--hf-space-5);
712 transition: background-color var(--hf-transition), color var(--hf-transition), box-shadow var(--hf-transition);
713 }
714
715 .hf-content .hf-main-nav li a:hover {
716 color: var(--hf-text);
717 }
718
719 .hf-content .hf-main-nav li a.hf-active-nav {
720 background: var(--hf-surface);
721 box-shadow: var(--hf-shadow-sm);
722 color: var(--hf-accent-text, #a3591b);
723 font-weight: 600;
724 }
725
726 /* ---------- Canvas header ---------- */
727
728 .hf-content .hf-canvas-header {
729 align-items: baseline;
730 border-bottom: 1px solid var(--hf-border);
731 display: flex;
732 gap: var(--hf-space-3);
733 justify-content: space-between;
734 margin: calc(var(--hf-space-5) * -1) calc(var(--hf-space-5) * -1) var(--hf-space-5);
735 padding: var(--hf-space-4) var(--hf-space-5);
736 }
737
738 .hf-content .hf-canvas-title {
739 color: var(--hf-text);
740 font-size: var(--hf-font-md);
741 font-weight: 600;
742 overflow: hidden;
743 text-overflow: ellipsis;
744 white-space: nowrap;
745 }
746
747 .hf-content .hf-canvas-count {
748 color: var(--hf-text-faint);
749 flex: 0 0 auto;
750 font-size: var(--hf-font-sm);
751 font-variant-numeric: tabular-nums;
752 }
753
754 /* ---------- Header actions ---------- */
755
756 /* Was a hardcoded #10a0ff that matched nothing else on the screen and fought
757 the black primary beside it. Embed is the secondary action, so it reads as
758 one. */
759 .hf-content .hf-header-nav .hf-embed-button,
760 .hf-header-nav .hf-embed-button {
761 background: var(--hf-surface, #fff);
762 border: 1px solid var(--hf-border-strong, #d3d8e0);
763 border-radius: var(--hf-radius-sm, 4px);
764 box-shadow: none;
765 color: var(--hf-text, #1e2327);
766 transition: background-color var(--hf-transition, .15s ease), border-color var(--hf-transition, .15s ease);
767 }
768
769 .hf-content .hf-header-nav .hf-embed-button:hover,
770 .hf-header-nav .hf-embed-button:hover {
771 background: var(--hf-surface-sunken, #fafbfc);
772 border-color: var(--hf-text-faint, #8c9196);
773 color: var(--hf-text, #1e2327);
774 }
775
776 /* ---------- Field group colours ---------- */
777
778 /* The palette was fifty identical white tiles with grey hairlines, which made
779 the groups structural but invisible and the whole panel characterless. Each
780 group carries a hue, used on its heading marker and on the icon tile of
781 every field in it, so the sidebar reads at a glance and has some life. The
782 hue only ever tints an icon or a marker — labels and surfaces stay neutral,
783 which keeps it from turning into a paintbox. */
784 .hf-content .hf-field-group {
785 --hf-group: #475569;
786 --hf-group-tint: #f1f5f9;
787 }
788
789 .hf-content .hf-field-group[data-group="basic"] {
790 --hf-group: #2563eb;
791 --hf-group-tint: #eff4ff;
792 }
793
794 .hf-content .hf-field-group[data-group="choice"] {
795 --hf-group: #7c3aed;
796 --hf-group-tint: #f5f1ff;
797 }
798
799 .hf-content .hf-field-group[data-group="advanced"] {
800 --hf-group: #c2610c;
801 --hf-group-tint: #fdf3e7;
802 }
803
804 .hf-content .hf-field-group[data-group="layout"] {
805 --hf-group: #475569;
806 --hf-group-tint: #f1f5f9;
807 }
808
809 .hf-content .hf-field-group[data-group="spam"] {
810 --hf-group: #047857;
811 --hf-group-tint: #e9f7f1;
812 }
813
814 .hf-content .hf-field-group[data-group="payment"] {
815 --hf-group: #0e7490;
816 --hf-group-tint: #e7f5f9;
817 }
818
819 /* A marker before the heading, so the colour is introduced with the name. */
820 .hf-content .hf-field-group-name::before {
821 background: var(--hf-group);
822 border-radius: 2px;
823 content: "";
824 display: inline-block;
825 height: 10px;
826 margin-right: var(--hf-space-2);
827 vertical-align: -1px;
828 width: 3px;
829 }
830
831 /* ---------- Field groups ---------- */
832
833 /* Around fifty field types is too many for one run of tiles, so they sit in
834 collapsible groups. The first opens by default; the rest stay shut until
835 asked for, which keeps the whole palette roughly one screen tall. */
836 .hf-content .hf-field-group {
837 border-bottom: 1px solid var(--hf-border);
838 }
839
840 .hf-content .hf-field-group:last-of-type {
841 border-bottom: 0;
842 }
843
844 .hf-content .hf-field-group-toggle {
845 align-items: center;
846 background: none;
847 border: 0;
848 color: var(--hf-text-faint);
849 cursor: pointer;
850 display: flex;
851 font-size: var(--hf-font-xs);
852 font-weight: 600;
853 gap: var(--hf-space-2);
854 letter-spacing: .06em;
855 padding: var(--hf-space-3) var(--hf-space-1);
856 text-transform: uppercase;
857 transition: color var(--hf-transition);
858 width: 100%;
859 }
860
861 .hf-content .hf-field-group-toggle:hover {
862 color: var(--hf-text);
863 }
864
865 .hf-content .hf-field-group-toggle:focus-visible {
866 outline: 2px solid var(--hf-accent);
867 outline-offset: -2px;
868 }
869
870 .hf-content .hf-field-group.hf-open .hf-field-group-toggle {
871 color: var(--hf-text);
872 }
873
874 .hf-content .hf-field-group-name {
875 flex: 1 1 auto;
876 text-align: left;
877 }
878
879 .hf-content .hf-field-group-count {
880 background: var(--hf-surface-sunken);
881 border: 1px solid var(--hf-border);
882 border-radius: var(--hf-radius-pill);
883 color: var(--hf-text-muted);
884 font-size: var(--hf-font-xs);
885 font-variant-numeric: tabular-nums;
886 letter-spacing: 0;
887 padding: 0 var(--hf-space-2);
888 }
889
890 /* A chevron drawn from a border, so it needs no icon font. */
891 .hf-content .hf-field-group-chevron {
892 border-right: 1.5px solid currentColor;
893 border-bottom: 1.5px solid currentColor;
894 flex: 0 0 auto;
895 height: 6px;
896 margin-right: var(--hf-space-1);
897 transform: rotate(-45deg);
898 transition: transform var(--hf-transition-slow);
899 width: 6px;
900 }
901
902 .hf-content .hf-field-group.hf-open .hf-field-group-chevron {
903 transform: rotate(45deg);
904 }
905
906 .hf-content .hf-field-group > .hf-fields-list {
907 display: none;
908 padding-bottom: var(--hf-space-3);
909 }
910
911 .hf-content .hf-field-group.hf-open > .hf-fields-list {
912 display: grid;
913 }
914
915 /* While a search is running the groups get out of the way: every match shows,
916 whatever group it came from. */
917 .hf-content .hf-fields-section.hf-searching .hf-field-group > .hf-fields-list {
918 display: grid;
919 }
920
921 .hf-content .hf-fields-section.hf-searching .hf-field-group-chevron {
922 visibility: hidden;
923 }
924
925 .hf-content .hf-field-group[hidden] {
926 display: none;
927 }
928
929 .hf-content .hf-fields-empty {
930 color: var(--hf-text-muted);
931 font-size: var(--hf-font-sm);
932 margin: 0;
933 padding: var(--hf-space-5) 0;
934 text-align: center;
935 }
936
937 .hf-content .hf-fields-empty[hidden] {
938 display: none;
939 }
940
941 /* ---------- Field list ---------- */
942
943 /* Three to a row: the palette runs to about fifty types, and at two per row a
944 group like Choice pushed everything after it off screen. */
945 .hf-content .hf-fields-list {
946 display: grid;
947 gap: 6px;
948 grid-template-columns: repeat(3, minmax(0, 1fr));
949 margin: 0;
950 padding: 0;
951 }
952
953 .hf-content .hf-fields-list .hf-field-box {
954 margin: 0;
955 }
956
957 .hf-content .hf-fields-list .hf-drag-field {
958 align-items: center;
959 background: var(--hf-surface);
960 border: 1px solid var(--hf-border);
961 border-radius: 10px;
962 box-shadow: none;
963 color: var(--hf-text);
964 cursor: grab;
965 display: flex;
966 flex-direction: column;
967 font-size: var(--hf-font-sm);
968 font-weight: 500;
969 gap: 6px;
970 justify-content: center;
971 line-height: 1.3;
972 min-height: 68px;
973 padding: var(--hf-space-2) var(--hf-space-1);
974 text-align: center;
975 text-decoration: none;
976 transition: border-color var(--hf-transition), background-color var(--hf-transition), box-shadow var(--hf-transition);
977 width: 100%;
978 }
979
980 /* The icon carries the group's colour on a tinted tile. Previously every icon
981 was the same thin grey glyph floating on white, which is most of why the
982 panel felt flat. */
983 .hf-content .hf-fields-list .hf-drag-field svg,
984 .hf-content .hf-fields-list .hf-drag-field i {
985 align-items: center;
986 background: var(--hf-group-tint, var(--hf-surface-sunken));
987 border-radius: var(--hf-radius-sm);
988 color: var(--hf-group, var(--hf-text-muted));
989 display: inline-flex;
990 flex: 0 0 auto;
991 height: 26px;
992 justify-content: center;
993 padding: 5px;
994 transition: background-color var(--hf-transition), color var(--hf-transition);
995 width: 26px;
996 }
997
998 .hf-content .hf-fields-list .hf-drag-field:hover {
999 border-color: var(--hf-group, var(--hf-accent));
1000 box-shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 4px 10px -6px var(--hf-group, var(--hf-accent));
1001 transform: translateY(-1px);
1002 }
1003
1004 .hf-content .hf-fields-list .hf-drag-field:hover svg,
1005 .hf-content .hf-fields-list .hf-drag-field:hover i {
1006 background: var(--hf-group, var(--hf-accent));
1007 color: #fff;
1008 }
1009
1010 .hf-content .hf-fields-list .hf-drag-field:active {
1011 cursor: grabbing;
1012 transform: none;
1013 }
1014
1015 /* Wrapping rather than truncating: at this width "Advanced Select" would
1016 otherwise be clipped to an ellipsis on every tile. */
1017 .hf-content .hf-fields-list .hf-drag-field span {
1018 font-size: 11px;
1019 line-height: 1.25;
1020 overflow: hidden;
1021 white-space: normal;
1022 }
1023
1024 /* ---------- Column presets ---------- */
1025
1026 .hf-content .hf-columns-list {
1027 display: grid;
1028 gap: var(--hf-space-2);
1029 grid-template-columns: repeat(4, minmax(0, 1fr));
1030 margin: 0;
1031 padding: 0;
1032 }
1033
1034 .hf-content .hf-columns-list .hf-column-box {
1035 margin: 0;
1036 }
1037
1038 .hf-content .hf-columns-list .hf-add-columns {
1039 align-items: center;
1040 background: var(--hf-surface);
1041 border: 1px solid var(--hf-border);
1042 border-radius: var(--hf-radius);
1043 display: flex;
1044 justify-content: center;
1045 padding: var(--hf-space-3) var(--hf-space-2);
1046 transition: border-color var(--hf-transition), background-color var(--hf-transition);
1047 }
1048
1049 .hf-content .hf-columns-list .hf-add-columns:hover {
1050 background: var(--hf-accent-soft);
1051 border-color: var(--hf-accent);
1052 }
1053
1054 .hf-content .hf-column-preview {
1055 display: flex;
1056 gap: 3px;
1057 width: 100%;
1058 }
1059
1060 .hf-content .hf-column-preview span {
1061 background: var(--hf-border-strong);
1062 border-radius: 2px;
1063 flex: 1 1 0;
1064 height: 18px;
1065 }
1066
1067 .hf-content .hf-add-columns:hover .hf-column-preview span {
1068 background: var(--hf-accent);
1069 }
1070
1071 /* ---------- Field settings panel ---------- */
1072
1073 .hf-content .hf-fields-settings {
1074 background: var(--hf-surface);
1075 }
1076
1077 .hf-content .hf-field-panel-header {
1078 align-items: center;
1079 background: var(--hf-surface);
1080 border-bottom: 1px solid var(--hf-border);
1081 display: flex;
1082 justify-content: space-between;
1083 margin: calc(var(--hf-space-4) * -1) calc(var(--hf-space-4) * -1) var(--hf-space-4);
1084 padding: var(--hf-space-3) var(--hf-space-4);
1085 position: sticky;
1086 top: 0;
1087 z-index: 8;
1088 }
1089
1090 .hf-content .hf-field-panel-header h3 {
1091 color: var(--hf-text);
1092 font-size: var(--hf-font-md);
1093 font-weight: 600;
1094 margin: 0;
1095 }
1096
1097 .hf-content .hf-field-panel-id {
1098 color: var(--hf-text-faint);
1099 font-size: var(--hf-font-sm);
1100 }
1101
1102 .hf-content .hf-form-row {
1103 margin-bottom: var(--hf-space-4);
1104 }
1105
1106 .hf-content .hf-form-row > label {
1107 color: var(--hf-text);
1108 display: block;
1109 font-size: var(--hf-font-base);
1110 font-weight: 500;
1111 margin-bottom: var(--hf-space-1);
1112 }
1113
1114 .hf-content .hf-field-desc {
1115 color: var(--hf-text-muted);
1116 display: block;
1117 font-size: var(--hf-font-sm);
1118 font-weight: 400;
1119 line-height: 1.5;
1120 margin-top: var(--hf-space-1);
1121 }
1122
1123 /* Ready-made regexes for the Format box, offered as small quiet chips so they
1124 read as shortcuts rather than as the setting itself. */
1125 .hf-content .hf-format-presets {
1126 display: flex;
1127 flex-wrap: wrap;
1128 gap: var(--hf-space-2);
1129 margin: var(--hf-space-2) 0 0;
1130 }
1131
1132 .hf-content .hf-format-preset {
1133 background: var(--hf-surface-sunken);
1134 border: 1px solid var(--hf-border-strong);
1135 border-radius: var(--hf-radius-pill);
1136 color: var(--hf-text-muted);
1137 cursor: pointer;
1138 font-size: var(--hf-font-sm);
1139 line-height: 1.4;
1140 padding: 3px var(--hf-space-3);
1141 transition: background-color var(--hf-transition), border-color var(--hf-transition), color var(--hf-transition);
1142 }
1143
1144 .hf-content .hf-format-preset:hover {
1145 background: var(--hf-surface);
1146 border-color: var(--hf-accent);
1147 color: var(--hf-accent-text, #a3591b);
1148 }
1149
1150 .hf-content .hf-format-preset:focus-visible {
1151 outline: 2px solid var(--hf-accent);
1152 outline-offset: 1px;
1153 }
1154
1155 .hf-content .hf-format-preset.hf-format-clear:hover {
1156 border-color: var(--hf-danger);
1157 color: var(--hf-danger);
1158 }
1159
1160 .hf-content .hf-validation-header,
1161 .hf-content .hf-fields-settings h4 {
1162 border-top: 1px solid var(--hf-border);
1163 color: var(--hf-text-faint);
1164 font-size: var(--hf-font-xs);
1165 font-weight: 600;
1166 letter-spacing: .06em;
1167 margin: var(--hf-space-5) 0 var(--hf-space-3);
1168 padding-top: var(--hf-space-4);
1169 text-transform: uppercase;
1170 }
1171
1172 /* Sub-field controls — the First/Last parts of a name, the pieces of an
1173 address — are laid out on the same six column grid the form settings use.
1174 Three of them side by side in a 300px sidebar left ~90px each, with the
1175 captions wrapping onto two lines, so in this panel they take a row apiece. */
1176 .hf-content .hf-fields-settings .hf-grid-container > .hf-form-row.hf-grid-2 {
1177 grid-column: span 6;
1178 }
1179
1180 .hf-content .hf-fields-settings .hf-sub-field-label {
1181 color: var(--hf-text);
1182 font-size: var(--hf-font-base);
1183 font-weight: 600;
1184 margin: var(--hf-space-3) 0 var(--hf-space-2);
1185 }
1186
1187 .hf-content .hf-fields-settings .hf-sub-field-label:empty {
1188 display: none;
1189 }
1190
1191 .hf-content .hf-no-field-placeholder {
1192 align-items: center;
1193 color: var(--hf-text-muted);
1194 display: flex;
1195 flex-direction: column;
1196 font-size: var(--hf-font-base);
1197 justify-content: center;
1198 min-height: 220px;
1199 padding: var(--hf-space-5);
1200 text-align: center;
1201 }
1202
1203 /* ---------- Canvas ---------- */
1204
1205 /* Same elevation as the sidebar and header, so the three read as panels of
1206 one workspace rather than a card sitting inside a padded box. */
1207 .hf-content .hf-form-wrap {
1208 background: var(--hf-surface);
1209 border: 1px solid var(--hf-border);
1210 border-radius: var(--hf-radius-lg);
1211 box-shadow: var(--hf-shadow-md);
1212 margin: 0 auto;
1213 max-width: 900px;
1214 padding: var(--hf-space-5);
1215 }
1216
1217 /* The drop target reads as an invitation rather than an error state. */
1218 .hf-content .hf-drag-hint,
1219 .hf-content .hf-empty-canvas {
1220 background: var(--hf-surface-sunken);
1221 border: 1px dashed var(--hf-border-strong);
1222 border-radius: var(--hf-radius);
1223 color: var(--hf-text-muted);
1224 font-size: var(--hf-font-base);
1225 padding: var(--hf-space-4);
1226 text-align: center;
1227 }
1228
1229 @media only screen and (max-width: 1200px) {
1230 .hf-content .hf-fields-list {
1231 grid-template-columns: repeat(2, minmax(0, 1fr));
1232 }
1233
1234 /* Not narrower than 330: the WordPress colour picker on the style
1235 template editor is a fixed 257px widget, and with the panel padding
1236 around it anything under this clips it against the sidebar's
1237 overflow. */
1238 .hf-content .hf-fields-sidebar {
1239 flex-basis: 330px;
1240 width: 330px;
1241 }
1242 }
1243
1244 /*
1245 * builder.js marks a field as newly added and clears the mark a second later,
1246 * which only makes sense as a flash telling you where the field you just
1247 * dropped has landed. No rule had ever answered it, so the mark came and went
1248 * with nothing to show for it. The timing here matches that one second.
1249 */
1250 .hf-newly-added {
1251 animation: hf-field-flash 1s ease-out;
1252 }
1253
1254 @keyframes hf-field-flash {
1255 from {
1256 background-color: var(--hf-accent-soft, #fdf4ed);
1257 box-shadow: 0 0 0 2px var(--hf-accent, #dd823b);
1258 }
1259
1260 to {
1261 background-color: transparent;
1262 box-shadow: 0 0 0 2px transparent;
1263 }
1264 }
1265
1266 @media (prefers-reduced-motion: reduce) {
1267
1268 .hf-newly-added {
1269 animation: none;
1270 box-shadow: 0 0 0 2px var(--hf-accent, #dd823b);
1271 }
1272 }
1273
1274 /* ---------- Conditional logic hint ---------- */
1275
1276 /* A field a rule shows, hides, or decides on.
1277 *
1278 * The rules are set up on the Settings tab, so the canvas gave no sign that a
1279 * field is only shown to some visitors - or that a field is the one deciding.
1280 *
1281 * Built like .hf-header-status: the same sunken pill the rest of the screen
1282 * uses for state, with a coloured dot carrying which kind of state it is. It is
1283 * positioned rather than in the flow, because .hf-editor-field-container is a
1284 * flex row and a child there would push the label and the input across.
1285 */
1286 /* The chip gets a strip of its own at the foot of the field, rather than being
1287 dropped on top of the input's bottom edge. Only fields that carry one pay
1288 for it.
1289
1290 Carries the #hf-editor-fields id because that is what sets the field's
1291 padding in admin-style.css, and an id beats any number of classes however
1292 late this sheet loads. */
1293 #hf-editor-fields .hf-editor-form-field:has(> .hf-editor-field-container > .hf-editor-condition-hint) {
1294 padding-bottom: 28px;
1295 }
1296
1297 .hf-content .hf-editor-condition-hint {
1298 align-items: center;
1299 background: var(--hf-surface-sunken);
1300 border: 1px solid var(--hf-border);
1301 border-radius: var(--hf-radius-pill);
1302 bottom: 4px;
1303 color: var(--hf-text-muted);
1304 display: inline-flex;
1305 font-size: var(--hf-font-xs);
1306 gap: var(--hf-space-1);
1307 line-height: 1;
1308 /* Never wider than the field it belongs to, however long the rule reads. */
1309 max-width: calc(100% - 20px);
1310 padding: 3px 8px;
1311 position: absolute;
1312 right: 10px;
1313 z-index: 2;
1314 }
1315
1316 /* The rule is written out here, so it is the part that gives way when there is
1317 not enough room. The whole of it stays in the tooltip. */
1318 .hf-content .hf-editor-condition-hint-label {
1319 overflow: hidden;
1320 text-overflow: ellipsis;
1321 white-space: nowrap;
1322 }
1323
1324 /* Kept out of the ellipsis, so "+2 more" is not the half that gets trimmed. */
1325 .hf-content .hf-editor-condition-hint-more {
1326 flex: 0 0 auto;
1327 opacity: .75;
1328 }
1329
1330 .hf-content .hf-editor-condition-hint::before {
1331 background: var(--hf-accent);
1332 border-radius: 50%;
1333 content: "";
1334 flex: 0 0 auto;
1335 height: 6px;
1336 width: 6px;
1337 }
1338
1339 /* The deciding end of a rule is the quieter of the two: that field is always
1340 on screen, it just governs another. */
1341 .hf-content .hf-editor-condition-hint-trigger::before {
1342 background: var(--hf-text-faint);
1343 }
1344
1345 /* The icon is the fork used on the rules panel itself, so the two read as the
1346 same feature. */
1347 .hf-content .hf-editor-condition-hint .mdi {
1348 font-size: 13px;
1349 }
1350
1351 /* The action buttons appear on hover across the top of the field, so the chip
1352 sits at the bottom and the two never overlap. It lifts on hover to stay
1353 legible against the highlighted field. */
1354 .hf-content .hf-editor-form-field:hover .hf-editor-condition-hint {
1355 background: var(--hf-surface);
1356 border-color: var(--hf-text-faint);
1357 color: var(--hf-text);
1358 }
1359