@arcforgelabs/flow 2026.10.45 → 2026.10.47
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/README.md +1 -0
- package/VISION.md +10 -10
- package/npm-shrinkwrap.json +104 -2
- package/package.json +6 -2
- package/server/api/invoicing.js +56 -16
- package/server/app.js +4 -2
- package/server/auth/people.js +5 -3
- package/server/auth/routes.js +4 -1
- package/server/core/invoice-rules.js +34 -4
- package/server/core/invoices.js +40 -1
- package/server/core/invoicing-rules.js +20 -3
- package/server/core/job-board.js +1 -1
- package/server/core/sending.js +76 -22
- package/server/integrations/call-guard.js +21 -4
- package/server/integrations/sentry/index.js +14 -7
- package/server/integrations/xero/client.js +12 -2
- package/server/integrations/xero/migrations/0010_xero_call_usage.sql +11 -0
- package/server/integrations/xero/migrations/meta/_journal.json +7 -0
- package/server/integrations/xero/routes.js +29 -5
- package/server/integrations/xero/runtime.js +5 -0
- package/server/integrations/xero/usage.js +74 -0
- package/server/ui/alerts.js +2 -1
- package/server/ui/app.js +110 -27
- package/server/ui/bulk-bar.js +18 -5
- package/server/ui/columns.js +54 -2
- package/server/ui/custom-fields.js +22 -7
- package/server/ui/flow.css +353 -45
- package/server/ui/invoicing.js +286 -64
- package/server/ui/job-board.js +10 -0
- package/server/ui/job-change.js +4 -3
- package/server/ui/job-view.js +14 -4
- package/server/ui/jobs.js +156 -56
- package/server/ui/kit.js +212 -51
- package/server/ui/list-views.js +50 -10
- package/server/ui/mobile.js +726 -0
- package/server/ui/monitoring.js +51 -0
- package/server/ui/nav-pins.js +41 -0
- package/server/ui/page.js +110 -5
- package/server/ui/pager.js +57 -10
- package/server/ui/price-list.js +1 -1
- package/server/ui/price-reconcile.js +12 -12
- package/server/ui/reconcile.js +19 -18
- package/server/ui/routes.js +1 -1
- package/server/ui/saved-views.js +6 -5
- package/server/ui/sidecar.js +106 -6
- package/server/ui/view-bar.js +22 -11
- package/server/ui/xero-import.js +48 -19
- package/server/ui/xero-usage-model.js +106 -0
- package/server/ui/xero-usage.js +133 -0
package/server/ui/flow.css
CHANGED
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
edge, as ClickUp and HubSpot do; the title, toolbar and content start at
|
|
12
12
|
one place on every page. */
|
|
13
13
|
--fx-gutter: clamp(16px, 2vw, 24px);
|
|
14
|
+
/* The height of every control in a list's toolbar: chips, view tabs,
|
|
15
|
+
search, Board/List and the page's button. */
|
|
16
|
+
--fx-control-h: 32px;
|
|
14
17
|
--fx-line-soft: color-mix(in srgb, var(--t-text) 7%, transparent);
|
|
15
18
|
--fx-hover: color-mix(in srgb, var(--t-text) 5%, transparent);
|
|
16
19
|
--fx-focus: 0 0 0 3px color-mix(in srgb, var(--t-ring) 40%, transparent);
|
|
@@ -279,6 +282,14 @@ a.fx-link:hover, a.fx-link:focus-visible { border-color: var(--t-strong); }
|
|
|
279
282
|
box-shadow: 0 8px 24px rgba(0, 0, 0, .18); animation: fx-rise 160ms var(--fx-ease);
|
|
280
283
|
}
|
|
281
284
|
.fx-toast[data-tone="danger"] { background: var(--t-danger); color: var(--t-paper); }
|
|
285
|
+
.fx-toast--stay { display: flex; align-items: flex-start; gap: 12px; }
|
|
286
|
+
.fx-toast__text { flex: 1; min-width: 0; }
|
|
287
|
+
.fx-toast__close {
|
|
288
|
+
flex: none; display: grid; place-items: center; width: 28px; height: 28px; margin: -6px -8px -6px 0;
|
|
289
|
+
border: 0; border-radius: var(--t-radius); background: transparent; color: inherit; cursor: pointer; opacity: .85;
|
|
290
|
+
}
|
|
291
|
+
.fx-toast__close:hover { opacity: 1; background: color-mix(in srgb, currentColor 14%, transparent); }
|
|
292
|
+
.fx-toast__close svg { width: 16px; height: 16px; }
|
|
282
293
|
|
|
283
294
|
/* ── Table and people ───────────────────────────────────────────────────── */
|
|
284
295
|
.fx-table { width: 100%; border-collapse: collapse; font-size: 14px; }
|
|
@@ -420,7 +431,7 @@ a.fx-strong:hover { text-decoration: underline; }
|
|
|
420
431
|
.fx-toolbar { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 12px; border-bottom: 1px solid var(--fx-line); }
|
|
421
432
|
.fx-tabs { display: flex; gap: 2px; }
|
|
422
433
|
.fx-tabs button { flex: none; }
|
|
423
|
-
@media (max-width:
|
|
434
|
+
@media (max-width: 639px) { .fx-tabs { max-width: 100%; overflow-x: auto; scrollbar-width: none; } }
|
|
424
435
|
.fx-tabs button {
|
|
425
436
|
display: inline-flex; align-items: center; gap: 8px; padding: 10px 14px; margin-bottom: -1px;
|
|
426
437
|
border: 0; border-bottom: 2px solid transparent; background: transparent; cursor: pointer;
|
|
@@ -431,14 +442,17 @@ a.fx-strong:hover { text-decoration: underline; }
|
|
|
431
442
|
.fx-tabs__count { padding: 0 7px; border-radius: 999px; background: var(--fx-hover); color: var(--t-dim); font-size: 12px; line-height: 20px; }
|
|
432
443
|
.fx-tabs button[data-tone="danger"] .fx-tabs__count { background: var(--t-danger-bg); color: var(--t-danger); }
|
|
433
444
|
|
|
434
|
-
/* Saved views (saved-views.js):
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
445
|
+
/* Saved views (saved-views.js): named view tabs in the toolbar, at the
|
|
446
|
+
right of Group, Sort and Filter (listHead's tools). The chosen tab is a
|
|
447
|
+
filled pill; its ⋯ shows on hover and when chosen. Save and Revert follow
|
|
448
|
+
while the list differs. */
|
|
449
|
+
.fx-toolbar__tools { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; }
|
|
450
|
+
.fx-views { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; }
|
|
438
451
|
.fx-views:empty { display: none; }
|
|
439
|
-
.fx-views__item { display: inline-flex; align-items: center; border-
|
|
440
|
-
.fx-views__item
|
|
441
|
-
.fx-
|
|
452
|
+
.fx-views__item { display: inline-flex; align-items: center; border-radius: 999px; }
|
|
453
|
+
.fx-views__item:hover { background: var(--fx-hover); }
|
|
454
|
+
.fx-views__item[data-on="true"] { background: var(--t-accent-bg); }
|
|
455
|
+
.fx-views__tab { display: inline-flex; align-items: center; gap: 6px; max-width: 180px; padding: 6px 4px 6px 10px; border-radius: 999px; border: 0; background: none; color: var(--t-dim); font: 600 13px var(--t-body); cursor: pointer; }
|
|
442
456
|
.fx-views__tab:hover, .fx-views__item[data-on="true"] .fx-views__tab { color: var(--t-strong); }
|
|
443
457
|
.fx-views__tab:focus-visible { outline: 2px solid var(--t-ring, var(--t-accent)); outline-offset: 1px; }
|
|
444
458
|
.fx-views__tab .fx-lucide { width: 14px; height: 14px; flex: none; }
|
|
@@ -447,11 +461,18 @@ a.fx-strong:hover { text-decoration: underline; }
|
|
|
447
461
|
.fx-views__item .fx-cfm__more { width: 22px; height: 22px; opacity: 0; }
|
|
448
462
|
.fx-views__item:hover .fx-cfm__more, .fx-views__item[data-on="true"] .fx-cfm__more, .fx-views__item .fx-cfm__more[aria-expanded="true"], .fx-views__item .fx-cfm__more:focus-visible { opacity: 1; }
|
|
449
463
|
.fx-views__item .fx-cfm__more .fx-lucide { width: 14px; height: 14px; }
|
|
450
|
-
.fx-views__add { display: inline-flex; align-items: center; gap: 4px; padding:
|
|
451
|
-
.fx-views__add:hover { color: var(--t-strong); }
|
|
464
|
+
.fx-views__add { display: inline-flex; align-items: center; gap: 4px; min-height: 30px; padding: 4px 9px; border: 0; border-radius: 999px; background: none; color: var(--t-dim); font: 600 13px/1.2 var(--t-body); cursor: pointer; }
|
|
465
|
+
.fx-views__add:hover { background: var(--fx-hover); color: var(--t-strong); }
|
|
466
|
+
.fx-views__add:focus-visible { outline: 2px solid var(--t-ring, var(--t-accent)); outline-offset: 2px; }
|
|
452
467
|
.fx-views__add .fx-lucide { width: 14px; height: 14px; }
|
|
453
|
-
.fx-views__end { display: inline-flex; gap: 6px; margin-left:
|
|
468
|
+
.fx-views__end { display: inline-flex; gap: 6px; margin-left: 4px; }
|
|
454
469
|
@media (hover: none) { .fx-views__item .fx-cfm__more { opacity: 1; } }
|
|
470
|
+
/* A phone keeps the tools on one row of their own that scrolls sideways. */
|
|
471
|
+
@media (max-width: 639px) {
|
|
472
|
+
.fx-toolbar__tools { flex: 1 1 100%; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
|
|
473
|
+
.fx-toolbar__tools > *, .fx-views { flex: none; flex-wrap: nowrap; }
|
|
474
|
+
.fx-toolbar__end:has(> .fx-toolbar__tools) { flex-wrap: wrap; row-gap: 8px; }
|
|
475
|
+
}
|
|
455
476
|
|
|
456
477
|
/* Quiet alerts (server/ui/alerts.js): one slim line under the page header,
|
|
457
478
|
only while something on the page needs this person. */
|
|
@@ -466,7 +487,7 @@ a.fx-strong:hover { text-decoration: underline; }
|
|
|
466
487
|
.fx-alerts__close:hover { background: var(--fx-hover); color: var(--t-strong); }
|
|
467
488
|
.fx-alerts__close svg { width: 14px; height: 14px; }
|
|
468
489
|
.fx-alerts__action:focus-visible, .fx-alerts__close:focus-visible { outline: 2px solid var(--t-ring); outline-offset: 2px; }
|
|
469
|
-
@media (max-width:
|
|
490
|
+
@media (max-width: 639px) {
|
|
470
491
|
.fx-alerts { flex-wrap: wrap; }
|
|
471
492
|
.fx-alerts__text { flex-basis: calc(100% - 52px); }
|
|
472
493
|
.fx-alerts__action, .fx-alerts__more { order: 2; }
|
|
@@ -572,6 +593,30 @@ a.fx-strong:hover { text-decoration: underline; }
|
|
|
572
593
|
.fx-pop__item[aria-checked="true"] { color: var(--t-strong); font-weight: 600; }
|
|
573
594
|
.fx-pop__tick { display: inline-grid; place-items: center; flex: none; width: 16px; height: 16px; color: var(--t-accent); }
|
|
574
595
|
.fx-pop__sep { height: 1px; margin: 6px 4px; background: var(--fx-line-soft); }
|
|
596
|
+
/* A row with a trailing control (the sidebar pin). The control does not
|
|
597
|
+
close the menu. An unpinned pin shows when the pointer is on the row. */
|
|
598
|
+
.fx-pop__row { display: flex; align-items: center; gap: 2px; }
|
|
599
|
+
.fx-pop__row > .fx-pop__item { flex: 1; min-width: 0; }
|
|
600
|
+
.fx-pop__row > .fx-pop__item > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
601
|
+
.fx-pop__pin, .fx-pop__pin--fixed {
|
|
602
|
+
display: inline-grid; place-items: center; flex: none; width: 28px; height: 28px;
|
|
603
|
+
border: 0; border-radius: var(--t-radius); background: none; color: var(--t-dim);
|
|
604
|
+
}
|
|
605
|
+
.fx-pop__pin { cursor: pointer; }
|
|
606
|
+
.fx-pop__pin .fx-lucide, .fx-pop__pin--fixed .fx-lucide, .fx-pop__pin .fx-ico, .fx-pop__pin--fixed .fx-ico { width: 15px; height: 15px; }
|
|
607
|
+
.fx-pop__pin[aria-pressed="false"] { opacity: 0; }
|
|
608
|
+
.fx-pop__row:hover .fx-pop__pin[aria-pressed="false"],
|
|
609
|
+
.fx-pop__row:focus-within .fx-pop__pin[aria-pressed="false"],
|
|
610
|
+
.fx-pop__pin:focus-visible { opacity: 1; }
|
|
611
|
+
.fx-pop__pin[aria-pressed="true"], .fx-pop__pin--fixed { color: var(--t-strong); opacity: 1; }
|
|
612
|
+
.fx-pop__pin:hover, .fx-pop__pin:focus-visible { background: var(--fx-hover); color: var(--t-strong); outline: none; }
|
|
613
|
+
.fx-pop.fx-pop--side { min-width: 240px; }
|
|
614
|
+
.fx-pop--side .fx-pop__tick { color: inherit; }
|
|
615
|
+
@media (hover: none) { .fx-pop__pin[aria-pressed="false"] { opacity: 1; } }
|
|
616
|
+
@media (max-width: 820px) {
|
|
617
|
+
.fx-pop--side .fx-pop__item { min-height: 44px; }
|
|
618
|
+
.fx-pop--side .fx-pop__pin, .fx-pop--side .fx-pop__pin--fixed { width: 44px; height: 44px; }
|
|
619
|
+
}
|
|
575
620
|
.fx-pop__foot { display: flex; justify-content: flex-end; padding: 6px 4px 2px; border-top: 1px solid var(--fx-line-soft); margin-top: 6px; }
|
|
576
621
|
/* A chip with an × that clears it (as ClickUp's "Clear all filters"). */
|
|
577
622
|
.fx-chipset { display: inline-flex; align-items: stretch; }
|
|
@@ -649,7 +694,7 @@ a.fx-strong:hover { text-decoration: underline; }
|
|
|
649
694
|
.fx-dot--stage[data-rank="7"] { --stage: var(--t-dim); }
|
|
650
695
|
.fx-pop--choices .fx-input { min-height: 32px; margin-bottom: 4px; font-size: 13px; }
|
|
651
696
|
.fx-pop__end { display: inline-grid; margin-left: auto; color: var(--t-accent); }
|
|
652
|
-
@media (max-width:
|
|
697
|
+
@media (max-width: 639px) {
|
|
653
698
|
.fx-pop.fx-pop--rows { min-width: 0; width: calc(100vw - 16px); }
|
|
654
699
|
.fx-rows__row, .fx-rows__row--sort { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 32px; }
|
|
655
700
|
.fx-rows__row > .fx-rows__lead, .fx-rows__row > .fx-select:first-child, .fx-rows__row > .fx-rows__join { grid-column: 1 / -1; }
|
|
@@ -785,6 +830,29 @@ th:hover > .fx-th-grip::after { background: var(--t-brd-hi); }
|
|
|
785
830
|
.fx-main--board .fx-board { height: 100%; overflow-y: hidden; align-items: stretch; }
|
|
786
831
|
.fx-main--board .fx-board__cards { flex: 1; max-height: none; }
|
|
787
832
|
}
|
|
833
|
+
/* Phone: one lane fills the width and snaps. Stage tabs (jobs.js) name the
|
|
834
|
+
lane; the lane's own head is hidden. Drag stays on a wider screen. */
|
|
835
|
+
.fx-board-tabs { display: none; }
|
|
836
|
+
@media (max-width: 639px) {
|
|
837
|
+
.fx-main--board .fx-board-tabs:not([hidden]) {
|
|
838
|
+
display: flex; flex: 1 1 100%; order: -1; gap: 2px; min-width: 0; max-width: 100%;
|
|
839
|
+
overflow-x: auto; scrollbar-width: none;
|
|
840
|
+
}
|
|
841
|
+
.fx-board-tabs button {
|
|
842
|
+
flex: none; display: inline-flex; align-items: center; gap: 8px; min-width: 44px; min-height: 44px;
|
|
843
|
+
padding: 0 12px; border: 0; border-bottom: 2px solid transparent; background: transparent;
|
|
844
|
+
color: var(--t-dim); font: 600 14px var(--t-body); cursor: pointer;
|
|
845
|
+
}
|
|
846
|
+
.fx-board-tabs button[aria-selected="true"] { color: var(--t-strong); border-bottom-color: var(--t-brand); }
|
|
847
|
+
.fx-main--board .fx-frame__body { padding: 0; }
|
|
848
|
+
.fx-main--board .fx-board {
|
|
849
|
+
--fx-lane: 100%; grid-auto-columns: 100%; gap: 0; min-width: 0; width: 100%;
|
|
850
|
+
scroll-snap-type: x mandatory; scrollbar-width: none;
|
|
851
|
+
}
|
|
852
|
+
.fx-main--board .fx-board__col { scroll-snap-align: start; scroll-snap-stop: always; border-radius: 0; }
|
|
853
|
+
.fx-main--board .fx-board__head { display: none; }
|
|
854
|
+
.fx-main--board .fx-board__cards { max-height: none; padding: 8px; }
|
|
855
|
+
}
|
|
788
856
|
.fx-board__none { padding: 8px 4px; color: var(--t-dim); font-size: 13px; }
|
|
789
857
|
.fx-table--jobs tbody tr { cursor: pointer; }
|
|
790
858
|
|
|
@@ -959,13 +1027,74 @@ th:hover > .fx-th-grip::after { background: var(--t-brd-hi); }
|
|
|
959
1027
|
.fx-task__activity li::after { content: ""; position: absolute; left: 5.5px; top: 16px; bottom: 0; width: 1px; background: var(--fx-line); }
|
|
960
1028
|
.fx-task__activity li:last-child::after { display: none; }
|
|
961
1029
|
.fx-task__activity time { display: block; margin-top: 1px; color: var(--t-mute); font-size: 11.5px; }
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1030
|
+
/* A record's phone bar and foot. Hidden above a phone, so the desk panel and
|
|
1031
|
+
the invoice header stay as they are. */
|
|
1032
|
+
.fx-record, .fx-record__foot { display: none; }
|
|
1033
|
+
@media (max-width: 639px) {
|
|
1034
|
+
/* The job panel is the whole screen. Back, the client and the next job
|
|
1035
|
+
sit in the bar; Activity and Fix are tabs under it; the action is fixed
|
|
1036
|
+
at the foot, in thumb reach. */
|
|
1037
|
+
.fx-dialog.fx-task {
|
|
1038
|
+
display: flex; flex-direction: column; inset: 0; width: 100%; max-width: none;
|
|
1039
|
+
height: 100%; max-height: none; margin: 0; border-radius: 0; overflow: hidden;
|
|
1040
|
+
}
|
|
1041
|
+
.fx-dialog.fx-task > .fx-record { flex: none; }
|
|
1042
|
+
.fx-dialog.fx-task .fx-task__grid {
|
|
1043
|
+
display: flex; flex-direction: column; flex: 1; min-height: 0; overflow-y: auto;
|
|
1044
|
+
grid-template-columns: minmax(0, 1fr);
|
|
1045
|
+
}
|
|
1046
|
+
.fx-dialog.fx-task .fx-task__main { padding: 16px; }
|
|
1047
|
+
.fx-dialog.fx-task .fx-task__fields { grid-template-columns: minmax(0, 1fr); }
|
|
1048
|
+
.fx-dialog.fx-task .fx-task__head, .fx-dialog.fx-task .fx-task__title { display: none; }
|
|
1049
|
+
.fx-dialog.fx-task .fx-task__grid:has(> .fx-sidecar [data-tab="fix"][aria-selected="true"]) { grid-template-columns: minmax(0, 1fr); }
|
|
1050
|
+
.fx-task__grid > .fx-sidecar__head {
|
|
1051
|
+
position: sticky; top: 0; z-index: 2; flex: none;
|
|
1052
|
+
background: var(--t-paper); border-bottom: 1px solid var(--fx-line-soft);
|
|
1053
|
+
}
|
|
1054
|
+
.fx-task__grid > .fx-sidecar__head .fx-sidecar__close, .fx-sidecar--page .fx-sidecar__close { display: none; }
|
|
1055
|
+
.fx-task__grid > .fx-sidecar__head .fx-sidecar__tab, .fx-sidecar--page .fx-sidecar__tab { min-width: 44px; min-height: 44px; }
|
|
1056
|
+
.fx-sidecar--page { border-left: 0; border-top: 1px solid var(--fx-line); }
|
|
1057
|
+
.fx-sidecar--page .fx-sidecar__body { scroll-margin-top: 52px; }
|
|
1058
|
+
.fx-dialog.fx-task .fx-task__actions:not(:empty) {
|
|
1059
|
+
position: fixed; left: 0; right: 0; bottom: 0; z-index: 5; margin: 0;
|
|
1060
|
+
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
|
1061
|
+
background: var(--t-paper); border-top: 1px solid var(--fx-line);
|
|
1062
|
+
}
|
|
1063
|
+
.fx-dialog.fx-task .fx-task__actions .fx-btn { flex: 1; min-height: 44px; }
|
|
1064
|
+
.fx-dialog.fx-task:has(.fx-task__actions:not(:empty)) .fx-task__grid,
|
|
1065
|
+
.fx-dialog.fx-task:has([data-action="accept"]) .fx-task__grid { padding-bottom: 68px; }
|
|
1066
|
+
.fx-dialog.fx-task:has([data-action="accept"]) .fx-task__actions { display: none; }
|
|
1067
|
+
.fx-invoice [data-action="accept"], .fx-dialog.fx-task [data-action="accept"] {
|
|
1068
|
+
position: fixed; left: 8px; right: 8px; bottom: 8px; z-index: 6; width: auto; min-height: 44px;
|
|
1069
|
+
}
|
|
1070
|
+
.fx-record {
|
|
1071
|
+
display: flex; align-items: center; gap: 2px; min-height: 48px; padding: 2px 4px;
|
|
1072
|
+
background: var(--t-paper); border-bottom: 1px solid var(--fx-line-soft);
|
|
1073
|
+
}
|
|
1074
|
+
.fx-record__back, .fx-record__step, .fx-record__menu {
|
|
1075
|
+
flex: none; display: inline-grid; place-items: center; width: 44px; height: 44px;
|
|
1076
|
+
min-width: 44px; min-height: 44px; padding: 0; border: 0; border-radius: var(--t-radius);
|
|
1077
|
+
background: transparent; color: var(--t-strong); cursor: pointer;
|
|
1078
|
+
}
|
|
1079
|
+
.fx-record__back:disabled, .fx-record__step:disabled { opacity: 0.35; cursor: default; }
|
|
1080
|
+
.fx-record__back:focus-visible, .fx-record__step:focus-visible, .fx-record__menu:focus-visible { box-shadow: var(--fx-focus); }
|
|
1081
|
+
.fx-record__menu[hidden] { display: none; }
|
|
1082
|
+
.fx-record__title, .fx-record .fx-title {
|
|
1083
|
+
flex: 1; min-width: 0; margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
1084
|
+
color: var(--t-strong); font: 600 16px/1.2 var(--t-body); letter-spacing: 0;
|
|
1085
|
+
}
|
|
1086
|
+
.fx-record .fx-ph { flex: 1; min-width: 0; min-height: 0; gap: 8px; background: transparent; }
|
|
1087
|
+
.fx-record .fx-ph__text { min-width: 0; }
|
|
1088
|
+
.fx-record__end { display: flex; flex: none; align-items: center; }
|
|
1089
|
+
.fx-record__foot:not([hidden]) {
|
|
1090
|
+
display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 5; gap: 8px;
|
|
1091
|
+
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
|
1092
|
+
background: var(--t-paper); border-top: 1px solid var(--fx-line);
|
|
1093
|
+
}
|
|
1094
|
+
.fx-record__foot .fx-btn { flex: 1; min-height: 44px; }
|
|
1095
|
+
.fx-invoice > .fx-pager, .fx-invoice .fx-ph__actions { display: none; }
|
|
1096
|
+
.fx-invoice:has(.fx-record__foot:not([hidden])), .fx-invoice:has([data-action="accept"]) { padding-bottom: 72px; }
|
|
1097
|
+
.fx-invoice:has([data-action="accept"]) .fx-record__foot { display: none; }
|
|
969
1098
|
}
|
|
970
1099
|
|
|
971
1100
|
/* ── Dialog ─────────────────────────────────────────────────────────────── */
|
|
@@ -979,6 +1108,17 @@ th:hover > .fx-th-grip::after { background: var(--t-brd-hi); }
|
|
|
979
1108
|
.fx-dialog__form { display: grid; gap: 16px; padding: 22px; }
|
|
980
1109
|
.fx-dialog__title { color: var(--t-strong); font: var(--t-display-weight) 21px/1.2 var(--t-display); }
|
|
981
1110
|
.fx-dialog__actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
|
|
1111
|
+
.fx-dialog[data-phone-layout="sheet"] {
|
|
1112
|
+
position: fixed; inset: auto 0 0 0; width: 100%; max-width: 100%; max-height: min(80vh, 100%);
|
|
1113
|
+
margin: 0; border-radius: var(--t-radius-lg) var(--t-radius-lg) 0 0;
|
|
1114
|
+
}
|
|
1115
|
+
.fx-sheet__choices { display: grid; gap: 4px; }
|
|
1116
|
+
.fx-sheet__choice {
|
|
1117
|
+
display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%;
|
|
1118
|
+
min-height: 44px; padding: 0 12px; border: 0; border-radius: var(--t-radius);
|
|
1119
|
+
background: transparent; color: var(--t-strong); font: 600 15px var(--t-body); text-align: left; cursor: pointer;
|
|
1120
|
+
}
|
|
1121
|
+
.fx-sheet__choice:hover { background: var(--fx-hover); }
|
|
982
1122
|
|
|
983
1123
|
/* Search (search.js): a box near the top, results grouped under it. */
|
|
984
1124
|
.fx-search-dialog { width: min(600px, calc(100vw - 32px)); margin-top: 12vh; }
|
|
@@ -1023,13 +1163,27 @@ th:hover > .fx-th-grip::after { background: var(--t-brd-hi); }
|
|
|
1023
1163
|
.fx-auth__title { font-size: 26px; max-width: none; }
|
|
1024
1164
|
}
|
|
1025
1165
|
|
|
1026
|
-
/* A one-message page (sign-in off, an error, no access,
|
|
1166
|
+
/* A one-message page (sign-in off, an error, no access, an OAuth return). */
|
|
1027
1167
|
.fx-message, .fx-centre .fx-message { min-height: 100vh; place-content: center; justify-items: center; gap: 20px; padding: 32px 16px; }
|
|
1028
1168
|
.fx-centre .fx-message { display: grid; }
|
|
1029
1169
|
.fx-message__card { display: grid; gap: 12px; width: min(460px, 100%); padding: 28px; }
|
|
1030
1170
|
.fx-message__card[data-tone="success"] { border-top: 3px solid var(--t-success); }
|
|
1031
1171
|
.fx-message__card[data-tone="danger"] { border-top: 3px solid var(--t-danger); }
|
|
1032
1172
|
.fx-message__card .fx-btn { justify-self: start; }
|
|
1173
|
+
.fx-message__marks {
|
|
1174
|
+
display: flex; align-items: center; gap: 10px; margin-bottom: 4px;
|
|
1175
|
+
}
|
|
1176
|
+
.fx-message__marks--solo { justify-content: flex-start; }
|
|
1177
|
+
.fx-message__flow .fx-mark { width: 34px; height: 34px; display: block; }
|
|
1178
|
+
.fx-message__plus { color: var(--t-dim); font: 600 18px/1 var(--t-body); }
|
|
1179
|
+
.fx-message__result {
|
|
1180
|
+
display: grid; place-items: center; width: 28px; height: 28px; margin-left: 4px;
|
|
1181
|
+
border-radius: 50%; color: var(--t-success); background: var(--t-success-bg);
|
|
1182
|
+
}
|
|
1183
|
+
.fx-message__result[data-tone="danger"] { color: var(--t-danger); background: var(--t-danger-bg); }
|
|
1184
|
+
.fx-message__result .fx-lucide { width: 16px; height: 16px; }
|
|
1185
|
+
.fx-message__status { margin: 0; }
|
|
1186
|
+
.fx-message__return { margin: 0; color: var(--t-dim); font-size: 13.5px; }
|
|
1033
1187
|
|
|
1034
1188
|
.fx-loading { display: none; min-height: 100vh; place-content: center; gap: 12px; color: var(--t-dim); }
|
|
1035
1189
|
body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
@@ -1058,7 +1212,7 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1058
1212
|
.fx-setting__value { font-size: 12.5px; color: var(--t-strong); overflow-wrap: anywhere; text-align: right; }
|
|
1059
1213
|
.fx-setting--wide { grid-template-columns: minmax(0, 1fr); }
|
|
1060
1214
|
.fx-setting--wide .fx-setting__control { display: block; }
|
|
1061
|
-
@media (max-width:
|
|
1215
|
+
@media (max-width: 639px) {
|
|
1062
1216
|
.fx-setting { grid-template-columns: minmax(0, 1fr); }
|
|
1063
1217
|
.fx-setting__control { justify-content: flex-start; }
|
|
1064
1218
|
.fx-setting__stack { justify-items: start; }
|
|
@@ -1125,6 +1279,7 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1125
1279
|
background: rgba(0, 0, 0, .32);
|
|
1126
1280
|
}
|
|
1127
1281
|
.fx-nav__report { margin-top: 8px; }
|
|
1282
|
+
.fx-nav a, .fx-nav__report, .fx-nav__more { min-height: 44px; }
|
|
1128
1283
|
.fx-side__end { margin-left: auto; padding: 0; border-top: 0; }
|
|
1129
1284
|
#user-button { flex: none; }
|
|
1130
1285
|
}
|
|
@@ -1145,15 +1300,36 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1145
1300
|
}
|
|
1146
1301
|
|
|
1147
1302
|
/* ── Phones ─────────────────────────────────────────────────────────────── */
|
|
1148
|
-
@media (max-width:
|
|
1303
|
+
@media (max-width: 639px) {
|
|
1149
1304
|
.fx-main { padding-top: 20px; }
|
|
1305
|
+
/* A two-line list needs the rows, not the gaps, so seven fit at 375×667.
|
|
1306
|
+
The alert stays one line. The toolbar stays one scrolling row. */
|
|
1307
|
+
.fx-main--frame:has([data-phone-layout="two-line"]) { gap: 8px; padding-top: 12px; }
|
|
1308
|
+
.fx-alerts { flex-wrap: nowrap; }
|
|
1309
|
+
.fx-alerts__text { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
1310
|
+
/* Tabs stay on their own row. The tools beside them stay one row and
|
|
1311
|
+
scroll, so a chip is never covered by the next control. */
|
|
1312
|
+
.fx-listhead, .fx-listhead > .fx-toolbar { min-width: 0; max-width: 100%; }
|
|
1313
|
+
.fx-listhead .fx-toolbar__tools { flex: 1 1 auto; min-width: 0; overflow-x: auto; scrollbar-width: none; }
|
|
1314
|
+
.fx-listhead .fx-toolbar__end,
|
|
1315
|
+
.fx-listhead .fx-toolbar__end:has(> .fx-toolbar__tools) {
|
|
1316
|
+
flex: 1 1 100%; flex-wrap: nowrap; min-width: 0; overflow-x: auto; scrollbar-width: none; row-gap: 0;
|
|
1317
|
+
}
|
|
1150
1318
|
.fx-title { font-size: 22px; }
|
|
1151
1319
|
.fx-table thead { display: none; }
|
|
1152
1320
|
.fx-table.fx-table--sized { width: 100% !important; min-width: 0; table-layout: auto; }
|
|
1153
1321
|
.fx-table--sized td { white-space: normal; }
|
|
1154
1322
|
.fx-table--sized colgroup { display: none; }
|
|
1155
1323
|
.fx-table--sized td.fx-c-end { display: none; }
|
|
1156
|
-
|
|
1324
|
+
/* Tables outside a column list still stack. People keeps its own grid. */
|
|
1325
|
+
.fx-table-scroll:not([data-phone-layout="two-line"]) .fx-table,
|
|
1326
|
+
.fx-table-scroll:not([data-phone-layout="two-line"]) .fx-table tbody,
|
|
1327
|
+
.fx-table-scroll:not([data-phone-layout="two-line"]) .fx-table tr,
|
|
1328
|
+
.fx-table-scroll:not([data-phone-layout="two-line"]) .fx-table td,
|
|
1329
|
+
.fx-table:not(.fx-table--sized, .fx-people),
|
|
1330
|
+
.fx-table:not(.fx-table--sized, .fx-people) tbody,
|
|
1331
|
+
.fx-table:not(.fx-table--sized, .fx-people) tr,
|
|
1332
|
+
.fx-table:not(.fx-table--sized, .fx-people) td { display: block; width: 100%; }
|
|
1157
1333
|
.fx-table tr { padding: 12px 14px; border-bottom: 1px solid var(--fx-line-soft); }
|
|
1158
1334
|
.fx-table td { padding: 4px 0; border: 0; }
|
|
1159
1335
|
.fx-table td:nth-child(2), .fx-table td:nth-child(3) { display: inline-flex; width: auto; margin: 6px 10px 0 0; vertical-align: middle; }
|
|
@@ -1170,20 +1346,58 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1170
1346
|
.fx-people td:nth-child(2) .fx-select { width: 100%; }
|
|
1171
1347
|
.fx-people td:nth-child(3) { grid-area: 3 / 1 / 4 / -1; }
|
|
1172
1348
|
.fx-people td:nth-child(3):empty { display: none; }
|
|
1173
|
-
/*
|
|
1174
|
-
and
|
|
1175
|
-
with
|
|
1176
|
-
.fx-table
|
|
1177
|
-
|
|
1178
|
-
.fx-table
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
.fx-table
|
|
1185
|
-
|
|
1186
|
-
|
|
1349
|
+
/* Column lists (columns.js): two lines, 56px. Line 1 is the title columns
|
|
1350
|
+
and the amount. Line 2 is the status and up to three meta columns.
|
|
1351
|
+
The tick stays at the left with a 44px hit area. */
|
|
1352
|
+
[data-phone-layout="two-line"] .fx-table,
|
|
1353
|
+
[data-phone-layout="two-line"] .fx-table tbody { display: block; width: 100% !important; min-width: 0; }
|
|
1354
|
+
[data-phone-layout="two-line"] .fx-table tbody tr:not(.fx-table__group) {
|
|
1355
|
+
display: flex; flex-wrap: wrap; align-items: center; position: relative;
|
|
1356
|
+
box-sizing: border-box; height: 56px; min-height: 56px; max-height: 56px;
|
|
1357
|
+
margin: 0; padding: 6px 12px 6px 44px; overflow: hidden;
|
|
1358
|
+
border-bottom: 1px solid var(--fx-line-soft);
|
|
1359
|
+
}
|
|
1360
|
+
[data-phone-layout="two-line"] .fx-table tbody tr:not(.fx-table__group)::after {
|
|
1361
|
+
content: ""; order: 3; flex-basis: 100%; height: 0;
|
|
1362
|
+
}
|
|
1363
|
+
[data-phone-layout="two-line"] .fx-table td,
|
|
1364
|
+
[data-phone-layout="two-line"] .fx-table td:nth-child(2),
|
|
1365
|
+
[data-phone-layout="two-line"] .fx-table td:nth-child(3) {
|
|
1366
|
+
display: block; width: auto; margin: 0; padding: 0; border: 0;
|
|
1367
|
+
white-space: nowrap; background: none;
|
|
1368
|
+
}
|
|
1369
|
+
[data-phone-layout="two-line"] .fx-tick-cell {
|
|
1370
|
+
position: absolute; top: 0; left: 0; display: flex; align-items: center; justify-content: center;
|
|
1371
|
+
width: 44px; height: 56px; padding: 0;
|
|
1372
|
+
}
|
|
1373
|
+
[data-phone-layout="two-line"] .fx-tick-cell .fx-tick { width: 44px; height: 44px; margin: 0; }
|
|
1374
|
+
[data-phone-layout="two-line"] [data-phone-slot="title"] {
|
|
1375
|
+
order: 1; flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis;
|
|
1376
|
+
color: var(--t-strong); font-weight: 600;
|
|
1377
|
+
}
|
|
1378
|
+
[data-phone-layout="two-line"] [data-phone-slot="title"] :is(a, button) {
|
|
1379
|
+
display: inline-flex; align-items: center; max-width: 100%; min-height: 44px;
|
|
1380
|
+
}
|
|
1381
|
+
[data-phone-layout="two-line"] [data-phone-slot="end"] {
|
|
1382
|
+
order: 2; flex: none; margin-left: 8px; font-variant-numeric: tabular-nums;
|
|
1383
|
+
}
|
|
1384
|
+
[data-phone-layout="two-line"] [data-phone-slot="meta"] {
|
|
1385
|
+
order: 5; flex: 0 1 auto; min-width: 0; max-width: 42%; overflow: hidden; text-overflow: ellipsis;
|
|
1386
|
+
color: var(--t-dim); font-size: 12px; line-height: 16px;
|
|
1387
|
+
}
|
|
1388
|
+
[data-phone-layout="two-line"] td.fx-c-stage,
|
|
1389
|
+
[data-phone-layout="two-line"] td.fx-c-status { order: 4; color: inherit; }
|
|
1390
|
+
[data-phone-layout="two-line"] .fx-stage { padding-block: 0; line-height: 16px; }
|
|
1391
|
+
[data-phone-layout="two-line"] [data-phone-slot="hide"],
|
|
1392
|
+
[data-phone-layout="two-line"] td.fx-c-end { display: none; }
|
|
1393
|
+
[data-phone-layout="two-line"] tr.fx-table__group {
|
|
1394
|
+
display: flex; align-items: center; box-sizing: border-box; height: 32px; min-height: 32px; max-height: 32px;
|
|
1395
|
+
margin: 0; padding: 0 8px 0 44px; overflow: visible; background: var(--t-s1);
|
|
1396
|
+
border-bottom: 1px solid var(--fx-line-soft);
|
|
1397
|
+
}
|
|
1398
|
+
[data-phone-layout="two-line"] tr.fx-table__group td { height: 32px; padding: 0; background: none; }
|
|
1399
|
+
[data-phone-layout="two-line"] tr.fx-table__group .fx-tick-cell { height: 32px; }
|
|
1400
|
+
[data-phone-layout="two-line"] tr.fx-table__group .fx-tick-cell .fx-tick { width: 44px; height: 44px; }
|
|
1187
1401
|
}
|
|
1188
1402
|
|
|
1189
1403
|
@keyframes fx-rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
|
|
@@ -1212,7 +1426,10 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1212
1426
|
.fx-price { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
|
|
1213
1427
|
.fx-price__head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 8px 16px; }
|
|
1214
1428
|
.fx-price__head .fx-search { margin: 0 0 6px; width: 260px; }
|
|
1215
|
-
@media (max-width:
|
|
1429
|
+
@media (max-width: 639px) {
|
|
1430
|
+
.fx-price__head .fx-search { width: 100%; }
|
|
1431
|
+
.fx-price__settings .fx-select { min-height: 44px; }
|
|
1432
|
+
}
|
|
1216
1433
|
.fx-price__table th { position: sticky; top: 0; z-index: 1; }
|
|
1217
1434
|
.fx-price__table td { padding-top: 9px; padding-bottom: 9px; }
|
|
1218
1435
|
.fx-price__table td.fx-num, .fx-price__table th.fx-num { text-align: right; white-space: nowrap; }
|
|
@@ -1384,13 +1601,27 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1384
1601
|
.fx-cfs__delete { color: var(--t-danger); background: color-mix(in srgb, var(--t-danger) 12%, transparent); }
|
|
1385
1602
|
.fx-cfs__delete:hover { background: color-mix(in srgb, var(--t-danger) 28%, transparent); }
|
|
1386
1603
|
.fx-cfs__delete .fx-lucide { width: 16px; height: 16px; }
|
|
1387
|
-
@media (max-width:
|
|
1604
|
+
@media (max-width: 639px) {
|
|
1388
1605
|
.fx-cfm { grid-template-columns: minmax(0, 1fr) 36px 32px; column-gap: 8px; }
|
|
1389
1606
|
.fx-cfm .fx-cfm__by, .fx-cfm .fx-cfm__date, .fx-cfm .fx-cfm__where { display: none; }
|
|
1390
1607
|
.fx-cfm__head, .fx-cfm__row { padding-left: 16px; }
|
|
1391
1608
|
.fx-cfm__create { padding-left: 16px; }
|
|
1392
1609
|
.fx-cfm__search { flex: 1 1 100%; width: auto; }
|
|
1393
1610
|
.fx-cfm__edit { display: none !important; }
|
|
1611
|
+
/* Custom fields uses the same phone slots as a column list: name and the
|
|
1612
|
+
menu on line 1, up to three facts on line 2, 56px. */
|
|
1613
|
+
.fx-cfm__row {
|
|
1614
|
+
display: flex; flex-wrap: wrap; align-items: center; box-sizing: border-box;
|
|
1615
|
+
height: 56px; min-height: 56px; max-height: 56px; padding: 6px 8px 6px 16px; overflow: hidden;
|
|
1616
|
+
}
|
|
1617
|
+
.fx-cfm__row::after { content: ""; order: 3; flex-basis: 100%; height: 0; }
|
|
1618
|
+
.fx-cfm__row > * { display: none; }
|
|
1619
|
+
.fx-cfm__row > [data-phone-slot="title"] { display: block; order: 1; flex: 1 1 0; min-width: 0; }
|
|
1620
|
+
.fx-cfm__row > [data-phone-slot="end"] { display: flex; order: 2; flex: none; align-items: center; }
|
|
1621
|
+
.fx-cfm__row > [data-phone-slot="meta"] {
|
|
1622
|
+
display: block; order: 5; flex: 0 1 auto; min-width: 0; max-width: 40%; overflow: hidden;
|
|
1623
|
+
text-overflow: ellipsis; white-space: nowrap; color: var(--t-dim); font-size: 12px; line-height: 16px;
|
|
1624
|
+
}
|
|
1394
1625
|
}
|
|
1395
1626
|
/* Invoice rules (invoice-rules.js): a row's Edit button and switch, and the
|
|
1396
1627
|
rule dialog's condition lines. */
|
|
@@ -1405,10 +1636,10 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1405
1636
|
.fx-rule__value { display: flex; gap: 6px; align-items: center; min-width: 0; }
|
|
1406
1637
|
.fx-rule__many { display: grid; gap: 2px; max-height: 160px; overflow: auto; padding: 4px 8px; border: 1px solid var(--fx-line); border-radius: 8px; width: 100%; }
|
|
1407
1638
|
.fx-rule__delete { justify-self: start; color: var(--t-danger); }
|
|
1408
|
-
@media (max-width:
|
|
1639
|
+
@media (max-width: 639px) {
|
|
1409
1640
|
.fx-rule__condition { grid-template-columns: minmax(0, 1fr); }
|
|
1410
1641
|
}
|
|
1411
|
-
@media (max-width:
|
|
1642
|
+
@media (max-width: 639px) {
|
|
1412
1643
|
.fx-set__row { gap: 12px; }
|
|
1413
1644
|
.fx-set__control .fx-input { width: 140px; }
|
|
1414
1645
|
.fx-set__control .fx-input[type="number"] { width: 72px; }
|
|
@@ -1416,7 +1647,7 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1416
1647
|
}
|
|
1417
1648
|
.fx-multi { position: relative; width: 220px; max-width: 100%; }
|
|
1418
1649
|
.fx-multi__summary { display: flex; align-items: center; list-style: none; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1419
|
-
@media (max-width:
|
|
1650
|
+
@media (max-width: 639px) { .fx-multi { width: 150px; } }
|
|
1420
1651
|
.fx-multi__summary::-webkit-details-marker { display: none; }
|
|
1421
1652
|
.fx-multi__list { position: absolute; right: 0; top: calc(100% + 4px); z-index: 30; display: grid; gap: 2px; min-width: 100%; max-height: 280px; overflow-y: auto; padding: 6px; background: var(--t-paper); border: 1px solid var(--fx-line); border-radius: var(--t-radius-lg); box-shadow: var(--t-shadow); }
|
|
1422
1653
|
.fx-multi__option { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 6px 8px; cursor: pointer; white-space: nowrap; }
|
|
@@ -1504,9 +1735,19 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1504
1735
|
.fx-listhead__edge { height: 0; }
|
|
1505
1736
|
.fx-listhead__edge + .fx-listhead[data-sticky] { margin-top: -32px; }
|
|
1506
1737
|
.fx-listhead > .fx-toolbar > .fx-tabs button { padding-block: 9px; }
|
|
1738
|
+
/* Every control in the toolbar is one height (--fx-control-h). Under a
|
|
1739
|
+
tab line, the controls keep 8px clear of the line; only the tabs sit on it. */
|
|
1740
|
+
.fx-listhead .fx-toolbar :is(.fx-btn, .fx-chip, .fx-views__add, .fx-views__tab) { min-height: var(--fx-control-h); }
|
|
1741
|
+
.fx-listhead .fx-toolbar .fx-btn:not(.fx-btn--sm) { padding-block: 0; font-size: 14px; }
|
|
1742
|
+
.fx-listhead .fx-toolbar :is(.fx-btn, .fx-chip) { height: var(--fx-control-h); }
|
|
1743
|
+
.fx-listhead .fx-toolbar .fx-find__button { width: var(--fx-control-h); height: var(--fx-control-h); }
|
|
1744
|
+
.fx-listhead .fx-toolbar .fx-find__input { height: var(--fx-control-h); }
|
|
1745
|
+
.fx-listhead .fx-toolbar .fx-seg { padding: 2px; }
|
|
1746
|
+
.fx-listhead .fx-toolbar .fx-seg__item { min-height: calc(var(--fx-control-h) - 4px); }
|
|
1747
|
+
.fx-listhead > .fx-toolbar:not(.fx-toolbar--plain) > :not(.fx-tabs) { margin-bottom: 8px; }
|
|
1507
1748
|
@media (max-width: 820px) { .fx-listhead[data-sticky] { top: 60px; } }
|
|
1508
1749
|
/* On a phone the head would hide too many rows: it scrolls away. */
|
|
1509
|
-
@media (max-width:
|
|
1750
|
+
@media (max-width: 639px) { .fx-listhead[data-sticky] { position: static; } }
|
|
1510
1751
|
|
|
1511
1752
|
/* The bulk action bar (bulk-bar.js): floats at the foot while rows are
|
|
1512
1753
|
ticked. "N selected ×", then icon actions in groups, then More. It takes
|
|
@@ -1519,6 +1760,8 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1519
1760
|
}
|
|
1520
1761
|
.fx-bulk[hidden] { display: none; }
|
|
1521
1762
|
.fx-bulk[aria-busy="true"] { opacity: .7; pointer-events: none; }
|
|
1763
|
+
.fx-bulk[aria-busy="true"]:has([data-busy]) { opacity: 1; }
|
|
1764
|
+
.fx-bulk__act .fx-spinner { flex: none; border-color: color-mix(in srgb, currentColor 35%, transparent); border-top-color: currentColor; }
|
|
1522
1765
|
.fx-bulk__acts { display: flex; align-items: center; gap: 2px; min-width: 0; }
|
|
1523
1766
|
.fx-bulk__count { display: inline-flex; align-items: center; gap: 6px; flex: none; margin-right: 6px; padding: 3px 4px 3px 10px; border: 1px solid var(--t-accent-brd, var(--fx-line)); border-radius: var(--t-radius); background: var(--t-accent-bg); color: var(--t-accent); font-weight: 600; }
|
|
1524
1767
|
.fx-bulk__clear, .fx-bulk__act { position: relative; display: inline-flex; align-items: center; gap: 6px; padding: 7px 9px; border: 1px solid transparent; border-radius: var(--t-radius); background: none; color: inherit; font: inherit; cursor: pointer; }
|
|
@@ -1540,13 +1783,18 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1540
1783
|
.fx-bulk__grid { display: grid; }
|
|
1541
1784
|
.fx-bulk__grid .fx-pop__item[data-tone="danger"] { color: var(--t-danger); }
|
|
1542
1785
|
.fx-bulk__none { margin: 8px 10px; color: var(--t-dim); font-size: 13.5px; }
|
|
1543
|
-
@media (max-width:
|
|
1786
|
+
@media (max-width: 639px) {
|
|
1544
1787
|
.fx-bulk { bottom: 10px; padding: 4px; }
|
|
1545
1788
|
.fx-bulk__count { margin-right: 2px; padding-left: 8px; }
|
|
1546
1789
|
.fx-bulk__act { padding: 7px 6px; }
|
|
1547
1790
|
.fx-bulk__sep { margin: 0 2px; }
|
|
1548
1791
|
.fx-bulk__act:not(.fx-bulk__act--primary) .fx-bulk__word { display: none; }
|
|
1549
1792
|
}
|
|
1793
|
+
/* Phone and tablet: Delete and Void are a full touch target. */
|
|
1794
|
+
@media (max-width: 1023px) {
|
|
1795
|
+
.fx-invoice .fx-ph__actions .fx-btn--danger { min-height: 44px; }
|
|
1796
|
+
.fx-bulk__act[data-tone="danger"] { min-width: 44px; min-height: 44px; justify-content: center; }
|
|
1797
|
+
}
|
|
1550
1798
|
|
|
1551
1799
|
/* Xero › Import (server/ui/xero-import.js): Review compares one fact per row
|
|
1552
1800
|
with ✓ or ≠ between the sides; the list and history tick rows for the bulk
|
|
@@ -1602,3 +1850,63 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
|
|
|
1602
1850
|
.fx-find__input { display: none; width: min(240px, 60vw); height: 32px; padding: 0 10px; }
|
|
1603
1851
|
.fx-find--open .fx-find__input { display: block; }
|
|
1604
1852
|
.fx-find--open .fx-find__button { display: none; }
|
|
1853
|
+
|
|
1854
|
+
/* Xero usage on the Xero card (server/ui/xero-usage.js). Colours are tokens. */
|
|
1855
|
+
.fx-xero-orgs { display: grid; gap: 18px; }
|
|
1856
|
+
.fx-xero-org { display: grid; gap: 12px; }
|
|
1857
|
+
.fx-xu { display: grid; gap: 14px; }
|
|
1858
|
+
.fx-xu__top { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
|
|
1859
|
+
.fx-xu__chips { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
|
1860
|
+
.fx-xu-ring { position: relative; width: 112px; height: 112px; flex: none; }
|
|
1861
|
+
.fx-xu-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
|
|
1862
|
+
.fx-xu-ring__track { fill: none; stroke: var(--fx-line); stroke-width: 3; }
|
|
1863
|
+
.fx-xu-ring__used { fill: none; stroke: var(--t-accent); stroke-width: 3; stroke-linecap: round; }
|
|
1864
|
+
.fx-xu[data-tone="warn"] .fx-xu-ring__used { stroke: var(--t-warn); }
|
|
1865
|
+
.fx-xu[data-tone="danger"] .fx-xu-ring__used { stroke: var(--t-danger); }
|
|
1866
|
+
.fx-xu-ring__label { position: absolute; inset: 0; display: grid; place-content: center; justify-items: center; gap: 2px; }
|
|
1867
|
+
.fx-xu-ring__num { color: var(--t-strong); font: 650 22px/1 var(--t-body); font-variant-numeric: tabular-nums; }
|
|
1868
|
+
.fx-xu-ring__of { color: var(--t-dim); font-size: 12px; font-variant-numeric: tabular-nums; }
|
|
1869
|
+
.fx-xu__fold { display: grid; gap: 12px; padding: 12px 14px; border: 1px solid var(--fx-line); border-radius: var(--t-radius-lg); background: var(--t-paper); }
|
|
1870
|
+
.fx-xu__fold summary { cursor: pointer; color: var(--t-strong); font-weight: 650; }
|
|
1871
|
+
.fx-xu__fold summary:focus-visible { outline: 2px solid var(--t-ring, var(--t-accent)); outline-offset: 2px; }
|
|
1872
|
+
.fx-xu-legend { display: flex; flex-wrap: wrap; gap: 8px 14px; }
|
|
1873
|
+
.fx-xu-legend span { display: inline-flex; align-items: center; gap: 6px; color: var(--t-dim); font-size: 12.5px; }
|
|
1874
|
+
.fx-xu-legend i, .fx-xu-lane { display: inline-block; }
|
|
1875
|
+
.fx-xu-legend i { width: 8px; height: 8px; border-radius: 2px; }
|
|
1876
|
+
.fx-xu-hours { display: flex; align-items: flex-end; gap: 3px; height: 88px; }
|
|
1877
|
+
.fx-xu-hour { flex: 1; min-width: 0; height: 100%; display: flex; align-items: flex-end; }
|
|
1878
|
+
.fx-xu-hour__stack { display: flex; flex-direction: column-reverse; width: 100%; height: var(--h, 0%); border-radius: 2px 2px 0 0; overflow: hidden; }
|
|
1879
|
+
.fx-xu-hour__stack i { display: block; width: 100%; height: var(--part, 0%); }
|
|
1880
|
+
.fx-xu-lane[data-lane="writes"] { background: var(--t-accent); }
|
|
1881
|
+
.fx-xu-lane[data-lane="sync"] { background: var(--t-success); }
|
|
1882
|
+
.fx-xu-lane[data-lane="reads"] { background: var(--t-warn); }
|
|
1883
|
+
.fx-xu-lane[data-lane="other"] { background: color-mix(in srgb, var(--t-text) 35%, var(--t-bg)); }
|
|
1884
|
+
.fx-xu-budget { display: flex; height: 10px; border-radius: 999px; overflow: hidden; background: var(--fx-hover); }
|
|
1885
|
+
.fx-xu-budget i { flex: none; width: var(--part, 0%); height: 100%; }
|
|
1886
|
+
.fx-xu-dots { display: flex; flex-wrap: wrap; gap: 12px 16px; }
|
|
1887
|
+
.fx-xu-dot { display: inline-flex; align-items: center; gap: 6px; color: var(--t-dim); font-size: 12.5px; }
|
|
1888
|
+
.fx-xu-dot::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--t-dim); }
|
|
1889
|
+
.fx-xu-dot[data-tone="success"]::before { background: var(--t-success); }
|
|
1890
|
+
.fx-xu-dot[data-tone="warn"]::before { background: var(--t-warn); }
|
|
1891
|
+
.fx-xu-dot[data-tone="danger"]::before { background: var(--t-danger); }
|
|
1892
|
+
.fx-xu-days { position: relative; display: flex; align-items: stretch; gap: 8px; height: 108px; }
|
|
1893
|
+
.fx-xu-days__line { position: absolute; left: 0; right: 0; bottom: calc(16px + (100% - 20px) * var(--warn, 0.7)); height: 0; border-top: 1px dashed var(--t-warn); pointer-events: none; }
|
|
1894
|
+
.fx-xu-day { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 4px; }
|
|
1895
|
+
.fx-xu-day__bar { flex: 1; display: flex; align-items: flex-end; justify-content: center; width: 100%; }
|
|
1896
|
+
.fx-xu-day b { display: block; width: 70%; max-width: 28px; height: var(--h, 0%); border-radius: 3px 3px 0 0; background: var(--t-accent); }
|
|
1897
|
+
.fx-xu-day[data-warning="true"] b { background: var(--t-warn); }
|
|
1898
|
+
.fx-xu-day[data-over="true"] b { background: var(--t-danger); }
|
|
1899
|
+
.fx-xu-day > span:last-child { color: var(--t-dim); font-size: 11px; font-variant-numeric: tabular-nums; }
|
|
1900
|
+
.fx-xu-rows { display: grid; gap: 6px; }
|
|
1901
|
+
.fx-xu-row { display: flex; justify-content: space-between; gap: 12px; font-size: 13px; }
|
|
1902
|
+
.fx-xu-row span { color: var(--t-text); }
|
|
1903
|
+
.fx-xu-row b { color: var(--t-strong); font-weight: 650; font-variant-numeric: tabular-nums; }
|
|
1904
|
+
.fx-xu .fx-notice { margin-top: 4px; }
|
|
1905
|
+
@media (max-width: 639px) {
|
|
1906
|
+
.fx-xu__top { gap: 14px; }
|
|
1907
|
+
.fx-xu-ring { width: 96px; height: 96px; }
|
|
1908
|
+
.fx-xu-ring__num { font-size: 20px; }
|
|
1909
|
+
.fx-xu-hours { overflow-x: auto; }
|
|
1910
|
+
.fx-xu-hour { flex: none; width: 10px; }
|
|
1911
|
+
.fx-xu__fold { padding: 12px; }
|
|
1912
|
+
}
|