/* MMD portal "GSP XP" skin — the shared semantic component layer for the
   gsp-xp design language (public/_design-system/design-language-gsp-xp.css).
   Moved out of the strategy app on 2026-08-22 when Order Management became
   the second app in this language: one source of truth, no per-app fork.

   Origin — Ben 2026-08-20 for the strategy app:
   Ben 2026-08-20: "have the design of the screens like SAP B1 screens, very
   windows XP era style, super functional and dense." Recorded override of the
   letterbox CDS look for the strategy app. SEMANTIC classes only — the app
   consumes these exactly like CDS classes; zero inline styles remain the rule
   (computed geometry travels as SVG/HTML attributes: line x/y, td colspan).
   One-screen constraint: the app frame locks to the portal body height and
   only pane interiors scroll; designed for 1366x768 upward. */

/* the portal body is the one scroll region; a GSP page opts out and fills it */
.shell > .body:has(> .gsp-app) { padding: 0; overflow: hidden; }

.gsp-app{font-family:var(--font-ui);font-size:11px;color:var(--ds-c-black-02);background:var(--ds-c-yellow-13);height:100%;display:flex;flex-direction:column;overflow:hidden}
.gsp-app *{box-sizing:border-box}

/* window + titlebar */
.gsp-window{border:1px solid var(--ds-c-blue-32);background:var(--ds-c-yellow-13);display:flex;flex-direction:column;min-height:0;min-width:0;flex:1}
.gsp-titlebar{background:linear-gradient(180deg,var(--ds-c-blue-24) 0%,var(--ds-c-blue-32) 100%);color:var(--ds-c-white-01);font-weight:700;font-size:11px;padding:3px 6px;display:flex;align-items:center;gap:6px;flex:none}
.gsp-titlebar-icon{width:14px;height:14px;background:var(--ds-c-yellow-13);border:1px solid var(--ds-c-white-01);flex:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ds-c-blue-32);font-size:9px;font-weight:700}
.gsp-titlebar-spring{flex:1}

/* menu + toolbar */
/* Title-bar close — real XP chrome on every window and dialog (Ben
   2026-08-21: "add proper nav items, close windo icons"). Escape does the
   same thing. */
/* One compact lead-company filter, never a row of country chips (Ben has
   rejected the chip row repeatedly); "All lead companies" is the default. */
.gsp-leadfilter{display:inline-flex;align-items:center;gap:4px;flex:none}
.gsp-leadfilter-label{font-size:10px;color:var(--ds-c-neutral-18);text-transform:uppercase;letter-spacing:.04em}
.gsp-leadfilter .gsp-select{max-width:210px}
.gsp-input-search{max-width:200px}
/* A toolbar is a flex row with min-width:0, so a native select or search
   box shrinks to a sliver once the row is full (seen live: the Catalogue's
   Group by / Rows selects and Find box). A control keeps a readable floor. */
.gsp-toolbar .gsp-select{min-width:120px}
.gsp-toolbar .gsp-input-search{min-width:150px}
.gsp-menubar{background:var(--ds-c-yellow-13);border-bottom:1px solid var(--ds-c-yellow-25);padding:1px 4px;display:flex;gap:2px;flex:none}
.gsp-menu{padding:2px 8px;cursor:pointer;color:var(--ds-c-black-02);text-decoration:none;border-radius:var(--ds-radius-sm);}
.gsp-menu:hover,.gsp-menu[aria-current="page"],.gsp-menu[data-active="true"]{background:var(--ds-c-blue-21);color:var(--ds-c-white-01)}
/* wrap, never clip: a toolbar wider than its window folds to a second row
   instead of hiding controls off the right edge (MMDB-2404 catalogue). */
.gsp-toolbar{background:var(--ds-c-yellow-13);border-bottom:1px solid var(--ds-c-yellow-25);padding:2px 4px;display:flex;gap:2px;align-items:center;flex:none;flex-wrap:wrap;min-width:0}
.gsp-tool{border:1px solid transparent;background:transparent;color:var(--ink);padding:3px 8px;font-family:var(--ds-font-window);border-radius:var(--ds-radius-sm);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;line-height:1;gap:4px;white-space:nowrap}
.gsp-tool:hover{border-color:var(--hairline-dark);background:var(--paper-2)}
/* A tool that cannot act says so (MMDB-2416): greyed, inert cursor, no hover
   invitation — an enabled-looking dead button is a lie. */
.gsp-tool:disabled{color:var(--ink-faint);cursor:default}
.gsp-tool:disabled:hover{border-color:transparent;background:transparent}
.gsp-tool[data-primary="true"]{border:1px solid var(--ds-c-blue-31);background:linear-gradient(180deg,var(--ds-c-white-01) 0%,var(--ds-c-yellow-11) 47%,var(--ds-c-amber-12) 100%);box-shadow:inset 1px 1px 0 var(--ds-c-white-01)}
.gsp-tool[data-primary="true"]:hover{background:linear-gradient(180deg,var(--ds-c-white-01) 0%,var(--ds-c-amber-08) 47%,var(--ds-c-amber-16) 100%)}
.gsp-tool[data-on="true"]{border-color:var(--ds-c-blue-21);background:var(--ds-c-blue-09)}
.gsp-toolbar-sep{width:1px;align-self:stretch;background:var(--ds-c-yellow-25);margin:1px 3px}
.gsp-toolbar-spring{flex:1}
.gsp-toolbar-note{color:var(--ds-c-neutral-13);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}

/* status bar */
.gsp-statusbar{border-top:1px solid var(--ds-c-yellow-25);background:var(--ds-c-yellow-13);padding:2px 6px;display:flex;flex-wrap:wrap;gap:4px 8px;flex:none;color:var(--ds-c-neutral-18);align-items:center;min-width:0}
.gsp-statusbar-cell{border:1px inset var(--ds-c-amber-11);padding:0 6px;background:var(--ds-c-yellow-13);white-space:nowrap}
.gsp-statusbar-cell[data-tone="red"]{color:var(--ds-c-red-22);font-weight:700}
.gsp-statusbar-spring{flex:1}
/* A sentence-length status cell (a refresh result, a sync message): takes
   its own full-width row and wraps instead of running past the window. */
.gsp-statusbar-note{white-space:normal;min-width:0;flex:1 1 100%}
/* A read failure said here used to be the ONLY place it was ever shown, in a
   single-line, ellipsis-clipped cell squeezed behind five other counts — the
   exact text that reported a 20s timeout was invisible unless someone widened
   the window (audit, 2026-08-22). It still echoes here for anyone glancing at
   the status bar, but is never load-bearing any more: `om-read-stale` /
   `om-failure` above the grid carry the same message unclipped. Forced onto
   its own full-width line so it is never fighting the other cells for room,
   and never truncated. */
.gsp-statusbar-evidence{border:1px solid var(--ds-c-amber-23);background:var(--ds-c-yellow-19);color:var(--ds-c-yellow-26);font-weight:700;padding:1px 6px;white-space:normal;min-width:0;flex:1 1 100%}

