/* Lowe's Invoice Reconciler. Visual reference: Lowes Rebate Validation
   (Geist here instead of Inter). Navy header, floating white card with a soft
   shadow, stepper strip, navy table headers, pinned action bar. The card floats
   whenever the viewport is larger than 1180x720, inside Acumatica too, and is
   full-bleed below that (swcorp.css). Fonts: static/fonts (OFL, Geist-OFL.txt). */

/* Fonts, colors, shape and motion: swcorp-tokens.css. Reset, window, header,
   side menu and pop-out: swcorp.css. Both load before this file (base.html). */

::selection { background: var(--navy-100); color: var(--ink); }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 4px; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: var(--focus); text-underline-offset: 2px; }
svg.i { width: 16px; height: 16px; flex: none; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* Identifiers (DM#, PO, SO, GL): same family as the rest, fixed-width digits. */
.mono { font-variant-numeric: tabular-nums; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
/* Accounting format: "$" pinned left, the figure right, negatives in (). */
.acct { display: flex; justify-content: space-between; align-items: baseline; gap: .5em; width: 100%; font-variant-numeric: tabular-nums; }
.acct > i { font-style: normal; color: var(--ink-3); font-weight: 400; }
.acct > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.muted { color: var(--ink-3); }
[hidden] { display: none !important; }

/* ---------------------------------------------------------------- stepper
   Beside the page title, on white. At rest: micro dots joined by short
   segments; done steps navy, upcoming grey, the run's position (when you are
   looking at another step) a navy ring, and the step you are on a navy pill
   with its name. Hover or keyboard focus opens a card with every step, its
   description and a link (rows stagger in 25ms; the card leaves faster). */
.titlebar { position: relative; z-index: 6; }
.steps { position: relative; margin-left: auto; align-self: flex-start; }
.steps-trigger { display: flex; align-items: center; gap: 12px; height: 34px; padding: 0 12px 0 14px; border-radius: 999px; border: 1.5px solid transparent; transition: border-color .2s ease, background-color .2s ease; }
.steps-now { font-size: 12px; font-weight: 700; color: var(--navy); white-space: nowrap; }
.steps-track { display: flex; align-items: center; }
.pip { display: block; flex: none; width: 8px; height: 8px; border-radius: 999px; background: #CED4DA; transition: width .3s var(--ease-settle), background-color .2s ease; }
.pip.done { background: var(--navy); }
.pip.current { background: var(--surface); box-shadow: inset 0 0 0 2px var(--navy); }
.pip.here { width: 22px; background: var(--navy); box-shadow: none; }
.seg { display: block; width: 14px; height: 2px; margin: 0 3px; border-radius: 2px; background: var(--line); }
.seg.on { background: var(--navy); }
.steps:hover .steps-trigger, .steps:focus-within .steps-trigger { border-color: var(--line); background: var(--surface-2); }
.steps-trigger:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(28,61,90,.25); }

/* Moving between steps is a page load; a cross-document view transition keeps
   the window and its header still (only the new snapshot is shown, so nothing
   blends or dims), slides the pill along the track from the old step to the
   new one, and swaps its name and the page body (sideways, the way the pill
   goes, when a step is picked in the card; a plain fade otherwise). Browsers
   without it just load the page. The pill's move is kept under reduced motion:
   it is small and it is what tells you where you went. */
@view-transition { navigation: auto; }
/* The header gets no view-transition-name: a named element is its own stacking
   context, and the menu button must stack above the side menu. It is the same
   on every page, so it simply stays put in the root snapshot. */
.content { view-transition-name: page; }   /* the page and its footer */
.steps-track .pip.here { view-transition-name: step-pill; }
.steps-now { view-transition-name: step-name; }
::view-transition-old(root) { display: none; }
::view-transition-group(root), ::view-transition-new(root),
::view-transition-group(page) { animation: none; }
::view-transition-old(page) { animation: vt-fade-out .09s ease-out both; }
::view-transition-new(page) { animation: vt-page-in .22s var(--ease-settle) .09s both; }
::view-transition-group(step-pill) { animation-duration: .38s; animation-timing-function: var(--ease-settle); }
::view-transition-group(step-name) { animation-duration: .3s; animation-timing-function: var(--ease-settle); }
::view-transition-old(step-name) { animation: vt-fade-out .12s ease-out both; }
::view-transition-new(step-name) { animation: vt-fade-in .24s var(--ease-settle) .1s both; }
/* From the steps card the name and the page slide sideways, the way the pill
   goes: forward (Inputs -> Process) leaves to the left and comes in from the
   right; back is the mirror. --vt-dx is the distance, signed by direction. */
html.step-fwd { --vt-dx: 1; }
html.step-back { --vt-dx: -1; }
html.step-fwd::view-transition-old(step-name), html.step-back::view-transition-old(step-name) { animation: vt-name-out .12s ease-out both; }
html.step-fwd::view-transition-new(step-name), html.step-back::view-transition-new(step-name) { animation: vt-name-in .26s var(--ease-settle) .1s both; }
html.step-fwd::view-transition-old(page), html.step-back::view-transition-old(page) { animation: vt-page-out .09s ease-out both; }
html.step-fwd::view-transition-new(page), html.step-back::view-transition-new(page) { animation: vt-page-side .24s var(--ease-settle) .09s both; }
@keyframes vt-name-out { to { opacity: 0; transform: translateX(calc(var(--vt-dx) * -10px)); } }
@keyframes vt-name-in { from { opacity: 0; transform: translateX(calc(var(--vt-dx) * 10px)); } }
@keyframes vt-page-out { to { opacity: 0; transform: translateX(calc(var(--vt-dx) * -12px)); } }
@keyframes vt-page-side { from { opacity: 0; transform: translateX(calc(var(--vt-dx) * 16px)); } }
@keyframes vt-fade-in { from { opacity: 0; } }
@keyframes vt-fade-out { to { opacity: 0; } }
@keyframes vt-page-in { from { opacity: 0; transform: translateY(4px); } }
@media (prefers-reduced-motion: reduce) {
  html.step-fwd::view-transition-new(page), html.step-back::view-transition-new(page),
  html.step-fwd::view-transition-new(step-name), html.step-back::view-transition-new(step-name), ::view-transition-new(page) { animation-name: vt-fade-in; }
  html.step-fwd::view-transition-old(page), html.step-back::view-transition-old(page),
  html.step-fwd::view-transition-old(step-name), html.step-back::view-transition-old(step-name) { animation-name: vt-fade-out; }
}

.steps-card { position: absolute; right: 0; top: calc(100% + 8px); width: 300px; margin: 0; padding: 6px; list-style: none; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-box);
  box-shadow: 0 12px 28px rgba(15,30,45,.14), 0 1px 3px rgba(21,46,69,.08); transform-origin: top right;
  opacity: 0; visibility: hidden; transform: translateY(-4px) scale(.98); transition: opacity .12s ease, transform .12s ease, visibility 0s linear .12s; }
/* Hover bridge over the 8px gap so the card stays open on the way down. */
.steps-card::before { content: ""; position: absolute; left: 0; right: 0; top: -10px; height: 10px; }
.steps:hover .steps-card, .steps:focus-within .steps-card { opacity: 1; visibility: visible; transform: none; transition: opacity .18s ease, transform .22s var(--ease-out), visibility 0s; }
.steps-card li { opacity: 0; transform: translateY(-3px); transition: opacity .12s ease, transform .12s ease; }
.steps:hover .steps-card li, .steps:focus-within .steps-card li { opacity: 1; transform: none; transition: opacity .18s ease, transform .22s var(--ease-out); }
.steps-card li:nth-child(2) { transition-delay: 25ms !important; } .steps-card li:nth-child(3) { transition-delay: 50ms !important; }
.steps-card li:nth-child(4) { transition-delay: 75ms !important; } .steps-card li:nth-child(5) { transition-delay: 100ms !important; }
.steps:not(:hover):not(:focus-within) .steps-card li { transition-delay: 0ms !important; }
/* A step was picked: the card goes at once (no fade), so it is not in the
   old page's snapshot, and on the page that opens it stays shut under the
   pointer until the pointer leaves the stepper (html.step-hush, base.html). */
.steps.picked .steps-card, html.step-hush .steps-card { opacity: 0 !important; visibility: hidden !important; transition: none !important; }
html.step-hush .steps:hover .steps-trigger { border-color: transparent; background: none; }
.steps-card a { display: grid; grid-template-columns: 30px 1fr; align-items: center; column-gap: 8px; padding: 8px 10px; border-radius: 6px; text-decoration: none; color: var(--ink); transition: background-color .12s ease; }
.steps-card a .pip { grid-row: span 2; justify-self: center; }
.steps-card .t { font-size: 13px; font-weight: 600; }
.steps-card .s { font-size: 12px; color: var(--ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.steps-card li.here a { background: var(--navy-50); }
.steps-card li.here .t { color: var(--navy); font-weight: 700; }
.steps-card li.todo a { pointer-events: none; }
.steps-card li.todo .t { color: var(--ink-3); }
.steps-card a:focus-visible { outline: 2px solid var(--navy); outline-offset: -2px; }
@media (hover: hover) and (pointer: fine) {
  .steps-card li:not(.todo):not(.here) a:hover { background: var(--surface-2); }
}
@media (prefers-reduced-motion: reduce) {
  .steps-card, .steps-card li, .pip { transform: none !important; transition-property: opacity, visibility, background-color !important; transition-delay: 0ms !important; }
}

/* ---------------------------------------------------------------- body */
.main { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; padding: 28px 32px 0; overflow: auto; }
@media (max-height: 820px) { .main { padding: 18px 24px 0; } }
.main.fixed { overflow: hidden; }
.titlebar { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.titlebar h2 { font-size: 20px; font-weight: 800; letter-spacing: -.01em; color: var(--navy); text-wrap: balance; }
.titlebar p { color: var(--ink-3); font-size: 13px; line-height: 1.65; margin-top: 4px; max-width: 80ch; text-wrap: pretty; }
.titlebar .right { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.section-title { font-size: 14px; font-weight: 700; color: var(--navy); margin: 20px 0 8px; }

.toolbar { display: flex; align-items: center; gap: 8px; margin: 14px 0 10px; flex-wrap: wrap; }
.tabs { display: flex; border: 1.5px solid var(--line); border-radius: var(--r-box); padding: 2px; background: var(--surface-2); }
.tab { padding: 5px 12px; border-radius: var(--r-ctl); font-size: 13px; color: var(--ink-2); display: flex; gap: 6px; align-items: center; border: 1px solid transparent; transition: background-color .15s ease, color .15s ease; }
.tab .c { font-variant-numeric: tabular-nums; color: var(--ink-3); }
.tab[aria-selected=true] { background: var(--surface); color: var(--navy); font-weight: 600; border-color: var(--line); box-shadow: 0 1px 2px rgba(21,46,69,.08); }
.tab[aria-selected=true] .c { color: var(--navy); }
.chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chip { display: flex; align-items: center; gap: 6px; padding: 5px 11px; border-radius: 999px; border: 1.5px solid var(--line); font-size: 12.5px; color: var(--ink-2); transition: background-color .15s ease, border-color .15s ease; }
.chip b { font-variant-numeric: tabular-nums; }
.chip[aria-pressed=true] { border-color: var(--navy); background: var(--navy-50); color: var(--navy); font-weight: 600; }
.chip.warn .i { color: var(--warn); }
.chip.block .i { color: var(--block); }
/* Build CM sits right of the search in Review's toolbar. */
.toolbar .build { flex: none; }
.search { margin-left: auto; display: flex; align-items: center; gap: 6px; border: 1.5px solid var(--line-strong); border-radius: var(--r-ctl); padding: 0 10px; height: 36px; width: 260px; color: var(--ink-3); background: var(--surface-2);
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease; }
.search input { border: 0; outline: 0; font-size: 13px; flex: 1; min-width: 0; color: var(--ink); background: none; }
.search input::placeholder { color: var(--ink-3); }
.search:focus-within { border-color: var(--navy); background: var(--surface); box-shadow: var(--ring); }
/* Tucked search: only its icon sits in the corner; it opens on hover or focus
   (a click or Tab lands in the field) and stays open while it has text. */
.search.tuck { width: 36px; padding: 0 10px; overflow: hidden; cursor: pointer; border-color: transparent; background: transparent; color: var(--ink-2);
  transition: width 280ms cubic-bezier(.23, 1, .32, 1), border-color .15s ease, background-color .15s ease, box-shadow .15s ease; }
.search.tuck .i { flex: none; }
.search.tuck input { opacity: 0; transition: opacity 140ms ease; cursor: pointer; }
.search.tuck:hover, .search.tuck:focus-within, .search.tuck.has-q { width: 260px; border-color: var(--line-strong); background: var(--surface-2); color: var(--ink-3); cursor: text; }
.search.tuck:hover input, .search.tuck:focus-within input, .search.tuck.has-q input { opacity: 1; transition-delay: 80ms; cursor: text; }
.search.tuck:focus-within { border-color: var(--navy); background: var(--surface); box-shadow: var(--ring); }
.search-x { flex: none; display: grid; place-items: center; width: 22px; height: 22px; margin-right: -4px; border-radius: 999px; color: var(--ink-3); cursor: pointer;
  transition: background-color .15s ease, color .15s ease; }
.search-x .i { width: 12px; height: 12px; }
.search-x:hover { background: var(--surface-3); color: var(--ink); }
/* Just cleared with the x: back to the icon even while the pointer is over it. */
.search.tuck.shut:hover { width: 36px; border-color: transparent; background: transparent; color: var(--ink-2); cursor: pointer; }
.search.tuck.shut:hover input { opacity: 0; transition-delay: 0s; }
@media (prefers-reduced-motion: reduce) { .search.tuck, .search.tuck input { transition: none; } }

/* ---------------------------------------------------------------- grids */
.grid-host { flex: 0 1 auto; min-height: 120px; display: flex; flex-direction: column; }
/* Never grows past the height fitHeight gives it, so it ends at its last row. */
.grid-host .tabulator { flex: 0 1 auto; min-height: 0; }
/* More rows past an edge: the rows at that edge fade into the table surface
   (under the header once scrolled, over the last rows while more are below). */
.grid-fade { position: absolute; left: 0; height: 44px; z-index: 3; pointer-events: none; opacity: 0;
  transition: opacity 200ms ease; }
.grid-fade.bottom { background: linear-gradient(to bottom, rgba(255,255,255,0), var(--surface) 92%); }
.grid-fade.top { height: 28px; background: linear-gradient(to top, rgba(255,255,255,0), var(--surface) 92%); }
.grid-fade.on { opacity: 1; }
.preview { flex: none; display: flex; gap: 10px; align-items: baseline; min-height: 34px; padding: 8px 12px; border: 1px solid var(--line); border-top: 0; border-radius: 0 0 10px 10px; font-size: 12.5px; color: var(--ink-2); background: var(--surface); }
.preview b { color: var(--ink); font-weight: 600; white-space: nowrap; }
.preview span { min-width: 0; overflow-wrap: anywhere; }

.tabulator { border: 1px solid var(--line); border-radius: var(--r-box) var(--r-box) 0 0; background: var(--surface); font-size: 13px; }
.tabulator.rounded { border-radius: var(--r-box); }
/* A grid with nothing under it (no preview line) rounds all four corners. */
.grid-host > .tabulator:last-child { border-radius: var(--r-box); }
.tabulator .tabulator-header { background: var(--navy); border-bottom: 0; color: rgba(255,255,255,.85); }
.tabulator .tabulator-header .tabulator-col { background: var(--navy); border-right: 0; transition: background-color .15s ease; }
.tabulator .tabulator-header .tabulator-col .tabulator-col-content { padding: 10px 12px; }
.tabulator .tabulator-header .tabulator-col .tabulator-col-title { font-size: 10px; font-weight: 700; letter-spacing: .045em; text-transform: uppercase; }
.tabulator .tabulator-header .tabulator-col .tabulator-col-sorter .tabulator-arrow { border-bottom-color: rgba(255,255,255,.45); border-top-color: rgba(255,255,255,.45); }
.tabulator .tabulator-header .tabulator-col[aria-sort=ascending] .tabulator-col-sorter .tabulator-arrow { border-bottom-color: #fff; }
.tabulator .tabulator-header .tabulator-col[aria-sort=descending] .tabulator-col-sorter .tabulator-arrow { border-top-color: #fff; }
.tabulator .tabulator-header .tabulator-col .tabulator-col-resize-handle:hover { background: rgba(255,255,255,.18); }
/* Headers: centred, wrap instead of cutting ("Payment Amount" never reads
   "PAYMENT AMO..."), and stay navy in every state (Tabulator's theme paints a
   hovered sortable header light grey, which made the white title unreadable).
   The title keeps equal room both sides of the sort arrow so it stays centred. */
.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title { white-space: normal; overflow-wrap: normal; text-overflow: clip; padding: 0 12px; line-height: 1.3; }
.tabulator .tabulator-header .tabulator-col { justify-content: center; }
.tabulator .tabulator-header .tabulator-col,
.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover,
.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending],
.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] { background: var(--navy); color: rgba(255,255,255,.85); }
/* Read-only grids (rows not selectable): one quieter text colour, no pointer,
   and only a light tint under the mouse to follow the line. */
.tabulator-row:not(.tabulator-selectable) .tabulator-cell,
.tabulator-row:not(.tabulator-selectable) .tabulator-cell.mono { color: var(--ink-2); cursor: default; }
@media (hover: hover) {
  .tabulator-tableholder .tabulator-row:not(.tabulator-selectable):hover { background: var(--surface-2); }
}
.tabulator .tabulator-tableholder .tabulator-table { background: var(--surface); }
.tabulator-row { min-height: var(--row); border-bottom: 1px solid var(--line-soft); background: var(--surface); }
.tabulator-row.tabulator-row-even { background: var(--surface); }
.tabulator-row .tabulator-cell { padding: 9px 12px; border-right: 0; font-variant-numeric: tabular-nums; color: var(--ink-2); }
.tabulator-row .tabulator-cell.mono { color: var(--ink); }
.tabulator-row.state-needs_gl, .tabulator-row.state-warn { background: var(--warn-bg); }
.tabulator-row.state-blocking { background: var(--block-bg); }
.tabulator-row.state-excluded .tabulator-cell { color: var(--ink-3); }
.tabulator-row.tabulator-selected { background: var(--navy-50) !important; }
.tabulator-row .tabulator-cell.tabulator-editing:not(.ed) { border: 1.5px solid var(--navy); padding: 6px 10px; }
.tabulator-row .tabulator-cell.tabulator-editing input { font-size: 13px; }
/* Editable cells read like Setup's quiet edit tables: plain text at rest, a
   field box on row hover, the focus ring on the one cell being edited. The box is a
   pseudo-element so text, row height and the editor's position never shift. */
.tabulator-row .tabulator-cell.ed { isolation: isolate; overflow: visible; }
/* Editable cells stay overflow: visible (their box is drawn a few px out), so
   their text is cut here instead, or a long SubAccount runs over CR. */
.tabulator-row .tabulator-cell.ed .cell-t { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.tabulator-row .tabulator-cell.ed::before { content: ""; position: absolute; inset: 3px 4px; z-index: -1; pointer-events: none;
  border: 1px solid transparent; border-radius: 5px; background: transparent; transition: border-color 120ms ease, background-color 120ms ease, box-shadow 120ms ease; }
.tabulator .tabulator-row .tabulator-cell.ed.tabulator-editing { padding: 9px 12px; border: 0; outline: none; }
.tabulator .tabulator-row .tabulator-cell.ed.tabulator-editing::before { border-color: var(--navy); background: var(--surface); box-shadow: var(--ring); }
.tabulator .tabulator-row .tabulator-cell.ed.tabulator-editing input { padding: 0 !important; border: 0; outline: none; background: transparent; font: inherit; color: var(--ink); }
.tabulator .tabulator-row .tabulator-cell.ed.tabulator-editing[tabulator-field="ext_cost"] input { text-align: right; -moz-appearance: textfield; }
.tabulator-cell.ed input::-webkit-inner-spin-button, .tabulator-cell.ed input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
/* No frame on the row while a cell is edited with the mouse; keyboard focus
   still gets one (inset, so the scrollbar does not cut it). */
.tabulator-row:has(:focus-visible) { box-shadow: inset 0 0 0 2px var(--focus); }
.tabulator .tabulator-footer { background: var(--surface-2); border-top: 1px solid var(--line); font-weight: 600; color: var(--ink-2); }
.tabulator .tabulator-footer .tabulator-calcs-holder { background: var(--surface-2); border: 0; }
.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row { background: var(--surface-2); }
/* The totals row takes the columns' classes; its cells are sums, not fields,
   so no edit box on them. */
.tabulator .tabulator-calcs .tabulator-cell.ed::before { display: none; }
.tabulator .tabulator-calcs .tabulator-cell { cursor: default; }
/* Empty or no-match message: quiet body text, not Tabulator's 20px bold grey. */
.tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents { color: var(--ink-3); font-weight: 400; font-size: 13px; }
/* Rebate's thin scrollbar: grey thumb inset by a white border. */
.tabulator .tabulator-tableholder { scrollbar-width: thin; scrollbar-color: #CED4DA transparent; }
.tabulator .tabulator-tableholder::-webkit-scrollbar { width: 10px; height: 10px; }
.tabulator .tabulator-tableholder::-webkit-scrollbar-thumb { background: #CED4DA; border: 2px solid #fff; border-radius: 8px; }
.tabulator .tabulator-tableholder::-webkit-scrollbar-thumb:hover { background: #ADB5BD; }
/* Loading: skeleton bars instead of a spinner (Tabulator's dataLoader). */
.tabulator .tabulator-alert { background: rgba(255,255,255,.72); }
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg { border: 0; background: none; padding: 0; }
.skel { display: grid; gap: 10px; width: min(520px, 70vw); }
.skel i { display: block; height: 12px; border-radius: 6px; background: linear-gradient(90deg, var(--surface-3) 0%, #E9ECEF 40%, var(--surface-3) 80%); background-size: 200% 100%; animation: skel 1.2s linear infinite; }
.skel i:nth-child(2) { width: 86%; } .skel i:nth-child(3) { width: 64%; }
@keyframes skel { to { background-position: -200% 0; } }
.tabulator .tabulator-tableholder { transition: none; }
@media (hover: hover) and (pointer: fine) {
  .tabulator-row.tabulator-selectable:hover { background: var(--surface-2); }
  .tabulator-row.state-needs_gl:hover { background: var(--warn-bg-h); }
  .tabulator-row:hover .tabulator-cell.ed::before { border-color: var(--line-strong); background: var(--surface); }
}

.st { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; transition: opacity 120ms ease; }
.st .i { width: 14px; height: 14px; }
.st.ok { color: var(--ok); } .st.warn { color: var(--warn); } .st.block { color: var(--block); } .st.off { color: var(--ink-3); }
/* Status badge: soft tinted capsule with its icon, for read-only status cells. */
/* Fits in the text line (18px with its border), so a badge cell is no taller
   than a text cell and every cell in the row stays vertically centred. */
.badge { display: inline-flex; align-items: center; gap: 5px; padding: 0 9px 0 6px; margin: -1px 0; border-radius: 999px; font-size: 12px; font-weight: 600; line-height: 18px; white-space: nowrap; border: 1px solid transparent; vertical-align: middle; }
.badge .i { width: 13px; height: 13px; }
.badge.ok { background: var(--ok-bg); color: var(--ok); border-color: var(--ok-line); }
.badge.warn { background: var(--warn-bg); color: var(--warn); border-color: #E9C46A; }
.badge.block { background: var(--block-bg); color: var(--block); border-color: var(--block-line); }
.badge.off { background: var(--surface-2); color: var(--ink-3); border-color: var(--line); }
.pill { display: inline-block; padding: 1px 7px; border-radius: 4px; font-size: 12px; background: var(--surface-2); border: 1px solid var(--line); color: var(--ink-2); }
/* Include checkbox after Motion's Base UI example: a rounded box that fills
   navy while the tick draws along its path; unchecking retracts the tick as
   the fill fades. A press squeezes the box a little. */
.cbx { position: relative; display: inline-grid; width: 18px; height: 18px; vertical-align: middle; }
.cbx input { appearance: none; -webkit-appearance: none; margin: 0; width: 18px; height: 18px; border: 1.5px solid var(--line-strong); border-radius: 5px; background: var(--surface); cursor: pointer;
  transition: background-color 180ms var(--ease-out), border-color 180ms var(--ease-out), transform 120ms var(--ease-out); }
.cbx input:checked { background: var(--navy); border-color: var(--navy); }
.cbx input:active { transform: scale(.88); }
.cbx input:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.cbx svg { position: absolute; inset: 0; width: 18px; height: 18px; pointer-events: none; fill: none; stroke: #fff; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 13; stroke-dashoffset: 13; transition: stroke-dashoffset 160ms var(--ease-out); }
.cbx input:checked + svg { stroke-dashoffset: 0; transition: stroke-dashoffset 220ms var(--ease-out) 40ms; }
@media (hover: hover) { .cbx input:not(:checked):hover { border-color: var(--navy); } }
/* Review's Duplicate SO section: one group per SO Order Nbr., its header
   with the macro's palette swatch, its lines tinted with the same colour. */
.tabulator .tabulator-row.tabulator-group { min-height: 34px; padding: 0 12px; display: flex; align-items: center; gap: 10px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--surface-2); font-weight: 600; color: var(--ink); }
.tabulator .tabulator-row.tabulator-group span { margin-left: 0; color: inherit; }
.tabulator .tabulator-row.tabulator-group .tabulator-group-toggle { display: none; }
.dup-sw { flex: none; width: 12px; height: 12px; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.08); }
.dup-so { font-variant-numeric: tabular-nums; }
.tabulator .tabulator-row.tabulator-group .dup-n { font-weight: 500; color: var(--ink-3); }
.tabulator-row.dup-row { background: color-mix(in srgb, var(--dup) 35%, var(--surface)); }
.tabulator-row.dup-row .tabulator-cell.tabulator-frozen { background: inherit; }
/* The arrow beside an order number that opens it in Acumatica. */
.link-box { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; margin-left: 6px; vertical-align: middle; border: 1px solid var(--line); border-radius: 4px; color: var(--ink-3); background: var(--surface); text-decoration: none;
  transition: color 120ms ease, border-color 120ms ease, background-color 120ms ease; }
.link-box:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
@media (hover: hover) { .link-box:hover { color: var(--navy); border-color: var(--navy); background: var(--navy-50); } }
.edited-dot { display: inline-block; width: 6px; height: 6px; margin-left: 6px; border-radius: 50%; background: var(--navy); vertical-align: middle; }
.edited-mark { display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 4px; font: 600 10px/1.6 var(--font); letter-spacing: .04em; text-transform: uppercase; background: var(--navy-50); color: var(--navy); }
.gl-empty { color: var(--warn); font-weight: 600; font-size: 12px; border-bottom: 1px dashed var(--warn); }
.hint { font-size: 12px; color: var(--ink-3); }

/* ---------------------------------------------------------------- panels */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 14px; margin-top: 16px; }
.tile { border: 1.5px solid var(--line); border-radius: var(--r-box); padding: 18px 20px; background: var(--surface); display: flex; flex-direction: column; gap: 10px; }
.tile h3 { font-size: 14px; font-weight: 700; color: var(--navy); display: flex; align-items: center; gap: 8px; }
.tile .meta { font-size: 12.5px; color: var(--ink-2); }
.tile.ok { border-color: var(--navy); }
.drop { position: relative; display: block; border: 1.5px solid var(--line); border-radius: var(--r-box); padding: 20px; text-align: center; color: var(--ink-2); font-size: 13px; transition: background-color .15s ease, border-color .15s ease; }
.drop input[type=file] { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; }
.drop.over { border-color: var(--navy); background: var(--surface-2); box-shadow: 0 0 0 4px rgba(28,61,90,.08); }
.drop:has(input:focus-visible) { border-color: var(--navy); box-shadow: 0 0 0 3px rgba(28,61,90,.25); }
.drop b { color: var(--navy); }
.drop .i { width: 22px; height: 22px; color: var(--navy); margin: 0 auto 6px; display: block; }
/* Inputs intake (layout of Rebate Validation's upload screen): one drop zone that
   takes the free height, the pills it sorts files into in a row underneath.
   Motion is feedback only: the zone answers the drag, the pill that receives the
   file spins while it is read, then fills navy and draws its check. */
#inputs-panel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.intake { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: 20px; margin-top: 20px; }

.zone { position: relative; flex: 1 1 auto; display: grid; place-items: center; min-height: 150px; padding: 32px 24px 28px; border: 1.5px solid var(--line); border-radius: 10px; background: var(--surface); text-align: center; color: var(--ink-2);
  transition: border-color .2s ease, background-color .2s ease, box-shadow .2s ease; }
.zone input[type=file] { position: absolute; inset: 0; z-index: 2; width: 100%; opacity: 0; cursor: pointer; }
.zone input[type=file]:disabled { cursor: progress; }
.zone-face { grid-area: 1 / 1; display: flex; flex-direction: column; align-items: center; gap: 6px; transition: opacity 180ms ease, transform 220ms var(--ease-out), filter 180ms ease; }
.zone-icon { width: 48px; height: 48px; margin-bottom: 8px; fill: none; stroke: var(--navy); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; transition: transform .2s ease, stroke .2s ease; }
.zone-prompt { font-size: 14px; color: var(--ink); }
.zone-prompt b { color: var(--navy); font-weight: 600; }
.zone-hint { font-size: 12px; color: var(--ink-3); max-width: 80ch; }
.zone.over { border-color: var(--navy); background: var(--navy-50); box-shadow: 0 0 0 4px rgba(28,61,90,.08); }
.zone.over .zone-icon { transform: translateY(-3px); }
.zone:has(input:focus-visible) { border-color: var(--focus); box-shadow: 0 0 0 3px rgba(47,111,176,.25); }
/* While a file is checked and read the zone stays as it is (only the pills
   show the loader); it just stops taking clicks. */
.zone[data-state=busy] input[type=file] { cursor: progress; }
.zone.shake { animation: nudge 320ms var(--ease-out); }
@keyframes nudge { 20% { transform: translateX(-4px); } 45% { transform: translateX(3px); } 70% { transform: translateX(-2px); } }
/* RTM Files: Inputs' zone over Rebate's bottom bar. The zone takes the free
   height (never under 150px); under it a navy badge (one Inputs pill tall,
   as wide as the zone; Rebate's contract badge) sums up the remit. While htmx
   sends a batch the zone stops taking files and the badge ring spins. */
#rtm-panel { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; --dm-bar: 70px; }
.rtm-intake { flex: 1 0 150px; display: flex; flex-direction: column; margin-top: 20px; }
.rtm-intake.htmx-request input[type=file] { pointer-events: none; cursor: progress; }
#rtm-panel .notice { flex: none; }
.dm-bar { flex: none; display: flex; margin-top: 20px; }
.dm-wrap { flex: 1 1 auto; min-width: 0; border-radius: 10px; }
.dm-wrap:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(28,61,90,.25); }
/* Empty (Inputs' idle pill: white, grey outline and ring) until every debit
   memo has its file; then navy with its check. While a batch loads the ring
   spins either way. The thin bar at its foot is how far the remit is. */
.dm-badge { position: relative; display: flex; align-items: center; gap: 12px; height: var(--dm-bar); padding: 0 16px; border: 1.5px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--ink-3);
  transition: background-color 240ms var(--ease-out), border-color 240ms var(--ease-out), color 240ms ease; }
.dm-wrap.all .dm-badge { border-color: var(--navy); background: var(--navy); color: #fff; }
/* Bridges the gap to the bubbles so moving up does not close them. */
.dm-badge::before { content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 12px; }
.dm-badge-check { position: relative; flex: none; width: 24px; height: 24px; border-radius: 50%; border: 2px solid #CED4DA; transition: background-color 240ms var(--ease-out), border-color 240ms var(--ease-out); }
.dm-badge-check .tick { position: absolute; inset: -2px; width: 24px; height: 24px; fill: none; stroke: var(--navy); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 16; stroke-dashoffset: 16; transition: stroke-dashoffset 280ms var(--ease-out) 90ms; }
.dm-wrap.all .dm-badge-check { border-color: #fff; background: #fff; }
.dm-wrap.all .dm-badge-check .tick { stroke-dashoffset: 0; }
#rtm-panel:has(.rtm-intake.htmx-request) .dm-badge-check { border-color: #CED4DA; border-top-color: var(--navy); background: none; animation: spin .75s linear infinite; }
#rtm-panel:has(.rtm-intake.htmx-request) .dm-wrap.all .dm-badge-check { border-color: rgba(255,255,255,.3); border-top-color: #fff; }
#rtm-panel:has(.rtm-intake.htmx-request) .dm-badge-check svg { opacity: 0; }
.dm-badge-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.dm-wrap.all .dm-badge-sub { color: rgba(255,255,255,.72); }
.dm-badge-count { flex: none; font-size: 13px; font-weight: 600; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.dm-badge-count i { font-style: normal; font-weight: 500; color: var(--ink-3); }
.dm-wrap.all .dm-badge-count, .dm-wrap.all .dm-badge-count i { color: #fff; }
/* Progress is the ring: a navy arc over the grey ring, clockwise from the
   top, as far as the remit is loaded, drawn on from where it stood before the
   batch (hidden while the ring spins). Complete, the arc closes, then the
   badge fills navy and the tick draws (only when this batch completed it). */
/* The ring is two CSS borders, not SVG: the grey one of the ring itself and
   a navy one over it, cut by a conic mask to --pv of the turn. An SVG stroke
   (or a radial-gradient band) over a CSS border rasterises softer than the
   bubbles' border rings; two borders match them pixel for pixel (measured in
   Playwright). --pv is registered so it can animate from where the remit
   stood before the batch (--p0) to now (--p). */
@property --pv { syntax: "<number>"; inherits: false; initial-value: 0; }
.dm-badge-check::before { content: ""; position: absolute; inset: -2px; border-radius: 50%; border: 2px solid var(--navy);
  -webkit-mask: conic-gradient(#000 calc(var(--pv) * 1turn), transparent 0); mask: conic-gradient(#000 calc(var(--pv) * 1turn), transparent 0);
  --pv: var(--p); animation: dm-arc 520ms var(--ease-out) both; }
@keyframes dm-arc { from { --pv: var(--p0); } to { --pv: var(--p); } }
.dm-wrap.all .dm-badge-check::before { display: none; }
.dm-wrap.filled .dm-badge-check::before { display: block; animation: dm-arc 520ms var(--ease-out) both, dm-arc-out 0s 520ms forwards; }
@keyframes dm-arc-out { to { visibility: hidden; } }
#rtm-panel:has(.rtm-intake.htmx-request) .dm-badge-check::before { display: none; }
.dm-wrap.filled .dm-badge { animation: dm-fill 280ms var(--ease-out) 480ms backwards; }
.dm-wrap.filled .dm-badge-check { animation: dm-fill-ring 280ms var(--ease-out) 480ms backwards; }
.dm-wrap.filled .dm-badge-check .tick { transition: none; animation: dm-check 360ms var(--ease-out) 620ms backwards; }
@keyframes dm-fill { from { background: var(--surface); border-color: var(--line); color: var(--ink-3); } }
@keyframes dm-fill-ring { from { background: transparent; border-color: #CED4DA; } }
.dm-badge-title { font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dm-badge-sub { font-size: 11px; font-weight: 500; color: var(--ink-3); line-height: 1.2; font-variant-numeric: tabular-nums; }
/* Rebate's file bubbles, one per debit memo, over the zone above the badge:
   four per row, filled left to right, sitting on the badge (they scroll if a
   remit has more than fit). Each li is
   the hit area (its padding is the gap) so the pointer never falls between
   bubbles; the card inside is what shows. */
/* Scrolls only while open (hidden cards sit 10px low, which would count as
   overflow); the padding, taken back by the offsets, is room for the pop's
   overshoot so it never flashes a scrollbar. */
.dm-bubbles { position: absolute; left: -4px; right: -16px; top: 20px; bottom: calc(var(--dm-bar) - 4px); z-index: 5; list-style: none; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-content: safe end; padding: 0 12px 12px 0; overflow: hidden; pointer-events: none; }
.dm-wrap:hover .dm-bubbles, .dm-wrap:focus-within .dm-bubbles { overflow-y: auto; }
/* Motion: every card rises from the badge (origin bottom centre, a small
   lift and 0.96 scale, never a shrunken card), in a diagonal wave: the row
   nearest the badge first, left to right within a row (--r rows from the
   badge, --c column), capped so a big remit is not slow. The exit is faster
   and all at once: a short drop and fade. Transitions, so a hover that
   leaves mid-way reverses from where it is. */
.dm-bubble { min-width: 0; padding: 4px; visibility: hidden; transition: visibility 0s 120ms; }
.dm-card { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border: 1.5px solid var(--line); border-radius: 10px; background: var(--surface); box-shadow: 0 6px 16px rgba(0,0,0,.1);
  opacity: 0; transform: translateY(6px) scale(.96); transform-origin: 50% 100%; transition: opacity 120ms var(--ease-out), transform 120ms var(--ease-out); }
.dm-wrap:hover .dm-bubble, .dm-wrap:focus-within .dm-bubble { visibility: visible; pointer-events: auto; transition: visibility 0s; }
.dm-wrap:hover .dm-card, .dm-wrap:focus-within .dm-card { opacity: 1; transform: none;
  transition: opacity 180ms ease-out, transform 300ms var(--ease-out); transition-delay: calc(min(var(--r), 6) * 50ms + var(--c) * 25ms); }
.dm-ring { position: relative; flex: none; width: 22px; height: 22px; border-radius: 50%; border: 2px solid #CED4DA; }
.dm-ring svg { position: absolute; inset: -2px; width: 22px; height: 22px; fill: none; stroke: #fff; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 16; stroke-dashoffset: 16; }
.dm-ring svg.x { stroke: var(--block); stroke-dasharray: 20; stroke-dashoffset: 20; }
.dm-bubble-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.dm-bubble-top { font-size: 9px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); line-height: 1.2; }
.dm-bubble-name { font-size: 11px; font-weight: 600; color: #ADB5BD; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dm-bubble-amt { flex: none; font-size: 11px; font-weight: 600; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.dm-bubble.done .dm-ring { border-color: var(--navy); background: var(--navy); }
.dm-bubble.done .dm-ring svg:not(.x) { stroke-dashoffset: 0; }
.dm-bubble.done .dm-bubble-top { color: var(--navy); }
.dm-bubble.done .dm-bubble-name { color: var(--ink-2); }
.dm-bubble.done .dm-bubble-amt { color: var(--ink); }
.dm-bubble.warn .dm-ring { border-color: var(--amber-stroke); background: var(--amber-stroke); }
.dm-bubble.warn .dm-bubble-name { color: #7A5A12; }
.dm-bubble.failed .dm-card { border-color: var(--block-line); }
.dm-bubble.failed .dm-ring { border-color: var(--block); background: #fff; }
.dm-bubble.failed .dm-ring svg.x { stroke-dashoffset: 0; }
.dm-bubble.failed .dm-bubble-name { color: var(--block); }
/* A batch on its way: the bubbles still waiting spin. */
#rtm-panel:has(.rtm-intake.htmx-request) .dm-bubble:not(.done) .dm-ring { border-color: #CED4DA; border-top-color: var(--navy); background: none; animation: spin .75s linear infinite; }
/* Loaded by this batch: the check draws (seen if the badge is hovered as it lands). */
.dm-bubble.just .dm-ring svg:not(.x) { animation: dm-check 360ms var(--ease-out) calc(min(var(--r), 6) * 50ms + var(--c) * 25ms + 200ms) backwards; }
@keyframes dm-check { from { stroke-dashoffset: 16; } }
/* No reduced-motion override: Rebate pops its bubbles regardless. */

.slots { list-style: none; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; flex: none; }
.slot { display: flex; align-items: center; gap: 12px; min-width: 0; min-height: 70px; padding: 13px 16px; border: 1.5px solid var(--line); border-radius: 10px; background: var(--surface);
  transition: background-color 300ms var(--ease-out), border-color 300ms var(--ease-out), transform 300ms var(--ease-out); }
.slot-mark { position: relative; flex: none; width: 24px; height: 24px; border-radius: 50%; border: 2px solid #CED4DA; transition: background-color 240ms var(--ease-out), border-color 240ms var(--ease-out); }
.slot-mark svg { position: absolute; inset: -2px; width: 24px; height: 24px; fill: none; stroke: var(--navy); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 16; stroke-dashoffset: 16; transition: stroke-dashoffset 280ms var(--ease-out) 90ms; }
.slot-text { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 3px; }
.slot-top { font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); line-height: 1.2; transition: color 240ms ease; }
.slot-main { font-size: 11px; font-weight: 500; color: var(--ink-3); line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: color 240ms ease; }
@keyframes swap-in { from { opacity: 0; transform: translateY(3px); filter: blur(2px); } }
.slot-flag { position: relative; z-index: 1; flex: none; padding: 3px 9px; border-radius: 999px; font-size: 12px; font-weight: 600; background: var(--warn-bg); color: #5E3F00; white-space: nowrap;
  transition: background-color 150ms ease, transform 160ms var(--ease-out); }
.slot-flag::after { content: " · Fix"; text-decoration: underline; text-underline-offset: 2px; }
.slot-flag:active { transform: scale(.96); }
.slot-flag:focus-visible { outline-color: #fff; }

.slot.loading .slot-mark { border-top-color: var(--navy); animation: spin .75s linear infinite; }
.slot.done { border-color: var(--navy); background: var(--navy); }
.slot.done .slot-mark { border-color: #fff; background: #fff; }
.slot.done .slot-mark svg:not(.x) { stroke-dashoffset: 0; }
.slot.done .slot-top { color: #fff; }
.slot.done .slot-main { color: rgba(255,255,255,.72); }
.slot.shake { animation: nudge 320ms var(--ease-out); }
/* Acumatica pill failed: the ring turns red with an x where the check goes. */
.slot-mark svg.x { stroke: var(--block); stroke-dasharray: 20; stroke-dashoffset: 20; }
.slot.failed { border-color: var(--block-line); background: var(--block-bg); }
.slot.failed .slot-mark { border-color: var(--block); background: #fff; }
.slot.failed .slot-mark svg.x { stroke-dashoffset: 0; }
.slot.failed .slot-main { color: var(--block); }
.slot-retry { flex: none; padding: 3px 11px; border-radius: 999px; font-size: 12px; font-weight: 600; background: #fff; color: var(--block); border: 1.5px solid var(--block-line);
  transition: background-color 150ms ease, transform 160ms var(--ease-out); }
.slot-retry:active { transform: scale(.96); }
@media (hover: hover) { .slot-retry:hover { background: var(--block-bg); } }
/* × only on a filled slot, and only while the pointer is over it (or it has
   keyboard focus). Seen tens of times a day, so a quick fade, no delay. */
.slot-x { flex: none; display: grid; place-items: center; width: 26px; height: 26px; margin: -4px -6px -4px 0; border-radius: 50%; color: rgba(255,255,255,.62);
  opacity: 0; transform: scale(.9); visibility: hidden;
  transition: opacity 120ms ease-out, transform 120ms var(--ease-out), background-color 150ms ease, color 150ms ease; }
.slot-x svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.slot-x:focus-visible { outline-color: #fff; }
.slot.done .slot-x { visibility: visible; }
.slot.done .slot-x:focus-visible { opacity: 1; transform: none; }
.slot.done .slot-x:active { transform: scale(.9); }
@media (hover: none) { .slot.done .slot-x { opacity: 1; transform: none; } }
.zone[data-state=full] input[type=file] { cursor: default; }
/* Short windows (laptop, Acumatica iframe): smaller icon, tighter pills. */
@media (max-height: 720px) {
  .intake { margin-top: 12px; gap: 10px; }
  .zone { min-height: 120px; padding: 16px; }
  .zone-icon { width: 36px; height: 36px; margin-bottom: 2px; }
  .slot { padding: 10px 12px; }
}

/* DM# correction dialog: a centred modal (scales from its centre, not a trigger). */
.fix-dialog { margin: auto; width: min(1080px, calc(100% - 48px)); max-height: calc(100dvh - 48px); padding: 0; border: 0; border-radius: 14px; background: var(--surface); color: var(--ink);
  box-shadow: 0 20px 50px rgba(21,46,69,.25), 0 2px 6px rgba(21,46,69,.08); }
.fix-dialog[open] { display: flex; flex-direction: column; animation: dlg-in 280ms var(--ease-overshoot); }
.fix-dialog::backdrop { background: rgba(21,46,69,.32); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); animation: fade-in 200ms ease-out; }
.fix-dialog.closing { animation: dlg-out 140ms ease-out forwards; }
.fix-dialog.closing::backdrop { animation: fade-out 140ms ease-out forwards; }
@keyframes dlg-in { from { opacity: 0; transform: translateY(8px) scale(.95); } }
@keyframes dlg-out { to { opacity: 0; transform: scale(.98); } }
@keyframes fade-in { from { opacity: 0; } }
@keyframes fade-out { to { opacity: 0; } }
.fix-head { display: flex; align-items: flex-start; gap: 16px; padding: 18px 20px 14px; }
.fix-head h3 { font-size: 16px; font-weight: 700; }
.fix-head p { font-size: 13px; color: var(--ink-2); margin-top: 3px; max-width: 90ch; }
.fix-close { flex: none; display: grid; place-items: center; width: 30px; height: 30px; margin: -4px -6px 0 auto; border-radius: 50%; color: var(--ink-2); transition: background-color 150ms ease, transform 160ms var(--ease-out); }
.fix-close svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.fix-close:active { transform: scale(.92); }
.fix-grid { padding: 0 20px; }
.fix-grid .tabulator { border-radius: 10px; }
.fix-foot { display: flex; align-items: center; gap: 12px; padding: 14px 20px; margin-top: 14px; border-top: 1px solid var(--line); }
.fix-foot .msg { font-size: 13px; color: var(--warn); font-weight: 600; }
.fix-foot .msg.ok { color: var(--ok); }
.fix-foot .grow { flex: 1; }
@media (hover: hover) and (pointer: fine) {
  .zone:not([data-state=busy]):not([data-state=full]):hover { border-color: var(--navy); background: var(--surface-2); }
  .slot.done:hover .slot-x { opacity: 1; transform: none; }
  .slot.done .slot-x:hover { background: rgba(255,255,255,.15); color: #fff; }
  .slot-flag:hover { background: #FBE3A6; }
  .fix-close:hover { background: var(--surface-2); color: var(--ink); }
  .zone:not([data-state=busy]):not([data-state=full]):hover .zone-icon { transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) {
  .zone, .zone-face, .zone-icon, .slot, .slot-mark svg, .slot-x { transition-property: opacity, background-color, border-color, color; }
  .zone[data-state=busy], .zone.shake, .slot.shake { animation: none; }
  .zone-face, .zone.over .zone-icon { transform: none; filter: none; }
  .slot-mark svg { transition: none; }
  .fix-dialog[open], .fix-dialog.closing { animation-name: fade-in; }
  .fix-dialog.closing { animation-name: fade-out; }
}

/* Process: three totals centred in the step; picking one moves them up into a
   compact row above its lines. */
.proc { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; justify-content: center; }
.proc.open { justify-content: flex-start; }
.sums-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sums { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; flex: 1 1 auto; }
.sum { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 220px; padding: 18px 22px; text-align: left;
  border: 1.5px solid var(--line); border-radius: 16px; background: var(--surface); color: var(--ink-2);
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease; }
.sum:hover { border-color: var(--line-strong); box-shadow: var(--shadow-pop); }
.sum-l { font-size: 12px; font-weight: 600; color: var(--ink-3); }
.sum-v { align-self: stretch; font: 600 24px/1.2 var(--font); letter-spacing: -.01em; color: var(--ink); font-variant-numeric: tabular-nums; }
/* Odometer roll of the totals on arrival: one-line window per digit. */
.roll { display: inline-block; height: 1.2em; line-height: 1.2em; overflow: hidden; vertical-align: top; }
.roll-strip { display: block; will-change: transform; }
.roll-strip > i { display: block; height: 1.2em; font-style: normal; }
.sum-n { display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.sum-w { display: inline-flex; align-items: center; gap: 5px; font-weight: 600; color: var(--warn); }
.sum.warn { border-color: #E9C46A; }
/* Open: the totals shrink to one line each and sit left of the search. */
.proc { position: relative; }
/* At the foot of the view, apart from the totals: the next step's name over
   the bar that counts down to it. */
.advance { position: absolute; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.advance b { font-size: 12.5px; font-weight: 600; color: var(--navy); }
.advance-bar { display: block; width: 140px; height: 3px; border-radius: 999px; background: var(--line); overflow: hidden; }
.advance-bar > i { display: block; height: 100%; background: var(--navy); transform-origin: left; transform: scaleX(0); }
.proc.open .sums-bar { margin: 14px 0 10px; }
/* Open: the pills sit centred; the tucked search stays pinned to the right. */
.proc.open .sums { justify-content: center; gap: 6px; }
.proc .sums-bar { position: relative; }
.proc.open .search { position: absolute; right: 0; top: 0; bottom: 0; margin: auto 0; }
.proc.open .sum { flex-direction: row; align-items: baseline; gap: 8px; min-width: 0; padding: 6px 12px; border-radius: 999px; }
.proc.open .sum-l { font-size: 13px; font-weight: 500; color: var(--ink-2); }
/* Open: the pills are only the section names; the figures live in the table.
   A debit memo without SO Order still shows by the amber border. */
.proc.open .sum-v, .proc.open .sum-n { display: none; }
.proc.open .sum[aria-expanded=true] { border-color: var(--navy); background: var(--navy-50); }
.proc.open .sum[aria-expanded=true] .sum-l, .proc.open .sum[aria-expanded=true] .sum-v { color: var(--navy); font-weight: 600; }
.notice { display: flex; gap: 10px; align-items: flex-start; padding: 11px 14px; border-radius: var(--r-box); font-size: 13px; margin-top: 12px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); border-left: 3px solid var(--navy); box-shadow: 0 2px 10px rgba(28,61,90,.07); }
.notice .i { margin-top: 1px; color: var(--navy); }
.notice.warn { border-left-color: var(--amber); }
.notice.warn .i { color: var(--amber-stroke); }
.notice.error { border-left-color: var(--block); }
.notice.error .i { color: var(--block); }
.notice.ok { border-left-color: var(--ok); }
.notice.ok .i { color: var(--ok); }
.notice ul { margin: 4px 0 0 18px; }
.console { font: 12px/1.6 var(--mono); background: #10202F; color: #D7E3EE; border-radius: 10px; padding: 10px 12px; max-height: 180px; overflow: auto; white-space: pre-wrap; }
.console .ok { color: #7FD8A6; } .console .warn { color: #F2C14E; } .console .err { color: #F7A097; } .console .skip { color: #9FB3C8; }
.progress-list { list-style: none; display: flex; flex-direction: column; gap: 6px; margin-top: 10px; font-size: 13px; }
.progress-list li { display: flex; gap: 8px; align-items: center; }
.spin { width: 16px; height: 16px; border-radius: 50%; border: 2px solid rgba(28,61,90,.2); border-top-color: var(--navy); animation: spin .7s linear infinite; flex: none; }
.btn .spin { border-color: rgba(255,255,255,.35); border-top-color: #fff; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------------- footer */
.spacer { flex: 1 1 0; min-height: 12px; }
.foot[hidden] { display: none; }
.foot { flex: none; display: flex; align-items: center; gap: 14px; padding: 14px 32px; border-top: 1px solid var(--line); background: var(--surface); transition: background-color 200ms ease, border-color 200ms ease; flex-wrap: wrap; }
.foot .msg { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; color: var(--ink-2); min-width: 0; }
.foot .msg b { color: var(--warn); }
.foot .msg ul { margin: 2px 0 0 18px; }
.foot.done { background: var(--ok-bg); border-top-color: var(--ok-line); }
.foot.done .msg, .foot.done .msg b { color: var(--ok); }
.foot.confirm { background: var(--warn-bg); }
.foot .grow { flex: 1; }
.foot .total { font-size: 13px; color: var(--ink-2); white-space: nowrap; }
.foot .total b { font-size: 15px; color: var(--ink); font-variant-numeric: tabular-nums; margin-left: 4px; }
.foot .why { font-size: 12px; color: var(--ink-3); white-space: nowrap; }

.btn { display: inline-flex; align-items: center; gap: 8px; height: 36px; padding: 0 16px; border-radius: var(--r-ctl); font-weight: 600; font-size: 13px; white-space: nowrap; text-decoration: none;
  transition: transform 160ms var(--ease-out), background-color .15s ease, color .15s ease, border-color .15s ease, box-shadow .15s ease; }
.btn:active:not([aria-disabled=true]):not(:disabled) { transform: scale(.97); }
.btn.primary { background: var(--navy); color: #fff; border: 1.5px solid var(--navy); }
.btn.sec { border: 1.5px solid var(--line); color: var(--ink-2); background: var(--surface); }
.btn.small { height: 30px; padding: 0 12px; font-size: 12.5px; }
.btn.danger { color: var(--block); border: 1.5px solid var(--block-line); background: var(--surface); }
.btn[aria-disabled=true], .btn:disabled { background: var(--surface-2); color: var(--ink-3); border: 1.5px solid var(--line); cursor: not-allowed; }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(28,61,90,.25); }
.btn[aria-busy=true] { cursor: progress; }
.linkbtn { color: var(--navy); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }

/* ---------------------------------------------------------------- forms */
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px 18px; margin-top: 10px; }
.field label { display: block; font-size: 12px; font-weight: 600; color: var(--ink-2); margin-bottom: 5px; }
.field input, .field select { width: 100%; height: 36px; border: 1.5px solid var(--line-strong); border-radius: var(--r-ctl); padding: 0 10px; background: var(--surface-2);
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease; }
.field input:focus, .field select:focus, table.edit input:focus { outline: none; border-color: var(--navy); background: var(--surface); box-shadow: var(--ring); }
.field .hint { margin-top: 3px; }
table.edit { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 13px; margin-top: 6px; border: 1px solid var(--line); border-radius: var(--r-box); overflow: hidden; }
table.edit th { text-align: left; font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: rgba(255,255,255,.85); background: var(--navy); padding: 10px 12px; }
table.edit td { padding: 4px 6px; border-bottom: 1px solid var(--line-soft); }
table.edit input { width: 100%; height: 32px; border: 1.5px solid var(--line); border-radius: 6px; padding: 0 8px; transition: border-color 120ms ease, background-color 120ms ease, box-shadow 120ms ease; }
table.edit td.x { width: 40px; text-align: center; }
table.plain { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 13px; }
table.plain th { text-align: left; font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: rgba(255,255,255,.85); padding: 10px 12px; background: var(--navy); position: sticky; top: 0; z-index: 1; }
table.plain td { padding: 10px 12px; border-bottom: 1px solid var(--line-soft); color: var(--ink-2); }
@media (hover: hover) and (pointer: fine) {
  .tab:hover:not([aria-selected=true]) { background: rgba(28,61,90,.06); color: var(--ink); }
  .chip:hover:not([aria-pressed=true]) { background: var(--surface-2); }
  .btn.primary:hover:not([aria-disabled=true]) { background: var(--navy-dark); }
  .btn.sec:hover:not([aria-disabled=true]) { border-color: var(--navy); color: var(--navy); }
  .btn.danger:hover:not([aria-disabled=true]) { border-color: var(--block); }
  table.edit.quiet tr:hover input { border-color: var(--line-strong); background: var(--surface); }
  table.edit td.x .linkbtn:not(.undo):hover { background: var(--block-bg); color: var(--block); }
  .fold summary:hover .t, .fold summary:hover .chev { color: var(--navy); }
}
@media (prefers-reduced-motion: reduce) {
  .btn, .foot, .st, .tab, .chip { transition-property: opacity, background-color, color, border-color; }
  .btn:active:not([aria-disabled=true]) { transform: none; }
}

/* Tabulator: headers stay in the UI face; sort arrows only when sorted or hovered. */
.tabulator .tabulator-header .tabulator-col .tabulator-col-sorter { opacity: 0; transition: opacity .15s ease; }
.tabulator .tabulator-header .tabulator-col[aria-sort=ascending] .tabulator-col-sorter,
.tabulator .tabulator-header .tabulator-col[aria-sort=descending] .tabulator-col-sorter,
.tabulator .tabulator-header .tabulator-col:hover .tabulator-col-sorter { opacity: 1; }
.setup-form { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

/* ---------------------------------------------------------------- setup
   Ordered by how often a part changes: GL mapping, then memo accounts and
   descriptions, then payment defaults (folded). Acumatica status sits beside
   the title because it is an action, not a setting. */
.main.setup { padding-bottom: 24px; }
.setup-head { display: flex; align-items: flex-start; gap: 24px; flex-wrap: wrap; }
.setup-head .titlebar { flex: 1 1 420px; }

.set-sec { margin-top: 32px; }
.set-sec + .set-sec { padding-top: 28px; border-top: 1px solid var(--line-soft); }
.sec-head h3 { font-size: 16px; font-weight: 700; letter-spacing: -.01em; color: var(--navy); }
.sec-head p { font-size: 13px; color: var(--ink-2); margin-top: 2px; max-width: 80ch; }
.set-sec h4 { font-size: 13px; font-weight: 600; display: flex; align-items: baseline; gap: 8px; }
.set-sec h4 .muted { font-size: 12px; font-weight: 400; }
.set-sec .col > .hint { margin-top: 2px; max-width: 72ch; }

.map-grid, .memo-grid { display: grid; gap: 20px 36px; margin-top: 16px; align-items: start; }
.map-grid { grid-template-columns: minmax(0, 1.85fr) minmax(300px, 1fr); }
.memo-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.memo-grid .col { display: flex; flex-direction: column; gap: 12px; }
.pair-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 18px; }
table.edit th.gl { width: 120px; }
.btn.add { margin-top: 8px; }
.col-head { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.col-head > div { flex: 1 1 320px; }
.col-head .search { width: 220px; }
/* Quiet edit tables: cells read as text until pointed at or focused. The
   boundary returns on hover and focus so editability is never hidden. */
table.edit.quiet { table-layout: fixed; }
#fee-table th:first-child { width: 40%; }
table.edit.quiet th.x { width: 44px; }
table.edit.quiet td { padding: 3px 6px; vertical-align: top; }
table.edit.quiet input { border-color: transparent; background: transparent; transition: border-color 120ms ease, background-color 120ms ease; }
table.edit.quiet input.soft { color: var(--ink-2); }
table.edit.quiet tr:focus-within input { border-color: var(--line-strong); background: var(--surface); }
table.edit.quiet td.x { vertical-align: middle; }
/* Remove: a 28px target in the neutral ink; red only on hover, since it is
   destructive. Undo stays a link (it restores). */
table.edit td.x .linkbtn:not(.undo) { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: var(--r-ctl); color: var(--ink-3); text-decoration: none; transition: background-color 120ms ease, color 120ms ease; }
.rownote { display: flex; align-items: center; gap: 5px; font-size: 12px; color: var(--ink-3); padding: 0 8px 4px; }
.rownote .i { width: 13px; height: 13px; }
.rownote.warn { color: var(--warn); }
.nomatch { margin-top: 8px; }

/* Edit states. Changed: navy tint (the same family as the edited mark in the
   review grids). Invalid: red boundary plus a message under the field.
   Removed: struck through until Save, with Undo in place of the trash icon. */
.field input.changed, table.edit.quiet tr input.changed { background: var(--navy-50); border-color: #9FB4C8; }
.field input[aria-invalid=true], table.edit.quiet tr input[aria-invalid=true] { border-color: var(--block); background: var(--block-bg); }
.foot .msg b.bad { color: var(--block); }
.ferr { font-size: 12px; color: var(--block); margin-top: 3px; font-weight: 600; }
table.edit .ferr { padding: 0 8px 4px; margin-top: 2px; }
table.edit tr.removed input { text-decoration: line-through; color: var(--ink-3); background: transparent; border-color: transparent; }
table.edit tr.removed td { background: var(--surface-3); }
.linkbtn.undo { font-size: 12px; }
.history { list-style: none; margin: 12px 0 0 28px; display: flex; flex-direction: column; gap: 12px; max-width: 900px; }
.history .when { font-size: 12px; font-weight: 600; color: var(--ink-2); }
.history ul { margin: 2px 0 0 18px; font-size: 13px; color: var(--ink-2); }
.field.tol { margin-top: 24px; max-width: 280px; }
.field.tol .hint { max-width: 40ch; }

.readas { margin-top: 5px; font-size: 12px; overflow-wrap: anywhere; }
.readas q { quotes: none; white-space: pre-wrap; color: var(--ink); background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: 4px; padding: 1px 6px; }
.readas .remit { color: var(--ink-3); }

.fold summary { list-style: none; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; cursor: pointer; padding: 4px 0; border-radius: var(--r-ctl); }
.fold summary::-webkit-details-marker { display: none; }
.fold summary .t { font-size: 16px; font-weight: 700; letter-spacing: -.01em; color: var(--navy); }
.fold summary .chev { transform: rotate(-90deg); transition: transform 160ms var(--ease-out); color: var(--ink-2); }
.fold[open] summary .chev { transform: none; }
.fold summary .vals { display: flex; gap: 14px; color: var(--ink-2); }
.fold summary .hint { flex-basis: 100%; padding-left: 28px; }
.fold .form-grid { margin-top: 12px; padding-left: 28px; }
.form-grid.four { grid-template-columns: repeat(4, minmax(0, 1fr)); max-width: 1100px; }

@media (max-width: 1280px) {
  .map-grid { grid-template-columns: minmax(0, 1fr); }
  .map-grid .col:last-child { max-width: 640px; }
}
@media (max-width: 1100px) {
  .memo-grid { grid-template-columns: minmax(0, 1fr); }
  .form-grid.four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) { .fold summary .chev { transition: none; } }

/* Row state change (e.g. Needs GL -> Ready): the tint fades instead of snapping. */
.tabulator-row { transition: background-color 240ms ease; }

/* ---------------------------------------------------------------- toasts
   Rebate's toast stack: bottom-right, newest at the bottom, white card with a
   3px left edge. Leaves after 6s (paused on hover/focus), like Rebate. */
.toast-stack { position: fixed; right: 16px; bottom: 16px; z-index: var(--z-toast); display: flex; flex-direction: column; align-items: flex-end; gap: 8px; max-width: min(420px, calc(100vw - 32px)); pointer-events: none; }
.toast { pointer-events: auto; display: flex; align-items: flex-start; gap: 10px; min-width: 280px; padding: 12px 12px 12px 14px; border-radius: var(--r-box); background: var(--surface);
  border: 1px solid var(--line); border-left: 3px solid var(--navy); box-shadow: var(--shadow-pop); font-size: 13px; color: var(--ink);
  position: relative; overflow: hidden; --edge: var(--navy);
  animation: toast-in 320ms var(--ease-out); }
.toast .i { margin-top: 1px; color: var(--navy); }
.toast.error { border-left-color: var(--block); --edge: var(--block); }
.toast.error .i { color: var(--block); }
.toast.warn { border-left-color: var(--amber); --edge: var(--amber-stroke); }
.toast.warn .i { color: var(--amber-stroke); }
.toast b { font-weight: 600; color: var(--ink); }
.toast-list { list-style: none; margin-top: 4px; display: flex; flex-direction: column; gap: 2px; color: var(--ink-2); font-size: 12.5px; }
.toast span { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.toast-x { flex: none; display: grid; place-items: center; width: 24px; height: 24px; margin: -3px -4px 0 0; border-radius: 6px; color: var(--ink-3); transition: background-color .15s ease, color .15s ease; }
.toast-x svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.toast.leaving { animation: toast-out 180ms var(--ease-out) forwards; }
/* The 6s line along the foot; its end dismisses the toast (app.js armToast).
   Hover or focus pauses it, and so does a hidden tab. */
.toast-timer { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--edge); transform-origin: left; animation: toast-time 6s linear forwards; }
@keyframes toast-time { from { transform: scaleX(1); } to { transform: scaleX(0); } }
.toast:hover > .toast-timer, .toast:focus-within > .toast-timer, html.tab-hidden .toast-timer { animation-play-state: paused; }
/* --toast-dy: 1 enters from below (desktop stack), -1 from above (phones). */
@keyframes toast-in { from { opacity: 0; transform: translateY(calc(var(--toast-dy, 1) * 16px)) scale(.96); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(calc(var(--toast-dy, 1) * 10px)); } }
@media (hover: hover) and (pointer: fine) { .toast-x:hover { background: var(--surface-3); color: var(--ink); } }
@media (prefers-reduced-motion: reduce) { .toast, .toast.leaving { animation-name: fade-in; } .toast.leaving { animation-name: fade-out; } }

/* ---------------------------------------------------------------- utilities (replace inline styles) */
.skip { position: absolute; left: 12px; top: -60px; z-index: var(--z-dialog); padding: 8px 14px; border-radius: var(--r-ctl); background: var(--navy); color: #fff; font-weight: 600; text-decoration: none; transition: top .15s ease; }
.skip:focus { top: 12px; }
.row-actions { display: flex; gap: 10px; align-items: center; }
.grow-host { flex: 1 1 auto; }
.spacer.tight { min-height: 0; flex: 0; }
/* Bottom margin equals the space above the title (.main top padding). */
.spacer.foot-gap { min-height: 28px; flex: 0; }
@media (max-height: 820px) { .spacer.foot-gap { min-height: 18px; } }
.tiles.rtm { grid-template-columns: minmax(320px, 1fr) minmax(320px, 1.4fr); }
.c-ok { color: var(--ok); } .c-warn { color: var(--warn); } .c-block { color: var(--block); }

/* Error pages (404 and friends) inside the window. */
.errpage { margin: auto; max-width: 460px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 40px 0; }
.errpage .code { font: 800 13px/1 var(--mono); letter-spacing: .08em; color: var(--ink-3); }
.errpage h2 { font-size: 20px; font-weight: 800; color: var(--navy); }
.errpage p { color: var(--ink-3); font-size: 13px; line-height: 1.65; text-wrap: pretty; }

/* Short windows: tighter footer (after .foot so it wins). */
@media (max-height: 820px) { .foot { padding: 12px 24px; } }
/* Skip-link target: passes the window's height on to main + footer. */
.content { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

/* ---------------------------------------------------------------- processing
   Ported from Rebate Validation's ProcessingScreen: navy field, white square
   that morphs round -> square while turning (2s linear), status line that
   cross-fades (out, swap at 300ms, in). Fades in over .42s like Rebate. */
.proc-screen { position: absolute; inset: 0; z-index: 20; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 24px; text-align: center;
  background: var(--navy); opacity: 0; transition: opacity .42s var(--ease-settle); }
.proc-screen[hidden] { display: none; }
.proc-screen.show { opacity: 1; }
.loader-shape { width: 48px; height: 48px; margin: 0 auto 20px; border-radius: 50%; background: #fff; animation: ellipseAnimation 2s linear infinite; }
@keyframes ellipseAnimation {
  0% { border-radius: 50%; }
  12.5% { border-radius: 0 50% 50% 50%; transform: rotate(45deg); }
  25% { border-radius: 0 0 50% 50%; transform: rotate(90deg); }
  37.5% { border-radius: 0 0 0 50%; transform: rotate(135deg); }
  50% { border-radius: 0; transform: rotate(180deg); }
  62.5% { border-radius: 50% 0 0 0; transform: rotate(225deg); }
  75% { border-radius: 50% 50% 0 0; transform: rotate(270deg); }
  87.5% { border-radius: 50% 50% 50% 0; transform: rotate(315deg); }
  100% { border-radius: 50%; transform: rotate(360deg); }
}
.process-text { min-height: 22px; font-size: 15px; font-weight: 600; letter-spacing: .2px; color: rgba(255,255,255,.8); transition: opacity .3s; }
/* Rebate's close button: 30px circle, white on 10% white. */
.proc-x { position: absolute; top: 16px; right: 16px; display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; background: rgba(255,255,255,.1); color: rgba(255,255,255,.7);
  transition: background-color .15s ease, color .15s ease, transform .16s var(--ease-out); }
.proc-x svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.proc-x:active { transform: scale(.92); }
.proc-x:focus-visible, .proc-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.proc-screen.failed .loader-shape, .proc-screen.failed .proc-x { display: none; }
.proc-error { margin-top: 8px; max-width: 60ch; font-size: 13px; line-height: 1.6; color: rgba(255,255,255,.72); }
.proc-actions { display: flex; gap: 8px; margin-top: 22px; }
.proc-btn { height: 36px; padding: 0 16px; border-radius: var(--r-ctl); border: 1.5px solid rgba(255,255,255,.3); color: #fff; font-size: 13px; font-weight: 600;
  transition: background-color .15s ease, border-color .15s ease, transform .16s var(--ease-out); }
.proc-btn.primary { background: #fff; border-color: #fff; color: var(--navy); }
.proc-btn:active { transform: scale(.97); }
@media (hover: hover) and (pointer: fine) {
  .proc-btn:hover { background: rgba(255,255,255,.1); border-color: rgba(255,255,255,.5); }
  .proc-btn.primary:hover { background: rgba(255,255,255,.88); }
}
@media (prefers-reduced-motion: reduce) { .stop-dialog[open] { animation-name: fade-in; } .stop-dialog.closing { animation-name: fade-out; } }
/* Stop confirmation: Rebate's ConfirmDialog (440px card, radius 14, blurred
   navy backdrop, springy entrance, quicker exit). */
.stop-dialog { margin: auto; width: min(440px, calc(100% - 32px)); padding: 22px 22px 18px; border: 0; border-radius: 14px; background: var(--surface); color: var(--ink);
  box-shadow: 0 20px 50px rgba(21,46,69,.25), 0 2px 6px rgba(21,46,69,.08); }
.stop-dialog[open] { animation: stop-in .4s var(--ease-overshoot); }
.stop-dialog::backdrop { background: rgba(21,46,69,.32); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); animation: fade-in .2s ease-out; }
.stop-dialog.closing { animation: stop-out .14s ease-out forwards; }
.stop-dialog.closing::backdrop { animation: fade-out .14s ease-out forwards; }
@keyframes stop-in { from { opacity: 0; transform: translateY(12px) scale(.9); } }
@keyframes stop-out { to { opacity: 0; transform: translateY(6px) scale(.95); } }
.stop-dialog h3 { font-size: 16px; font-weight: 800; color: var(--navy); }
.stop-dialog p { margin-top: 6px; font-size: 13px; line-height: 1.6; color: var(--ink-2); }
.stop-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }
/* Review's Build CM question: the warnings as a short list. */
.build-dialog { width: min(520px, calc(100% - 32px)); }
.build-warn { margin: 8px 0 0 18px; font-size: 13px; line-height: 1.55; color: var(--ink); }
.build-warn li + li { margin-top: 4px; }
@media (hover: hover) and (pointer: fine) {
  .proc-x:hover { background: rgba(255,255,255,.18); color: #fff; }
}
/* Loaders keep Rebate's speed under reduced motion: they only say "working". */
@media (prefers-reduced-motion: reduce) { .proc-screen { transition-duration: .2s; } }
.content:focus { outline: none; }
.sprite { position: absolute; }

/* ---------------------------------------------------------------- phone tier
   Family standard (swcorp-app-family/css/swcorp.css, "responsive tiers"):
   below 600px (header, safe area and menu come from swcorp.css) gutters are 16px, inputs are 16px (iOS zooms on anything
   smaller), slots go 2 per row and toasts sit at the top, full width. */
@media (max-width: 599px) {
  .run-chip { display: none; }
  .main { padding: 20px 16px 0; }
  .titlebar h2 { font-size: 18px; }
  .foot { padding: 12px 16px; gap: 10px; }
  .foot .btn.primary { flex: 1 1 100%; justify-content: center; height: 44px; }
  .field input, .field select, .search input, table.edit input,
  .tabulator-row .tabulator-cell.tabulator-editing input { font-size: 16px; }
  .search { width: 100%; margin-left: 0; }
  .btn { height: 40px; }
  .slots { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .slots > .slot:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .slot { min-height: 56px; padding: 10px 12px; gap: 10px; }
  .tiles, .form-grid.four { grid-template-columns: 1fr; }
  .toast-stack { left: 12px; right: 12px; top: calc(56px + 8px + var(--sat)); bottom: auto; max-width: none; align-items: stretch; }
  .toast { --toast-dy: -1; min-width: 0; }
  .fix-dialog, .stop-dialog, .build-dialog { width: calc(100% - 24px); }
}
