@arcforgelabs/flow 2026.10.34 → 2026.10.36

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.
@@ -189,6 +189,30 @@ body:is([data-state="off"], [data-state="error"], [data-state="no-access"]) .fx-
189
189
  .fx-notice[data-tone="danger"] { border-color: var(--t-danger-brd); background: var(--t-danger-bg); color: var(--t-danger); }
190
190
  .fx-panel > .fx-notice { margin: 12px; }
191
191
 
192
+ /* The job changed after its invoice was made (job-change.js): was / now per
193
+ changed fact. Was is struck through; Now is the work system's value. */
194
+ .fx-change {
195
+ display: grid; gap: 10px; padding: 12px 14px;
196
+ border: 1px solid var(--t-danger-brd); border-radius: var(--t-radius);
197
+ background: var(--t-danger-bg); color: var(--t-text); font-size: 14px;
198
+ }
199
+ .fx-change p { margin: 0; }
200
+ .fx-change strong { color: var(--t-danger); }
201
+ .fx-change__head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px; }
202
+ .fx-change__acts { display: flex; flex-wrap: wrap; gap: 8px; }
203
+ .fx-change__note { font-size: 13px; color: var(--t-dim); }
204
+ .fx-change__scroll { overflow-x: auto; }
205
+ .fx-change__table { width: 100%; border-collapse: collapse; background: var(--t-paper); border: 1px solid var(--t-brd); font-size: 13.5px; }
206
+ .fx-change__table th, .fx-change__table td { padding: 8px 12px; border-bottom: 1px solid var(--t-brd); text-align: left; vertical-align: top; }
207
+ .fx-change__table thead th {
208
+ font-size: var(--t-label-size, 12px); font-weight: var(--t-label-weight, 600); letter-spacing: var(--t-label-spacing, .08em);
209
+ text-transform: var(--t-label-case, uppercase); color: var(--t-dim);
210
+ }
211
+ .fx-change__table tbody th { font-weight: 400; color: var(--t-dim); white-space: nowrap; }
212
+ .fx-change__was { background: color-mix(in srgb, var(--t-danger) 9%, transparent); text-decoration: line-through; text-decoration-thickness: 1px; }
213
+ .fx-change__now { background: color-mix(in srgb, var(--t-success) 11%, transparent); color: var(--t-strong); font-weight: 600; }
214
+ .fx-change__table .fx-num { text-align: left; font-family: var(--t-data); font-variant-numeric: tabular-nums; }
215
+
192
216
  .fx-status {
193
217
  display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px;
194
218
  border-radius: 999px; font-size: 12.5px; font-weight: 600; white-space: nowrap;
@@ -199,6 +223,17 @@ body:is([data-state="off"], [data-state="error"], [data-state="no-access"]) .fx-
199
223
  .fx-status[data-tone="warn"] { color: var(--t-warn); background: var(--t-warn-bg); }
200
224
  .fx-status[data-tone="mute"] { color: var(--t-dim); background: var(--fx-hover); }
201
225
  .fx-status[data-tone="danger"] { color: var(--t-danger); background: var(--t-danger-bg); }
226
+ .fx-links { white-space: nowrap; }
227
+ .fx-links > * + * { margin-left: 6px; }
228
+ .fx-link { position: relative; display: inline-grid; place-items: center; width: 26px; height: 26px; border: 1px solid var(--fx-line); border-radius: 8px; vertical-align: middle; }
229
+ .fx-link img { width: 15px; height: 15px; }
230
+ a.fx-link:hover, a.fx-link:focus-visible { border-color: var(--t-strong); }
231
+ .fx-link--none { border-style: dashed; }
232
+ .fx-link--none img { filter: grayscale(1); opacity: .35; }
233
+ .fx-link__dot { position: absolute; right: -3px; bottom: -3px; width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--t-paper); background: var(--t-dim); }
234
+ .fx-link__dot[data-tone="success"] { background: var(--t-success); }
235
+ .fx-link__dot[data-tone="warn"] { background: var(--t-warn); }
236
+ .fx-link__dot[data-tone="danger"] { background: var(--t-danger); }
202
237
  .fx-tag {
203
238
  margin-left: 8px; padding: 1px 7px; border: 1px solid var(--fx-line); border-radius: 999px;
204
239
  color: var(--t-dim); font-size: 11.5px; font-weight: 600;
@@ -220,7 +255,7 @@ body:is([data-state="off"], [data-state="error"], [data-state="no-access"]) .fx-
220
255
  letter-spacing: var(--t-label-spacing); text-transform: var(--t-label-case);
221
256
  }