/* ------------------------------------------------------------------ */
/* Why-What-How matrix (graphical, drawn connectors, chain isolation)  */
.gsp-matrix{display:grid;grid-template-columns:1fr 36px 1fr 36px 1.25fr;flex:1;min-height:0;padding:3px;gap:0;position:relative}
/* connectors sit UNDER the opaque columns so they only show in the gaps */
.gsp-matrix-svg{position:absolute;inset:0;pointer-events:none;z-index:1;width:100%;height:100%}
.gsp-edge{stroke:var(--ds-c-amber-17);stroke-width:1.5;fill:none}
.gsp-edge[data-on="true"]{stroke:var(--ds-c-blue-24);stroke-width:2.5}
.gsp-mcol{border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);display:flex;flex-direction:column;min-height:0;min-width:0;position:relative;z-index:2}
.gsp-mcol-head{background:linear-gradient(180deg,var(--ds-c-white-02) 0%,var(--ds-c-blue-07) 100%);border-bottom:1px solid var(--ds-c-neutral-06);padding:3px 6px;font-weight:700;color:var(--ds-c-blue-32);flex:none;display:flex;gap:6px;align-items:baseline}
.gsp-mcol-head-count{font-weight:400;color:var(--ds-c-neutral-13)}
.gsp-mcol-body{flex:1;overflow:auto;min-height:0;padding:4px;display:flex;flex-direction:column;gap:4px}
.gsp-mgap{min-width:0}
.gsp-node{border-radius:var(--ds-radius-sm);border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-yellow-05);padding:3px 6px;cursor:pointer;position:relative;text-align:left;font:inherit;width:100%;display:block}
.gsp-node:hover{background:var(--ds-c-yellow-09)}
.gsp-node[data-selected="true"]{border:2px solid var(--ds-c-blue-24);background:var(--ds-c-blue-04);padding:2px 5px}
.gsp-node[data-dim="true"]{opacity:.35}
.gsp-node-id{font-size:10px;color:var(--ds-c-blue-32);font-weight:700;margin-right:4px}
.gsp-node-sub{display:block;font-size:10px;color:var(--ds-c-neutral-10);margin-top:1px}
.gsp-node-open{display:inline-block;margin-left:6px;border:1px solid var(--ds-c-blue-31);background:linear-gradient(180deg,var(--ds-c-white-01) 0%,var(--ds-c-yellow-11) 47%,var(--ds-c-amber-12) 100%);box-shadow:inset 1px 1px 0 var(--ds-c-white-01);padding:0 6px;font-size:10px;font-weight:700;color:var(--ds-c-blue-32);cursor:pointer}
.gsp-node-open:hover{background:linear-gradient(180deg,var(--ds-c-white-01) 0%,var(--ds-c-amber-08) 47%,var(--ds-c-amber-16) 100%)}
.gsp-pane-foot{border-top:1px solid var(--ds-c-yellow-25);background:var(--ds-c-yellow-13);padding:2px 6px;color:var(--ds-c-neutral-13);flex:none}
.gsp-plan-state{font-size:10px;white-space:nowrap}
.gsp-plan-state[data-state="none"]{color:var(--ds-c-red-17);font-weight:700}
.gsp-plan-state[data-state="deck_derived"]{color:var(--rp-ink-mute)}
.gsp-plan-state[data-state="draft"]{color:var(--rp-ink-mute)}
.gsp-plan-state[data-state="unscheduled"]{color:var(--ds-c-red-17)}
.gsp-plan-state[data-state="confirmed"]{color:var(--ds-c-green-12)}

/* status chips */
.gsp-chip{display:inline-block;border:1px solid var(--ds-c-neutral-06);padding:0 4px;font-size:10px;background:var(--ds-c-white-01);white-space:nowrap;border-radius:var(--ds-radius-sm);}
.gsp-chip[data-tone="red"]{background:var(--ds-c-red-08);border-color:var(--ds-c-red-17);color:var(--ds-c-red-26)}
.gsp-chip[data-tone="amber"]{background:var(--ds-c-yellow-19);border-color:var(--ds-c-amber-23);color:var(--ds-c-yellow-26)}
.gsp-chip[data-tone="green"]{background:var(--ds-c-green-04);border-color:var(--ds-c-green-09);color:var(--ds-c-green-12)}
.gsp-chip[data-tone="blue"]{background:var(--ds-c-blue-07);border-color:var(--ds-c-blue-21);color:var(--ds-c-blue-32)}
/* "stop": a read failed and the true state is UNKNOWN — never the same claim
   as "red" (verified retired/unguarded). Hazard-striped on the same red
   tokens `red` already uses, so it reads as "more urgent than red", not as
   a fourth unrelated colour. */
.gsp-chip[data-tone="stop"]{background:repeating-linear-gradient(135deg,var(--ds-c-red-08),var(--ds-c-red-08) 4px,var(--ds-c-white-01) 4px,var(--ds-c-white-01) 8px);border-color:var(--ds-c-red-17);color:var(--ds-c-red-26);font-weight:700}
/* neutral tone for a read-only/reference status (e.g. an imported historic
   record, not a live workflow state) -- Ben, 2026-08-22 direct-purchase
   historic-rows task */
.gsp-chip[data-tone="grey"]{background:var(--ds-c-yellow-15);border-color:var(--ds-c-neutral-06);color:var(--ds-c-neutral-13)}
.gsp-link{color:var(--ds-c-blue-32);text-decoration:underline;cursor:pointer;background:none;border:0;font:inherit;padding:0}
.gsp-muted{color:var(--ds-c-neutral-08)}

/* ------------------------------------------------------------------ */
/* Objective program sheet (MMD Project Reporting Template mirror)     */
.gsp-sheet{display:grid;grid-template-columns:1fr 1fr 1fr;grid-auto-rows:min-content;gap:3px;padding:3px 3px 46px;flex:1;min-height:0;overflow:auto}
.gsp-card{border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);display:flex;flex-direction:column;min-height:0}
.gsp-card-head{background:linear-gradient(180deg,var(--ds-c-white-02),var(--ds-c-yellow-20));border-bottom:1px solid var(--ds-c-yellow-25);padding:2px 6px;font-weight:700;font-size:10px;letter-spacing:.04em;display:flex;gap:6px;align-items:baseline}
.gsp-card-head-note{font-weight:400;color:var(--ds-c-neutral-12);letter-spacing:0}
.gsp-card-body{padding:4px 6px;font-size:11px;line-height:1.35}
.gsp-card-body ul{margin:0;padding-left:14px}
.gsp-span2{grid-column:span 2}
.gsp-span3{grid-column:span 3}
.gsp-headstrip{display:flex;gap:8px;align-items:center;min-width:0;overflow:hidden}
.gsp-headcell{border:1px inset var(--ds-c-amber-11);background:var(--ds-c-white-01);padding:1px 6px;white-space:nowrap;font-size:10px}
.gsp-rag{display:inline-block;width:12px;height:12px;border:1px solid var(--ds-c-neutral-12);vertical-align:middle}
.gsp-rag[data-rag="G"]{background:var(--ds-c-green-07)}.gsp-rag[data-rag="A"]{background:var(--ds-c-amber-20)}.gsp-rag[data-rag="R"]{background:var(--ds-c-red-14)}.gsp-rag[data-rag="N"]{background:var(--ds-c-yellow-24)}
.gsp-noplan{border:2px solid var(--ds-c-red-17);background:var(--ds-c-red-04);color:var(--ds-c-red-26);font-weight:700;padding:8px 10px;text-align:center}
.gsp-noplan .gsp-noplan-sub{display:block;font-weight:400;color:var(--ds-c-neutral-18);margin-top:2px}

/* phase timeline (computed month spans travel as td colspan attributes) */
.gsp-gantt{width:100%;border-collapse:collapse}
.gsp-gantt th,.gsp-gantt td{border:1px solid var(--ds-c-yellow-15);font-size:9px;padding:1px 3px;text-align:center}
.gsp-gantt td.gsp-phase-name{text-align:left;font-size:10px;white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis}
.gsp-bar{display:block;height:9px;background:repeating-linear-gradient(90deg,var(--ds-c-blue-21) 0,var(--ds-c-blue-21) 6px,var(--ds-c-blue-16) 6px,var(--ds-c-blue-16) 8px)}
.gsp-bar[data-state="done"]{background:var(--ds-c-green-07)}
.gsp-bar[data-state="planned"]{background:repeating-linear-gradient(90deg,var(--ds-c-yellow-24) 0,var(--ds-c-yellow-24) 4px,var(--ds-c-white-01) 4px,var(--ds-c-white-01) 6px)}
.gsp-action-row{display:flex;gap:6px;align-items:baseline;border-bottom:1px dotted var(--ds-c-yellow-20);padding:1px 0}
.gsp-traction{font-size:9px;border:1px solid var(--ds-c-neutral-06);padding:0 3px;white-space:nowrap;background:var(--ds-c-white-01)}
.gsp-traction[data-t="moving"],.gsp-traction[data-t="granted"],.gsp-traction[data-t="done"]{background:var(--ds-c-green-04);border-color:var(--ds-c-green-09)}
.gsp-traction[data-t="stalled"],.gsp-traction[data-t="high"]{background:var(--ds-c-red-08);border-color:var(--ds-c-red-17)}
.gsp-traction[data-t="new"],.gsp-traction[data-t="decision"],.gsp-traction[data-t="money"]{background:var(--ds-c-blue-07);border-color:var(--ds-c-blue-21)}
.gsp-traction[data-t="med"]{background:var(--ds-c-yellow-19);border-color:var(--ds-c-amber-23)}

/* overview rollup band — dense working strip above the grid */
.gsp-rollup{border-bottom:1px solid var(--ds-c-yellow-25);background:var(--ds-c-yellow-05);padding:2px 6px;display:flex;gap:8px;align-items:baseline;flex-wrap:wrap;flex:none}
.gsp-rollup-cell{border:1px inset var(--ds-c-amber-11);background:var(--ds-c-white-01);padding:0 6px;white-space:nowrap}
.gsp-rollup-cell[data-tone="red"]{color:var(--ds-c-red-22);font-weight:700}
.gsp-rollup-cell b{color:var(--ds-c-red-22)}
/* full-basis + ellipsis: the nowrap chase line's min-content width was
   wider than the viewport and dragged the whole window into page-level
   horizontal scroll */
.gsp-rollup-chase{flex:1 1 100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* hub sections (Review & status page): stacked labeled blocks */
.gsp-hub-section{border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);margin:3px}
.gsp-hub-section .gsp-mcol-head{display:flex;align-items:baseline;gap:6px}

/* grids (SAP-B1 style, used by trail + overview) */
.gsp-grid{width:100%;border-collapse:collapse;font-size:11px}
.gsp-grid th{background:linear-gradient(180deg,var(--ds-c-white-02),var(--ds-c-yellow-20));border:1px solid var(--ds-c-yellow-25);border-top:none;padding:2px 5px;text-align:left;font-weight:700;position:sticky;top:0;white-space:nowrap;z-index:2}
.gsp-grid td{border-right:1px solid var(--ds-c-yellow-15);border-bottom:1px solid var(--ds-c-yellow-15);padding:2px 5px;vertical-align:top}
.gsp-grid tr:nth-child(even) td{background:var(--ds-c-yellow-05)}
/* Hover only invites a click where a click does something (MMDB-2416):
   a glowing row with no handler is a lying affordance. */
.gsp-grid tbody tr[data-click="true"]:hover td{background:var(--ds-c-yellow-09)}
.gsp-grid td[data-num="true"],.gsp-grid th[data-num="true"]{text-align:right;font-variant-numeric:tabular-nums}
.gsp-grid tr[data-group="true"] td{background:var(--ds-c-blue-07);color:var(--ds-c-blue-32);font-weight:700;border-bottom:1px solid var(--ds-c-neutral-06)}
/* imported historic/reference row -- dimmed + non-interactive look, no
   hover highlight, distinct from a live, clickable workflow row (Ben,
   2026-08-22 direct-purchase historic-rows task) */
.gsp-grid tr[data-historic="true"] td{background:var(--ds-c-yellow-08);color:var(--ds-c-neutral-12);font-style:italic}
.gsp-grid tr[data-historic="true"]:hover td{background:var(--ds-c-yellow-08)}
.gsp-grid tr[data-click="true"]{cursor:pointer}
.gsp-picker-results{max-height:220px;overflow-y:auto;border:1px solid var(--ds-c-neutral-06)}
.gsp-cell-tight{white-space:nowrap;max-width:240px;overflow:hidden;text-overflow:ellipsis}
/* frozen identity columns on the overview grid (UX P1: scrolling right to the
   status columns lost the ID/Objective a row belongs to) */
.gsp-col-pin{position:sticky;background:var(--ds-c-white-01);z-index:3}
th.gsp-col-pin{z-index:4}
.gsp-col-pin-id{left:0;min-width:84px;max-width:320px;border-right:1px solid var(--ds-c-neutral-06)}
.gsp-col-pin-title{left:84px;border-right:2px solid var(--ds-c-neutral-06)}
.gsp-grid-kpi .gsp-col-pin-id{max-width:230px}
.gsp-grid-kpi-plain tbody td:nth-child(4){max-width:180px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gsp-grid-kpi tbody td:nth-child(2){max-width:170px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gsp-grid tr:nth-child(even) td.gsp-col-pin{background:var(--ds-c-yellow-05)}
.gsp-grid tbody tr:hover td.gsp-col-pin{background:var(--ds-c-yellow-09)}
.gsp-group-label{position:sticky;left:6px;display:inline-block}
.gsp-group-toggle{background:none;border:0;font:inherit;font-weight:700;color:var(--ds-c-blue-32);cursor:pointer;padding:0;text-align:left}
.gsp-group-toggle:hover .gsp-group-chevron{color:var(--ds-c-red-22)}
.gsp-group-chevron{display:inline-block;width:12px;color:var(--ds-c-blue-21)}
.gsp-group-hint{font-weight:400;color:var(--ds-c-neutral-12);font-size:10px}
tr[data-group][data-collapsed="true"] td{border-bottom:2px solid var(--ds-c-neutral-06)}
/* open affordance on clickable rows (Ben: "make sure it's understood...
   they can double-click to open") */
.gsp-grid tr[data-click="true"] td:first-child::before{content:"▸ ";color:var(--ds-c-blue-21);font-size:9px}
.gsp-grid tr[data-click="true"]:hover td:first-child::before{color:var(--ds-c-red-22)}
/* sortable column headers (MMDB-2256: register/activity/status grids) */
.gsp-grid th[data-click="true"]{cursor:pointer}
.gsp-grid th[data-click="true"]:hover{background:var(--ds-c-blue-04)}
/* compound cell: bold primary line + gsp-node-sub secondary line, used where
   a DataGrid cell used to stack a title over an id/leader/lead sub-line */
.gsp-cell-title{font-weight:700}
/* the pane scrolls both ways — keep the scrollbar visible as the affordance;
   it is also the ONE region that grows/scrolls inside a gsp-window (the
   one-screen rule: everything else in the window is flex:none) */
.gsp-pane-body{flex:1;min-height:0;overflow:auto;padding-bottom:46px;scrollbar-width:thin;scrollbar-color:var(--ds-c-neutral-06) var(--ds-c-yellow-13)}

/* stacked sections inside one scrolling pane (MMDB-2256: register/status
   surfaces stack more than one gsp-grid under a single toolbar+statusbar) */
.gsp-section{border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);margin:3px;display:flex;flex-direction:column;min-height:0}
.gsp-section-head{background:linear-gradient(180deg,var(--ds-c-white-02) 0%,var(--ds-c-blue-07) 100%);border-bottom:1px solid var(--ds-c-neutral-06);padding:2px 6px;font-weight:700;color:var(--ds-c-blue-32);flex:none;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.gsp-section-head-note{font-weight:400;color:var(--ds-c-neutral-13)}

/* toolbar filter fields — fixed widths so they don't fight the toolbar's
   note/spring for growth (register/activity/status filter bars) */
.gsp-toolbar-label{color:var(--ds-c-neutral-18);white-space:nowrap}
.gsp-input[data-w="wide"]{flex:none;width:200px}
.gsp-select[data-w="wide"]{flex:none;width:168px}

/* forms (dense XP group boxes) + dialogs */
.gsp-fieldset{border:1px solid var(--ds-c-neutral-06);margin:4px;padding:4px 6px 6px;min-width:0}
.gsp-fieldset legend{color:var(--ds-c-blue-32);font-weight:700;padding:0 4px}
.gsp-form-row{display:flex;align-items:center;gap:6px;margin:2px 0}
.gsp-form-row label{flex:0 0 110px;text-align:right;color:var(--ds-c-neutral-18)}
.gsp-input,.gsp-select,.gsp-textarea{border:1px solid var(--ds-c-blue-13);background:var(--ds-c-white-01);font:inherit;padding:1px 3px;flex:1;min-width:0}
.gsp-input[data-w="narrow"]{flex:none;width:76px}
.gsp-select[data-w="narrow"]{flex:none;width:96px}
.gsp-textarea{resize:none}
/* 2026-08-28 MMDB-1688/2395 locked-design rollout: gsp-btn is the ONE
   button class every windowed-desktop app (Strategy/Procurement2/
   Order-mgmt/Master-data/Dealer-portal) renders through -- 193 call sites
   across 47 files, all plain "gsp-btn" with no variant. It is now a thin
   alias onto the central .ds-btn recipe (flat, 1px border, hairline inset
   bottom edge, 4px radius, SF Pro, CDS tokens only -- zero new hex). */
.gsp-btn{display:inline-flex;align-items:center;justify-content:center;line-height:1;gap:6px;border:1px solid var(--hairline-dark);background:var(--paper);color:var(--ink);box-shadow:inset 0 -1px 0 color-mix(in srgb, var(--ink) 10%, transparent);font-family:var(--ds-font-window);font-weight:500;font-size:11px;padding:5px 13px;border-radius:var(--ds-radius-sm);cursor:pointer}
.gsp-btn:hover{border-color:var(--ink-mute);color:var(--ink)}
.gsp-btn[data-default="true"]{background:var(--baobab);color:var(--baobab-on);border-color:var(--baobab);box-shadow:inset 0 -1px 0 rgba(0,0,0,.18)}
.gsp-btn[data-default="true"]:hover{background:color-mix(in srgb, var(--baobab) 88%, black)}
.gsp-btn:disabled{color:var(--ink-faint);cursor:default;opacity:.6}
.gsp-btnrow{display:flex;gap:7px;justify-content:flex-end;align-items:center;padding:6px 10px;border-top:1px solid var(--hairline);background:var(--paper-2);flex:none}
.gsp-btnrow-note{margin-right:auto;font-family:var(--ds-font-window);color:color-mix(in srgb, var(--baobab) 72%, black)}
.gsp-dialog-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.25);display:flex;align-items:center;justify-content:center;z-index:60}
.gsp-dialog{border:1px solid var(--ds-c-blue-32);background:var(--ds-c-yellow-13);box-shadow:2px 2px 6px rgba(0,0,0,.4);width:min(860px,94vw);max-height:92vh;display:flex;flex-direction:column;font-family:var(--font-ui);font-size:11px}
.gsp-dialog *{box-sizing:border-box}
.gsp-dialog-body{overflow:auto;min-height:0}
.gsp-rowbtn{border:1px solid var(--hairline-dark);background:var(--paper);color:var(--ink);font-family:var(--ds-font-window);font-size:10px;padding:1px 6px;cursor:pointer;flex:none;border-radius:var(--ds-radius-sm)}
.gsp-rowbtn:hover{background:var(--baobab-bg);border-color:var(--baobab)}
.gsp-addrow{border:1px dashed var(--hairline-dark);background:var(--paper);color:var(--ink-mute);font-family:var(--ds-font-window);padding:2px 9px;cursor:pointer;margin:3px 0 0;border-radius:var(--ds-radius-sm)}
.gsp-addrow:hover{background:var(--paper-2);border-color:var(--ink-mute);color:var(--ink)}