222
257
  .fx-table td { padding: 12px 16px; border-bottom: 1px solid var(--fx-line-soft); vertical-align: middle; }
223
- .fx-table tbody tr:last-child td { border-bottom: 0; }
258
+ .fx-table tbody:last-child tr:last-child td { border-bottom: 0; }
224
259
  .fx-table tbody tr:hover td { background: var(--fx-hover); }
225
260
  .fx-table__actions { text-align: right; width: 1%; white-space: nowrap; }
226
261
  .fx-table__actions .fx-row { flex-wrap: nowrap; }
@@ -439,7 +474,41 @@ a.fx-strong:hover { text-decoration: underline; }
439
474
  .fx-toolbar--plain .fx-search { margin-bottom: 0; }
440
475
  .fx-empty .fx-btn { margin-top: 12px; }
441
476
  .fx-panel.fx-empty { display: grid; justify-items: center; }
442
- .fx-toolbar--end { justify-content: flex-end; }
477
+ /* The Jobs toolbar: Group, Sort and Filter at the left, as small outlined
478
+ buttons that each open a menu; search and Board/List at the right. */
479
+ .fx-toolbar__end { display: flex; flex: 1 1 360px; align-items: center; justify-content: flex-end; gap: 12px; min-width: 0; margin-left: auto; }
480
+ .fx-toolbar__end .fx-search { flex: 0 1 320px; min-width: 0; }
481
+ .fx-viewbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
482
+ .fx-chip {
483
+ display: inline-flex; align-items: center; gap: 6px; min-height: 30px; padding: 4px 11px;
484
+ border: 1px solid var(--fx-line); border-radius: 999px; background: transparent;
485
+ color: var(--t-text); font: 600 13px/1.2 var(--t-body); white-space: nowrap; cursor: pointer;
486
+ }
487
+ .fx-chip svg { flex: none; color: var(--t-dim); }
488
+ .fx-chip:hover, .fx-chip[aria-expanded="true"] { border-color: var(--t-brd-hi, var(--fx-line)); background: var(--fx-hover); color: var(--t-strong); }
489
+ .fx-chip:focus-visible { outline: 2px solid var(--t-ring, var(--t-accent)); outline-offset: 2px; }
490
+ .fx-chip--on { border-color: var(--t-accent-brd, var(--t-accent)); background: var(--t-accent-bg); color: var(--t-accent); }
491
+ .fx-chip--on svg { color: currentColor; }
492
+ .fx-pop {
493
+ position: fixed; inset: auto; margin: 0; min-width: 220px; max-width: min(320px, calc(100vw - 16px)); max-height: min(420px, calc(100vh - 32px));
494
+ overflow-y: auto; padding: 6px; border: 1px solid var(--fx-line); border-radius: var(--t-radius-lg);
495
+ background: var(--t-paper); color: var(--t-text); box-shadow: 0 12px 32px rgba(0, 0, 0, .22);
496
+ }
497
+ .fx-pop__head { margin: 0; padding: 8px 10px 4px; color: var(--t-dim); font: var(--t-label-weight) var(--t-label-size)/1.3 var(--t-body); letter-spacing: var(--t-label-spacing); text-transform: var(--t-label-case); }
498
+ .fx-pop__item {
499
+ display: flex; align-items: center; gap: 8px; width: 100%; padding: 7px 10px; border: 0; border-radius: var(--t-radius);
500
+ background: none; color: var(--t-text); font: 500 13.5px/1.3 var(--t-body); text-align: left; cursor: pointer;
501
+ }
502
+ .fx-pop__item:hover, .fx-pop__item:focus-visible { background: var(--fx-hover); color: var(--t-strong); outline: none; }
503
+ .fx-pop__item[aria-checked="true"] { color: var(--t-strong); font-weight: 600; }
504
+ .fx-pop__tick { display: inline-grid; place-items: center; flex: none; width: 16px; height: 16px; color: var(--t-accent); }
505
+ .fx-pop__sep { height: 1px; margin: 6px 4px; background: var(--fx-line-soft); }
506
+ .fx-pop__foot { display: flex; justify-content: flex-end; padding: 6px 4px 2px; border-top: 1px solid var(--fx-line-soft); margin-top: 6px; }
507
+ .fx-table__group td { padding: 14px 16px 8px; background: var(--t-s1); }
508
+ .fx-table tbody tr.fx-table__group:hover td { background: var(--t-s1); }
509
+ .fx-table__group-row { display: flex; align-items: center; gap: 12px; }
510
+ .fx-table__group-row .fx-board__sum { margin-left: 0; }
511
+ .fx-stage[data-rank="plain"] { --stage: var(--t-dim); }
443
512
  /* The board never scrolls sideways: its columns (one per work system status)
444
513
  are about a phone wide, wrap onto more rows when the page is narrow, and
445
514
  stack on a phone. On a wide, tall screen the board fills the page down to
@@ -499,6 +568,22 @@ a.fx-strong:hover { text-decoration: underline; }
499
568
  .fx-job__problem:hover, .fx-job__problem:focus-visible { background: var(--t-warn-bg); }
500
569
  .fx-job__cell { display: inline-flex; align-items: center; gap: 6px; }
501
570
 
571
+ /* Moves on the board (jobs.js, enableDrag): the lifted card, the copy that
572
+ follows the pointer, the lane that takes it, and the "Waiting for
573
+ Seazona" chip of a stage move the work system has not made yet. */
574
+ .fx-job__wait { justify-self: start; margin-top: 8px; padding: 1px 8px; border: 1px dashed var(--t-accent); border-radius: 999px; color: var(--t-accent); font-size: 11.5px; font-weight: 600; }
575
+ .fx-job--lifted { opacity: .35; }
576
+ .fx-job--ghost { position: fixed; top: 0; left: 0; z-index: 60; pointer-events: none; box-shadow: var(--t-shadow-lg, var(--t-shadow)); cursor: grabbing; }
577
+ .fx-board--dragging, .fx-board--dragging .fx-job { cursor: grabbing; user-select: none; }
578
+ .fx-board__col--over { outline: 2px solid var(--t-accent); outline-offset: -2px; background: var(--t-accent-bg, var(--t-s1)); }
579
+ .fx-board__lane { font-weight: 600; }
580
+ .fx-board__lane .fx-stage__count { margin-left: 2px; }
581
+ /* The stage move dialog (jobs.js, moveStage). */
582
+ .fx-move__path { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; color: var(--t-dim); }
583
+ .fx-move__stage { padding: 2px 10px; border: 1px solid var(--fx-line); border-radius: 999px; color: var(--t-strong); font-size: 13px; font-weight: 600; }
584
+ .fx-move__note { margin: 0; color: var(--t-text); }
585
+ .fx-check { display: inline-flex; align-items: center; gap: 8px; color: var(--t-dim); font-size: 13.5px; cursor: pointer; }
586
+
502
587
  /* ── Job page ───────────────────────────────────────────────────────────────
503
588
  A job opened from the board: a large panel over it, like a task page, with
504
589
  the activity at the side. It stacks on a phone. */