/* progress cell (dense bar; widths via the CDS pct-step attribute scale) */
.gsp-meter{display:inline-flex;align-items:center;gap:4px;white-space:nowrap}
.gsp-meter-track{width:60px;height:8px;border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);display:inline-block}
.gsp-meter-fill{height:100%;background:repeating-linear-gradient(90deg,var(--ds-c-blue-21) 0,var(--ds-c-blue-21) 6px,var(--ds-c-blue-16) 6px,var(--ds-c-blue-16) 8px);display:block}
.gsp-meter-fill[data-pct="0"]{width:0}.gsp-meter-fill[data-pct="5"]{width:5%}.gsp-meter-fill[data-pct="10"]{width:10%}.gsp-meter-fill[data-pct="15"]{width:15%}.gsp-meter-fill[data-pct="20"]{width:20%}.gsp-meter-fill[data-pct="25"]{width:25%}.gsp-meter-fill[data-pct="30"]{width:30%}.gsp-meter-fill[data-pct="35"]{width:35%}.gsp-meter-fill[data-pct="40"]{width:40%}.gsp-meter-fill[data-pct="45"]{width:45%}.gsp-meter-fill[data-pct="50"]{width:50%}.gsp-meter-fill[data-pct="55"]{width:55%}.gsp-meter-fill[data-pct="60"]{width:60%}.gsp-meter-fill[data-pct="65"]{width:65%}.gsp-meter-fill[data-pct="70"]{width:70%}.gsp-meter-fill[data-pct="75"]{width:75%}.gsp-meter-fill[data-pct="80"]{width:80%}.gsp-meter-fill[data-pct="85"]{width:85%}.gsp-meter-fill[data-pct="90"]{width:90%}.gsp-meter-fill[data-pct="95"]{width:95%}.gsp-meter-fill[data-pct="100"]{width:100%}

/* action wizard (MMDB-2260): source plan / generated proposal / versions */
/* Wizard generation progress — a real, staged read-out of a job that runs on
   the gateway for the best part of a minute, not a spinner. */
.gsp-progress{display:flex;align-items:center;gap:8px;margin:3px 3px 0;padding:2px 6px;border:1px solid var(--ds-c-blue-21);background:var(--ds-c-blue-03);font-size:11px}
.gsp-progress[data-state="done"]{border-color:var(--ds-c-green-09);background:var(--ds-c-green-02)}
.gsp-progress[data-state="failed"]{border-color:var(--ds-c-red-17);background:var(--ds-c-red-03)}
.gsp-progress-step{font-size:9px;font-weight:700;color:var(--ds-c-blue-32);border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);padding:0 4px;white-space:nowrap}
.gsp-progress[data-state="failed"] .gsp-progress-step{color:var(--ds-c-red-17)}
.gsp-progress-text{font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}
.gsp-progress-detail{font-weight:400;color:var(--ds-c-blue-30)}
.gsp-progress-bar{position:relative;flex:none;width:190px;height:12px;border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);overflow:hidden}
.gsp-progress-fill{position:absolute;left:0;top:0;bottom:0;width:0;background:repeating-linear-gradient(90deg,var(--ds-c-blue-21) 0 8px,var(--ds-c-blue-17) 8px 12px);transition:width .4s linear}
.gsp-progress[data-state="done"] .gsp-progress-fill{background:repeating-linear-gradient(90deg,var(--ds-c-green-09) 0 8px,var(--ds-c-green-06) 8px 12px)}
.gsp-progress[data-state="failed"] .gsp-progress-fill{background:repeating-linear-gradient(90deg,var(--ds-c-red-17) 0 8px,var(--ds-c-red-12) 8px 12px)}
.gsp-progress-pct{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;color:var(--ds-c-blue-32);mix-blend-mode:normal}
.gsp-progress-elapsed{font-variant-numeric:tabular-nums;color:var(--ds-c-neutral-13);white-space:nowrap;flex:none}
.gsp-progress-note{color:var(--ds-c-neutral-13);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:none}
.gsp-progress-fill[data-pct="0"]{width:0%}
.gsp-progress-fill[data-pct="5"]{width:5%}
.gsp-progress-fill[data-pct="10"]{width:10%}
.gsp-progress-fill[data-pct="15"]{width:15%}
.gsp-progress-fill[data-pct="20"]{width:20%}
.gsp-progress-fill[data-pct="25"]{width:25%}
.gsp-progress-fill[data-pct="30"]{width:30%}
.gsp-progress-fill[data-pct="35"]{width:35%}
.gsp-progress-fill[data-pct="40"]{width:40%}
.gsp-progress-fill[data-pct="45"]{width:45%}
.gsp-progress-fill[data-pct="50"]{width:50%}
.gsp-progress-fill[data-pct="55"]{width:55%}
.gsp-progress-fill[data-pct="60"]{width:60%}
.gsp-progress-fill[data-pct="65"]{width:65%}
.gsp-progress-fill[data-pct="70"]{width:70%}
.gsp-progress-fill[data-pct="75"]{width:75%}
.gsp-progress-fill[data-pct="80"]{width:80%}
.gsp-progress-fill[data-pct="85"]{width:85%}
.gsp-progress-fill[data-pct="90"]{width:90%}
.gsp-progress-fill[data-pct="95"]{width:95%}
.gsp-progress-fill[data-pct="100"]{width:100%}
@media (prefers-reduced-motion:reduce){.gsp-progress-fill{transition:none}}
/* Action tree (MMDB-2282) — a tracked action per row: its id, what kind of
   work it is, the text, who else it serves, its traction, and the controls to
   break it down or hand it over. Depth is a data attribute so app code never
   carries an inline indent. */
.gsp-card-head-spring{flex:1}
/* The action tree is a working list, not a side panel: it takes the whole
   width of the sheet grid so a row reads on one line. */
.gsp-sheet > .gsp-card-wide{grid-column:1 / -1}
.gsp-card-wide .gsp-card-body{max-height:340px;overflow:auto}
.gsp-action-node{display:flex;gap:6px;align-items:baseline;border-bottom:1px dotted var(--ds-c-yellow-15);padding:2px 4px;min-height:19px}
.gsp-action-node:hover{background:var(--ds-c-yellow-09)}
.gsp-action-node[data-depth="1"]{padding-left:22px}
.gsp-action-node[data-depth="2"]{padding-left:40px}
.gsp-action-node[data-depth="3"]{padding-left:58px}
.gsp-action-node[data-depth="4"]{padding-left:76px}
.gsp-action-node[data-depth="5"]{padding-left:94px}
.gsp-action-node[data-depth="6"]{padding-left:112px}
.gsp-action-node[data-depth="7"]{padding-left:130px}
.gsp-action-node[data-depth="8"]{padding-left:148px}
.gsp-action-node[data-depth="1"],.gsp-action-node[data-depth="2"],.gsp-action-node[data-depth="3"],
.gsp-action-node[data-depth="4"],.gsp-action-node[data-depth="5"],.gsp-action-node[data-depth="6"],
.gsp-action-node[data-depth="7"],.gsp-action-node[data-depth="8"]{border-left:1px solid var(--ds-c-yellow-20)}
.gsp-tree-toggle{font:inherit;font-size:9px;line-height:1;width:13px;height:13px;padding:0;flex:none;border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);color:var(--ds-c-blue-32);cursor:pointer}
.gsp-tree-toggle:hover{background:var(--ds-c-blue-07)}
.gsp-tree-leaf{width:13px;flex:none}
.gsp-action-id{font-size:10px;font-weight:700;color:var(--ds-c-blue-32);white-space:nowrap;flex:none;font-variant-numeric:tabular-nums}
.gsp-action-text{flex:1;min-width:0}
.gsp-action-shared{font-size:10px;color:var(--ds-c-amber-28);border:1px solid var(--ds-c-amber-23);background:var(--ds-c-yellow-19);padding:0 4px;white-space:nowrap;flex:none}
.gsp-select-tight{font-size:10px;padding:0 2px;max-width:118px;flex:none}
.gsp-action-add{display:flex;gap:6px;align-items:center;padding:3px 4px;border-bottom:1px solid var(--ds-c-neutral-06);background:var(--ds-c-yellow-05)}
.gsp-action-add .gsp-input{flex:1;min-width:0}
.gsp-action-add .gsp-select{flex:none;max-width:150px}
.gsp-wiz-section{display:flex;gap:6px;align-items:baseline;border-bottom:1px solid var(--ds-c-yellow-20);padding:2px 0 1px;margin-top:2px}
.gsp-wiz-section-count{font-size:10px;color:var(--ds-c-neutral-12)}
.gsp-wiz-section-spring{flex:1}
.gsp-wiz{display:grid;grid-template-columns:0.9fr 1.6fr 0.8fr;gap:3px;padding:3px;flex:1;min-height:0}
.gsp-wiz-col{border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);display:flex;flex-direction:column;min-height:0}
.gsp-wiz-item{display:flex;gap:6px;align-items:baseline;border-bottom:1px dotted var(--ds-c-yellow-20);padding:2px 4px;cursor:pointer}
.gsp-wiz-kind{font-size:9px;border:1px solid var(--ds-c-neutral-06);padding:0 3px;white-space:nowrap;background:var(--ds-c-white-01)}
.gsp-wiz-kind[data-k="task"]{background:var(--ds-c-green-04);border-color:var(--ds-c-green-09)}
.gsp-wiz-kind[data-k="research"]{background:var(--ds-c-blue-07);border-color:var(--ds-c-blue-21)}
.gsp-wiz-kind[data-k="gap"]{background:var(--ds-c-yellow-19);border-color:var(--ds-c-amber-23)}
.gsp-wiz-kind[data-k="people"]{background:var(--ds-c-neutral-02);border-color:var(--ds-c-neutral-08)}
.gsp-version{border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-yellow-05);padding:3px 6px;cursor:pointer;display:block;width:100%;text-align:left;font:inherit;margin-bottom:3px}
.gsp-version[data-active="true"]{border:2px solid var(--ds-c-blue-24);background:var(--ds-c-blue-04)}
.gsp-version-meta{display:block;font-size:10px;color:var(--ds-c-neutral-10)}

/* popup record layout (XP popup kit) */
.gsp-record{display:flex;flex-direction:column}
.gsp-record-fields{display:grid;grid-template-columns:1fr 1fr;gap:1px 10px}
.gsp-record-field{display:flex;gap:6px;align-items:baseline;border-bottom:1px dotted var(--ds-c-yellow-15);padding:1px 0;min-width:0}
.gsp-record-field[data-wide="true"]{grid-column:span 2}
.gsp-record-field[data-empty="true"]{opacity:.55}
.gsp-record-field-l{flex:0 0 120px;color:var(--ds-c-neutral-13);font-size:10px;text-transform:uppercase;letter-spacing:.03em}
.gsp-record-field-v{min-width:0;overflow-wrap:anywhere}
.gsp-record-lead{display:flex;justify-content:space-between;align-items:baseline;gap:10px;border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-yellow-05);padding:3px 6px;margin:0 0 3px}
.gsp-record-lead[data-tone="warn"]{background:var(--ds-c-yellow-19);border-color:var(--ds-c-amber-23)}
.gsp-record-lead[data-tone="alert"]{background:var(--ds-c-red-08);border-color:var(--ds-c-red-17)}
.gsp-record-lead-id{min-width:0}
.gsp-record-lead-flag{display:flex;gap:5px;align-items:baseline;white-space:nowrap}

/* the id chip sits on the blue titlebar: keep its ink dark (UX round 1: white-on-white made it invisible) */
.gsp-titlebar .gsp-headcell{color:var(--ds-c-blue-32);background:var(--ds-c-yellow-13);font-weight:700}
/* dense popup form grid (UX round 1: letterbox fields inside an XP dialog) */
.gsp-field-row-2{display:grid;grid-template-columns:1fr 1fr;gap:2px 10px;padding:2px 0}
.gsp-field{display:flex;flex-direction:column;gap:1px;min-width:0}
.gsp-field-span-2{grid-column:span 2}
.gsp-label{font-size:10px;color:var(--ds-c-neutral-13);text-transform:uppercase;letter-spacing:.03em}
.gsp-field .gsp-input,.gsp-field .gsp-select,.gsp-field .gsp-textarea{flex:none;width:100%}
.gsp-field .gsp-textarea{min-height:44px}

/* dock clearance (UX round 2): the portal's floating agent dock sits bottom-
   right and covered the dialog's primary action — reserve its width so
   [ Save ] / [ Submit ] are never under it. */