@@ -523,6 +608,11 @@ a.fx-strong:hover { text-decoration: underline; }
523
608
  .fx-task__fix h3 { padding: 12px 14px 4px; color: var(--t-warn); }
524
609
  .fx-task__fixrow { padding: 9px 14px; border-top: 1px solid var(--fx-line-soft); color: var(--t-strong); font-size: 13.5px; }
525
610
  .fx-task__fixrow:first-of-type { border-top: 0; }
611
+ .fx-task__custom { margin-top: 24px; }
612
+ .fx-task__custom h3 { margin: 0 0 4px; color: var(--t-dim); font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
613
+ .fx-task__input { width: 100%; min-width: 0; }
614
+ .fx-task__move { display: grid; gap: 10px; max-width: 420px; margin-top: 8px; }
615
+ .fx-task__wait { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 10px 12px; border: 1px dashed var(--t-accent); border-radius: var(--t-radius); font-size: 13.5px; }
526
616
  .fx-task__lines { margin-top: 24px; }
527
617
  .fx-task__lines h3 { margin-bottom: 8px; }
528
618
  .fx-task__lines table { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: 13px; }
@@ -777,6 +867,69 @@ body[data-state="loading"] .fx-loading { display: grid; justify-items: center; }
777
867
  .fx-cf__line .fx-input, .fx-cf__line .fx-select { width: 100%; min-width: 0; }
778
868
  .fx-cf__color { border-left: 4px solid var(--cf); }
779
869
  @media (max-width: 560px) { .fx-cf__line { grid-template-columns: minmax(0, 1fr) 96px; } }
870
+ /* Custom fields manager (custom-fields.js), like ClickUp's Custom Field
871
+ Manager: a toolbar, then one table of type groups that fold. */
872
+ .fx-lucide { display: inline-block; flex: none; width: 16px; height: 16px; background: currentColor; -webkit-mask: var(--icon) center / contain no-repeat; mask: var(--icon) center / contain no-repeat; }
873
+ .fx-cfm__card { padding: 0; overflow: hidden; }
874
+ .fx-cfm__bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 12px 16px; border-bottom: 1px solid var(--fx-line-soft); }
875
+ .fx-cfm__search { width: 220px; min-width: 0; height: 32px; }
876
+ .fx-cfm__tool { min-height: 32px; }
877
+ .fx-cfm__tool--dashed { border-style: dashed; }
878
+ .fx-cfm__gap { flex: 1; }
879
+ .fx-cfm { display: grid; grid-template-columns: minmax(160px, 1fr) 64px 96px 120px minmax(90px, .6fr) 44px; }
880
+ .fx-cfm > [role="row"], .fx-cfm > .fx-notice, .fx-cfm > .fx-cfm__create, .fx-cfm > .fx-cfm__empty { grid-column: 1 / -1; }
881
+ .fx-cfm__head, .fx-cfm__row { display: grid; grid-template-columns: subgrid; align-items: center; }
882
+ .fx-cfm__head { height: 36px; padding: 0 8px 0 36px; color: var(--t-dim); font-size: 12.5px; border-bottom: 1px solid var(--fx-line-soft); }
883
+ .fx-cfm__sort { all: unset; cursor: pointer; display: inline-flex; gap: 4px; align-items: center; }
884
+ .fx-cfm__sort:focus-visible { box-shadow: var(--fx-focus); border-radius: 4px; }
885
+ .fx-cfm__sort .fx-lucide { width: 13px; height: 13px; }
886
+ .fx-cfm__group { display: flex; align-items: center; gap: 8px; height: 44px; margin-top: 12px; padding: 0 16px 0 8px; border-bottom: 1px solid var(--fx-line-soft); }
887
+ .fx-cfm__group:first-of-type { margin-top: 4px; }
888
+ .fx-cfm__fold { all: unset; cursor: pointer; display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: 6px; color: var(--t-dim); }
889
+ .fx-cfm__fold:hover { background: var(--fx-hover); color: var(--t-strong); }
890
+ .fx-cfm__fold:focus-visible { box-shadow: var(--fx-focus); }
891
+ .fx-cfm__fold .fx-lucide { width: 14px; height: 14px; transition: transform .15s var(--fx-ease); }
892
+ .fx-cfm__fold[aria-expanded="false"] .fx-lucide { transform: rotate(-90deg); }
893
+ .fx-cfm__pill { display: inline-flex; align-items: center; gap: 6px; padding: 3px 9px; border-radius: 6px; font-size: 12.5px; font-weight: 600; color: var(--cf); background: color-mix(in srgb, var(--cf) 14%, transparent); }
894
+ .fx-cfm__pill .fx-lucide { width: 14px; height: 14px; }
895
+ .fx-cfm__count { color: var(--t-dim); font-size: 12.5px; font-weight: 600; }
896
+ .fx-cfm__row { min-height: 36px; padding: 0 8px 0 36px; border-bottom: 1px solid var(--fx-line-soft); font-size: 14px; }
897
+ .fx-cfm__row:hover { background: var(--fx-hover); }
898
+ .fx-cfm__row[data-archived] .fx-cfm__label { color: var(--t-dim); }
899
+ .fx-cfm__name { display: flex; align-items: center; gap: 8px; min-width: 0; padding-right: 8px; color: var(--t-strong); }
900
+ .fx-cfm__name > .fx-lucide { width: 13px; height: 13px; color: var(--t-dim); }
901
+ .fx-cfm__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
902
+ .fx-cfm__edit { display: none; align-items: center; gap: 5px; flex: none; height: 24px; padding: 0 7px; border: 1px solid var(--fx-line); border-radius: 6px; background: var(--t-paper); color: var(--t-text); font: inherit; font-size: 12px; cursor: pointer; }
903
+ .fx-cfm__edit .fx-lucide { width: 13px; height: 13px; }
904
+ .fx-cfm__row:hover .fx-cfm__edit, .fx-cfm__edit:focus-visible { display: inline-flex; }
905
+ .fx-cfm__edit:focus-visible { box-shadow: var(--fx-focus); outline: none; }
906
+ .fx-cfm__rename { height: 28px; width: 100%; max-width: 320px; }
907
+ .fx-cfm__type { color: var(--cf); }
908
+ .fx-cfm__type .fx-lucide { width: 17px; height: 17px; }
909
+ .fx-cfm__avatar { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; background: var(--t-primary); color: var(--t-on-primary); font-size: 10.5px; font-weight: 700; letter-spacing: .02em; }
910
+ .fx-cfm__avatar .fx-lucide { width: 13px; height: 13px; }
911
+ .fx-cfm__date, .fx-cfm__where { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
912
+ .fx-cfm__row .fx-cfm__where { font-weight: 600; }
913
+ .fx-cfm__end { justify-self: end; }
914
+ .fx-cfm__more { all: unset; cursor: pointer; display: inline-grid; place-items: center; width: 30px; height: 28px; border-radius: 6px; color: var(--t-dim); }
915
+ .fx-cfm__more:hover, .fx-cfm__more[aria-expanded="true"] { background: var(--fx-hover); color: var(--t-strong); }
916
+ .fx-cfm__more:focus-visible { box-shadow: var(--fx-focus); }
917
+ .fx-cfm__create { all: unset; cursor: pointer; display: flex; align-items: center; gap: 6px; height: 36px; padding: 0 16px 0 36px; color: var(--t-dim); font-size: 13px; }
918
+ .fx-cfm__create:hover, .fx-cfm__create:focus-visible { color: var(--t-strong); background: var(--fx-hover); }
919
+ .fx-cfm__create .fx-lucide { width: 14px; height: 14px; }
920
+ .fx-cfm__empty { margin: 0; padding: 20px 16px; color: var(--t-dim); }
921
+ .fx-cfm > .fx-notice { margin: 12px 16px 0; }
922
+ .fx-cfm__foot { display: flex; justify-content: space-between; gap: 12px; padding: 12px 16px; border-top: 1px solid var(--fx-line-soft); color: var(--t-dim); font-size: 13px; }
923
+ .fx-pop__item:disabled { opacity: .5; cursor: default; }
924
+ .fx-pop__item .fx-lucide { width: 15px; height: 15px; }
925
+ @media (max-width: 720px) {
926
+ .fx-cfm { grid-template-columns: minmax(0, 1fr) 40px 40px; }
927
+ .fx-cfm .fx-cfm__by, .fx-cfm .fx-cfm__date, .fx-cfm .fx-cfm__where { display: none; }
928
+ .fx-cfm__head, .fx-cfm__row { padding-left: 16px; }
929
+ .fx-cfm__create { padding-left: 16px; }
930
+ .fx-cfm__search { flex: 1 1 100%; width: auto; }
931
+ .fx-cfm__edit { display: none !important; }
932
+ }
780
933
  /* Invoice rules (invoice-rules.js): a row's Edit button and switch, and the
781
934
  rule dialog's condition lines. */
782
935
  .fx-rule__controls { align-items: center; gap: 10px; }
@@ -21,6 +21,6 @@ export function sendModeNote(to, sendMode, what = 'each invoice') {
21
21
  // The line under a draft's title, one fact per sentence.
22
22
  export function draftNote(to, invoice, ready) {
23
23
  if (!to) return ready ? 'A person checked it. A saved change keeps it ready.' : 'Flow gives it a number when you issue it.';
24
- if (!ready) return `Mark it ready, then send it to ${to}.`;
24
+ if (!ready) return `Finalise it, then send it to ${to}.`;
25
25
  return sendModeNote(to, invoice?.sendMode, 'this invoice');
26
26
  }