.gsp-dialog .gsp-btnrow{padding-right:150px}
.gsp-statusbar{padding-right:150px}
.gsp-sheet > .gsp-card:last-child .gsp-card-body,
.gsp-matrix .gsp-mcol:last-child .gsp-pane-foot,
.gsp-wiz .gsp-wiz-col:last-child .gsp-mcol-body{padding-bottom:52px}

/* ------------------------------------------------------------------ */
/* Order Management additions (2026-08-22) — the second app in this    */
/* language. Semantic objects only, added to the shared skin so the    */
/* app itself stays a pointer: order documents, line grids with a      */
/* reference sub-row, typeahead pickers, notes, and the step strip.    */

/* a document dialog is wider than a record dialog: an order line grid
   carries product, qty, price, total and a decision on one row */
.gsp-dialog-wide{width:min(1180px,96vw)}

/* three-across field row for the commercial terms blocks */
.gsp-field-row-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:2px 10px;padding:2px 0}
.gsp-field-row-4{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:2px 10px;padding:2px 0}
.gsp-field[data-span="true"]{grid-column:1 / -1}

/* inline note: why a step cannot go yet, or a fact the user must read */
.gsp-note{border:1px solid var(--ds-c-amber-23);background:var(--ds-c-yellow-19);color:var(--ds-c-yellow-26);padding:3px 6px;margin:3px}
.gsp-note[data-tone="stop"]{border-color:var(--ds-c-red-17);background:var(--ds-c-red-08);color:var(--ds-c-red-26);font-weight:700}
.gsp-note[data-tone="info"]{border-color:var(--ds-c-blue-21);background:var(--ds-c-blue-07);color:var(--ds-c-blue-32)}
.gsp-note-title{font-weight:700;margin-right:6px}

/* the order document: header facts over the line grid, inside a dialog */
.gsp-doc{display:flex;flex-direction:column;gap:3px;padding:3px}
.gsp-doc-strip{display:flex;flex-wrap:wrap;gap:6px;align-items:baseline;border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-yellow-05);padding:3px 6px}
.gsp-doc-strip-cell{display:flex;gap:5px;align-items:baseline;white-space:nowrap}
.gsp-doc-strip-l{font-size:10px;color:var(--ds-c-neutral-13);text-transform:uppercase;letter-spacing:.03em}
.gsp-doc-strip-v{font-weight:700}
.gsp-doc-note{border:1px solid var(--ds-c-yellow-20);background:var(--ds-c-yellow-07);padding:2px 6px;color:var(--ds-c-neutral-18)}

/* totals under a line grid — the money, right-aligned, one strong figure */
.gsp-totals{display:flex;justify-content:flex-end;gap:14px;align-items:baseline;border-top:1px solid var(--ds-c-neutral-06);background:var(--ds-c-yellow-13);padding:3px 6px;flex-wrap:wrap}
.gsp-totals-item{display:flex;gap:5px;align-items:baseline;white-space:nowrap}
.gsp-totals-l{font-size:10px;color:var(--ds-c-neutral-13);text-transform:uppercase;letter-spacing:.03em}
.gsp-totals-v{font-variant-numeric:tabular-nums}
.gsp-totals-item[data-strong="true"] .gsp-totals-v{font-weight:700;font-size:13px;color:var(--ds-c-blue-32)}

/* line grid: the muted reference row under a line (floor, cost, margin) */
.gsp-grid tr[data-ref="true"] td{background:var(--ds-c-yellow-05);border-bottom:1px solid var(--ds-c-neutral-06);padding:1px 5px}
.gsp-grid tr[data-ref="true"]:hover td{background:var(--ds-c-yellow-05)}
.gsp-ref-item{display:inline-flex;gap:4px;align-items:baseline;margin-right:10px;font-size:10px}
.gsp-ref-l{color:var(--ds-c-neutral-10);text-transform:uppercase;letter-spacing:.03em}
.gsp-ref-v{font-variant-numeric:tabular-nums}
.gsp-ref-v[data-tone="bad"]{color:var(--ds-c-red-22);font-weight:700}
.gsp-ref-v[data-tone="warn"]{color:var(--ds-c-amber-28);font-weight:700}
.gsp-ref-v[data-tone="good"]{color:var(--ds-c-green-12)}
.gsp-line-code{display:block;font-size:9px;color:var(--ds-c-neutral-10);font-family:var(--font-mono)}
.gsp-line-note{font-size:10px;color:var(--ds-c-neutral-13)}
.gsp-line-note[data-tone="bad"]{color:var(--ds-c-red-22);font-weight:700}

/* typeahead picker — dealer and product, over a live SAP search */
.gsp-picker{position:relative;display:flex;flex-direction:column;gap:1px;min-width:0}
.gsp-picker-chosen{display:flex;gap:6px;align-items:baseline;border:1px solid var(--ds-c-blue-13);background:var(--ds-c-white-01);padding:1px 3px;min-width:0}
.gsp-picker-chosen-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gsp-picker-change{border:1px solid var(--hairline-dark);background:var(--paper-2);color:var(--ink);font-family:var(--ds-font-window);font-size:10px;padding:1px 6px;cursor:pointer;flex:none;border-radius:var(--ds-radius-sm)}
.gsp-picker-change:hover{background:var(--paper);border-color:var(--ink-mute)}
.gsp-picker-list{position:absolute;top:100%;left:0;right:0;z-index:30;max-height:220px;overflow:auto;border:1px solid var(--ds-c-blue-32);background:var(--ds-c-white-01);box-shadow:2px 2px 4px rgba(0,0,0,.35)}
.gsp-picker-option{display:block;width:100%;text-align:left;font:inherit;border:0;border-bottom:1px dotted var(--ds-c-yellow-20);background:var(--ds-c-white-01);padding:2px 5px;cursor:pointer}
.gsp-picker-option:hover{background:var(--ds-c-blue-21);color:var(--ds-c-white-01)}
.gsp-picker-option-meta{display:block;font-size:10px;color:var(--ds-c-neutral-10)}
.gsp-picker-option:hover .gsp-picker-option-meta{color:var(--ds-c-blue-05)}
.gsp-picker-note{font-size:10px;color:var(--ds-c-neutral-10)}
.gsp-picker-note[data-tone="bad"]{color:var(--ds-c-red-22)}
.gsp-input[data-attention="true"],.gsp-select[data-attention="true"]{border-color:var(--ds-c-red-17);background:var(--ds-c-white-03)}

/* step strip: where the order stands in its own process */
.gsp-steps{display:flex;flex-wrap:wrap;gap:2px;align-items:center;padding:2px 3px}
.gsp-step{font-size:10px;border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);padding:0 5px;white-space:nowrap;color:var(--ds-c-neutral-12)}
.gsp-step[data-state="done"]{background:var(--ds-c-green-04);border-color:var(--ds-c-green-09);color:var(--ds-c-green-12)}
.gsp-step[data-state="now"]{background:var(--ds-c-blue-24);border-color:var(--ds-c-blue-32);color:var(--ds-c-white-01);font-weight:700}

/* terms box + tick — the dealer's explicit act before an order binds */
.gsp-terms{border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);margin:3px;padding:3px 6px}
.gsp-terms-title{font-weight:700;color:var(--ds-c-blue-32)}
.gsp-terms-text{max-height:120px;overflow:auto;border:1px inset var(--ds-c-amber-11);background:var(--ds-c-yellow-07);padding:3px 5px;margin:2px 0;white-space:pre-wrap}
.gsp-tick{display:flex;gap:5px;align-items:baseline}

/* dealer portal catalogue: dense card list, not a tile wall */
.gsp-cat{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:3px;padding:3px}
.gsp-cat-item{border:1px solid var(--ds-c-neutral-06);background:var(--ds-c-white-01);padding:3px 6px;display:flex;flex-direction:column;gap:1px;text-align:left;font:inherit;cursor:pointer}
.gsp-cat-item:hover{background:var(--ds-c-yellow-09)}
.gsp-cat-name{font-weight:700}
.gsp-cat-meta{font-size:10px;color:var(--ds-c-neutral-10)}
.gsp-cat-price{font-variant-numeric:tabular-nums;color:var(--ds-c-blue-32);font-weight:700}

/* Gaps found while the order screens were being built (2026-08-22): a cell
   that carries more than one status chip, and a sortable header that must
   show which way it is sorted. Both were being worked around in app code,
   which is exactly what this layer exists to prevent. */
.gsp-chips{display:inline-flex;gap:3px;align-items:baseline;flex-wrap:wrap}
.gsp-grid th[data-sort]{padding-right:14px;position:relative}
.gsp-grid th[data-sort="asc"]::after{content:"\25B2";position:absolute;right:4px;font-size:8px;color:var(--ds-c-blue-32)}
.gsp-grid th[data-sort="desc"]::after{content:"\25BC";position:absolute;right:4px;font-size:8px;color:var(--ds-c-blue-32)}
/* a sub-line inside a tight cell: the ellipsis lives on the line, not the cell */
.gsp-cell-sub{display:block;font-size:10px;color:var(--ds-c-neutral-10);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* Procurement2 floating desktop (Ben 2026-08-22: "every main-menu
   destination opens as a WINDOW... several stay open at once... resizable,
   minimizable, repositionable"). DEAD as of 2026-08-30 (Ben: "turn these
   into tabs... we abandon the always floating windows") -- procurement2's
   top-level screens are `.gsp-tabpane` tabs now (see pxp.tsx), never this
   `.gsp-app--floating`/`.gsp-desktop-layer` chrome, and nothing in src/
   renders these classes any more. Left in place rather than deleted
   (no-deletion-of-working-code default) but not consumed by anything.
   CORRECTION 2026-08-31: this comment used to claim "the shell's generic
   ds-window chrome never built minimize/maximize" as the reason these
   classes existed -- WindowChrome.tsx now DOES carry minimize + maximize
   itself (every window it renders, docked to the whole work area), so that
   claim would be actively wrong left as written. */
.gsp-desktop-layer{position:fixed;inset:0;z-index:45;pointer-events:none}
.gsp-app--floating{position:fixed;left:var(--win-x,80px);top:var(--win-y,80px);width:var(--win-w,960px);height:var(--win-h,620px);z-index:var(--win-z,45);pointer-events:auto;box-shadow:2px 2px 10px rgba(0,0,0,.35)}
.gsp-app--floating.gsp-app--minimized{display:none}
.gsp-app--floating .gsp-window{height:100%}
.gsp-titlebar[data-draggable="true"]{cursor:move;user-select:none}
/* resize grip, bottom-right corner of a floating window only */
.gsp-window-resize{position:absolute;right:0;bottom:0;width:14px;height:14px;cursor:nwse-resize;background:repeating-linear-gradient(135deg,var(--ds-c-neutral-06) 0,var(--ds-c-neutral-06) 1px,transparent 1px,transparent 4px)}

/* taskbar -- always visible while inside the procurement2 app, real XP
   taskbar language (dark gradient bar, pressed-in look for the active
   window's chip). Chips restore a minimized window or bring one to front;
   Settings lives at the right end, same place a systray sits.

   CORRECTION 2026-08-22 (real root cause of "Settings never opens", found
   via a real Playwright trace, not guesswork): the shell's own Yarnball/
   CoFlow dock (.cowork-dock, globals.css) is `position:fixed; top:0; right:0;
   bottom:0` -- FULL VIEWPORT HEIGHT -- with `pointer-events:auto` and
   z-index:60, EVEN WHILE COLLAPSED (AgentDock.tsx COLLAPSED_W = 40px, never
   0). Because this taskbar was flush against the same right edge
   (`right:0`), its rightmost element (Settings) sat physically UNDER that
   permanent 40px strip: every real click -- even a Playwright forced click
   that bypasses the actionability check -- was delivered to the dock
   overlay, not the button underneath it. The taskbar chips' own overflow
   scrolling (below) never running off-screen was a red herring; the button
   was on-screen and "clickable" by inspection, just permanently covered.
   Mirrors the existing `.shell > .body { margin-right: var(--cowork-dock-w,
   0px); }` pattern (globals.css) so this taskbar keeps clear of the same
   reserved strip whether the dock is collapsed or expanded. */
.gsp-taskbar{position:fixed;left:0;right:var(--cowork-dock-w,0px);bottom:0;z-index:46;pointer-events:auto;display:flex;align-items:center;gap:3px;padding:3px 6px;background:linear-gradient(180deg,var(--ds-c-blue-20) 0%,var(--ds-c-blue-26) 50%,var(--ds-c-blue-28) 100%);border-top:1px solid var(--ds-c-blue-32);font-family:var(--font-ui);font-size:11px}
/* Chips scroll horizontally inside their own strip -- as MORE windows open,
   the row never pushes Settings (or later chips) past the viewport edge the
   way an unconstrained nowrap flex row did (confirmed live with 4 windows
   open: Settings ran off-screen). Settings itself stays a fixed, never-
   shrinking, always-reachable element outside the scroll area, same as a
   real OS taskbar's system tray never scrolling away with running apps. */
.gsp-taskbar-chips{display:flex;gap:3px;overflow-x:auto;flex:1;min-width:0;scrollbar-width:thin}
.gsp-taskbar-chip{font:inherit;color:var(--ds-c-white-01);background:linear-gradient(180deg,var(--ds-c-blue-15) 0%,var(--ds-c-blue-23) 100%);border:1px solid var(--ds-c-blue-32);border-radius:var(--ds-radius-sm);padding:2px 10px;cursor:pointer;max-width:220px;flex:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gsp-taskbar-chip:hover{background:linear-gradient(180deg,var(--ds-c-blue-12) 0%,var(--ds-c-blue-19) 100%)}
.gsp-taskbar-chip[data-active="true"]{background:linear-gradient(180deg,var(--ds-c-blue-27) 0%,var(--ds-c-blue-28) 100%);box-shadow:inset 1px 1px 2px rgba(0,0,0,.5)}
.gsp-taskbar-settings{font:inherit;color:var(--ds-c-white-01);background:linear-gradient(180deg,var(--ds-c-blue-15) 0%,var(--ds-c-blue-23) 100%);border:1px solid var(--ds-c-blue-32);border-radius:2px;padding:2px 12px;cursor:pointer;flex:none;margin-left:3px}
.gsp-taskbar-settings:hover{background:linear-gradient(180deg,var(--ds-c-blue-12) 0%,var(--ds-c-blue-19) 100%)}

/* App-level screen switcher, TOP bar (Ben 2026-08-22, explicit: "why would
   every page open a new popup with the whole main navigation" -- the
   eleven-screen menu used to render inside every open window, once per
   window; three windows open drew it three times -- THEN, on layout: "the
   main navigation must always stay at the top, not in the popups... put the
   main navigation at the top left to open a new item or create a new
   transaction... put Purchase or Master Data on the right"). One persistent
   bar, never inside a window: "New" trigger + flyout at top-left, direct
   quick-links to the highest-frequency browse destinations at top-right.
   z-index sits ABOVE the WindowManager's own z-order (WINDOW_Z_BASE=100,
   incrementing per focus) -- unlike .gsp-taskbar below (z-index 46, already
   under every floating window), this bar carries Ben's literal "must always
   stay at the top" requirement, so it is pinned above normal window
   stacking instead of sharing the taskbar's tier. */
.gsp-topbar{position:fixed;left:0;right:var(--cowork-dock-w,0px);top:0;z-index:200;pointer-events:auto;display:flex;align-items:center;justify-content:space-between;gap:6px;padding:3px 6px;background:linear-gradient(180deg,var(--ds-c-blue-20) 0%,var(--ds-c-blue-26) 50%,var(--ds-c-blue-28) 100%);border-bottom:1px solid var(--ds-c-blue-32);font-family:var(--font-ui);font-size:11px}
.gsp-topbar-left,.gsp-topbar-right{display:flex;align-items:center;gap:4px;min-width:0}
.gsp-topbar-new{font-family:var(--ds-font-window);font-weight:600;color:var(--paper);background:var(--baobab);border:1px solid var(--baobab);border-radius:var(--ds-radius-sm);padding:4px 14px;cursor:pointer;flex:none;box-shadow:inset 0 -1px 0 rgba(0,0,0,.18)}
.gsp-topbar-new:hover{background:color-mix(in srgb, var(--baobab) 88%, black)}
.gsp-topbar-new[data-open="true"]{background:color-mix(in srgb, var(--baobab) 80%, black);box-shadow:inset 0 1px 3px rgba(0,0,0,.35)}
.gsp-topbar-link{font-family:var(--ds-font-window);color:var(--paper);background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.32);border-radius:var(--ds-radius-sm);padding:4px 10px;cursor:pointer;flex:none;white-space:nowrap}
.gsp-topbar-link:hover{background:rgba(255,255,255,.28)}
/* Flyout hangs below the top-left New button; the transparent full-viewport
   catcher behind it closes the menu on any outside click -- catcher's
   z-index sits below the flyout's so clicks inside the flyout itself are
   unaffected, and above .gsp-topbar so it also catches a click back onto
   the New button itself (closing, not re-toggling open, on that click). */
.gsp-startmenu-catcher{position:fixed;inset:0;z-index:200;background:transparent;pointer-events:auto}
.gsp-startmenu{position:fixed;left:6px;top:28px;z-index:210;background:var(--ds-c-yellow-13);border:1px solid var(--ds-c-blue-32);box-shadow:2px 2px 6px rgba(0,0,0,.45);display:flex;flex-direction:column;padding:2px;min-width:230px;max-height:80vh;overflow-y:auto;pointer-events:auto}
/* Section headers + dividers group the flyout (Ben: "Agreements and
   supplier admin should be in separate places") -- PROC_MENU_SECTIONS in
   nav.ts is the grouping; these two classes are just its visual expression. */
.gsp-startmenu-section{padding:3px 8px 1px;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--ds-c-neutral-12)}
.gsp-startmenu-divider{border-top:1px solid var(--ds-c-yellow-23);margin:2px 4px}

/* Classic expanding menus in the menu bar (OmMenu): the trigger reads
   "Name  Value ▾"; the panel is a paper sheet that drops under it. Master
   Data's global Domain / Data type scope lives in these (MMDB-2407). */
.gsp-menu-drop{position:relative;display:inline-flex;flex:none}
.gsp-menu-drop>.gsp-menu{display:inline-flex;align-items:center;gap:5px;border:0;background:transparent;font:inherit}
.gsp-menu-name{font-weight:700}
.gsp-menu-value{color:inherit;opacity:.85;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gsp-menu-caret{font-size:9px;opacity:.75}
.gsp-menu-panel{position:absolute;left:0;top:100%;z-index:60;min-width:190px;max-height:60vh;overflow:auto;background:var(--ds-c-white-01);border:1px solid var(--ds-c-neutral-06);box-shadow:2px 2px 0 var(--ds-c-yellow-25);padding:2px;display:flex;flex-direction:column}
.gsp-menu-item{display:flex;align-items:center;gap:6px;text-align:left;border:0;background:transparent;font:inherit;padding:3px 10px 3px 6px;cursor:pointer;white-space:nowrap;color:var(--ds-c-black-02)}
.gsp-menu-item:hover,.gsp-menu-item:focus-visible{background:var(--ds-c-blue-21);color:var(--ds-c-white-01);outline:none}
.gsp-menu-item[data-on="true"]{font-weight:700}
.gsp-menu-item:disabled{color:var(--ds-c-neutral-06);cursor:default;background:transparent}
.gsp-menu-item-mark{display:inline-block;width:10px;text-align:center;font-size:10px}
.gsp-menubar-sep{width:1px;align-self:stretch;background:var(--ds-c-yellow-25);margin:1px 4px}
/* The app's scope group (what you are working on) sits in its own sunken
   frame at the head of the bar, apart from the screen entries that follow. */
.gsp-menubar-scope{display:inline-flex;align-items:center;gap:2px;flex:none;padding:0 3px;margin:0 2px 0 0;background:var(--ds-c-yellow-06);border:1px solid var(--ds-c-yellow-25);box-shadow:inset 1px 1px 0 var(--ds-c-white-01)}
.gsp-menubar-scope>.gsp-menu-drop+.gsp-menu-drop{border-left:1px solid var(--ds-c-yellow-21);padding-left:2px}


/* Controls in this structural layer that painted a box but never declared a
   radius, so they rendered square while the rest of the portal moved to the
   locked 4px. Found by measuring computed style on Procurement, Order
   Management and Strategy signed-in. These are definitions, not overrides:
   none of these rules set a radius anywhere. */
.gsp-tool,
.gsp-select,
.gsp-taskbar-settings { border-radius: var(--ds-radius-sm); }

/* Screen tabs (Ben, 2026-08-30 hand-annotation: "turn these into tabs",
   "launch as tabs only, we abandon the always floating windows", "max as
   per disply/window"). A `kind: "screen"` window (windows.tsx) no longer
   floats -- exactly one is ever current, filling the whole work area with
   no computed geometry. `data-eid="om-desktop"` names the OmAppFrame work
   area (order-mgmt/_lib/windows.tsx) -- the ONE component every consumer of
   it renders (Order Management itself, Master Data, the Dealer Portal
   popup, and Strategy's own tabbed desktop, which reuses the identical
   OmAppFrame under its `.slp` skin via a `wrapperClassName` prop rather
   than duplicating this file). `data-eid="proc-desktop"` names the
   equivalent work area in procurement2's OWN separate desktop
   (ProcDesktop.tsx / pxp.tsx), which does not use OmAppFrame at all but
   needed the identical CSS-only override. Both selectors are scoped
   tightly enough to leave the base `.gsp-matrix` rule above alone for its
   other, unrelated consumers -- Strategy's own Why-What-How matrix
   (MatrixSurface, a `.gsp-matrix` element rendered INSIDE one of its tab
   panes, carrying neither eid) chief among them. A record popup (kind:
   "record") still floats over either desktop exactly as before --
   position:fixed is set on its own node by OmWindowFrame, unaffected by
   the desktop's own display mode. */
.gsp-matrix[data-eid="om-desktop"],
.gsp-matrix[data-eid="proc-desktop"] { display: block; grid-template-columns: none; }
.gsp-tabpane{position:absolute;inset:0;display:none;flex-direction:column;min-height:0;min-width:0}
.gsp-tabpane[data-current="true"]{display:flex}

/* Record tabs (Ben, 2026-08-31: "we have generally abandoned the always
   popup design, make it tab that can be disconnected and turned into
   windows, for all pages/apps"). A record popup (order-mgmt windows.tsx
   `kind: "record"`, procurement2's own local record registry) now opens
   DOCKED by default: a tab in the SAME strip as the screens, visually
   distinct from a screen tab because it carries its own reference text
   PLUS an inline close × (a screen tab is never closeable). `.gsp-menu`
   supplies the base tab look; `.gsp-menu-record` only adjusts the padding
   to make room for the close button sitting inside it. `data-active` reuses
   the existing `.gsp-menu[data-active="true"]` rule above -- one active
   look for every tab, screen or record. */
.gsp-menu-record{display:inline-flex;align-items:center;gap:2px;padding:1px 3px 1px 2px}
.gsp-menu-record-label{font:inherit;color:inherit;background:transparent;border:0;padding:2px 6px;cursor:pointer}
.gsp-menu-close{font:inherit;display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:0;background:transparent;color:inherit;opacity:.7;cursor:pointer;border-radius:var(--ds-radius-sm);flex:none}
.gsp-menu-close:hover{opacity:1;background:rgba(0,0,0,.15)}
.gsp-menu-close svg{display:block;width:9px;height:9px}
.gsp-menu-record[data-active="true"] .gsp-menu-close:hover{background:rgba(255,255,255,.25)}
