/* ===========================================================================
   panel.css - the Gate-E Admin Panel design, as classes.

   Source: old_project/Design update_ old site to new/Gate-E Admin Panel.dc.html
   (Claude Design handoff bundle). The prototype writes every rule as an inline
   style on a React element; this file is the same visual output expressed once,
   so the Smarty templates under boxs/ carry markup and not a style attribute.

   Everything is prefixed .gp- (Gate-E panel) and every colour is a token from
   global.css, so the panel follows the light/dark switch and the per-system
   accent without a second palette living here.

   Loaded after components.css and before utilities.css - see
   sections/start-page.html. The page bodies that use these classes carry no
   bootstrap markup, so there is nothing for the utility layer to override.
   =========================================================================== */


/* ===== Page head =========================================================
   The title block every screen opens with: heading, one line of prose, then a
   right-aligned cluster of search / filter / action controls. */

.gp-head{display:flex;align-items:flex-end;gap:20px;row-gap:14px;flex-wrap:wrap;margin:0 0 24px}
.gp-head h1{margin:0;font-size:27px;font-weight:600;letter-spacing:-.025em;line-height:1.2}
.gp-head p{margin:8px 0 0;font-size:13.5px;color:var(--text-3)}
.gp-head-grow{flex:1 1 auto}

/* The back link above a detail screen's title. */
.gp-back{display:inline-flex;align-items:center;gap:8px;margin:0 0 18px;padding:0;border:none;background:none;font-size:13px;font-weight:500;color:var(--text-3);cursor:pointer}
.gp-back:hover{color:var(--accent);text-decoration:none}

/* The square icon button that opens a form screen (design: back arrow). */
.gp-back-box{display:grid;place-items:center;width:34px;height:34px;flex:0 0 34px;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:var(--text-2);cursor:pointer}
.gp-back-box:hover{color:var(--text);border-color:var(--text-3)}


/* ===== Search box ========================================================
   Icon sits inside the field, so the input carries the left padding rather
   than the icon carrying a margin - otherwise a long value runs under it. */

.gp-search{position:relative;width:270px;max-width:100%}
.gp-search .gp-search-ic{position:absolute;top:50%;left:12px;transform:translateY(-50%);display:grid;color:var(--text-3);pointer-events:none}
.gp-search input{width:100%;height:40px;padding:0 12px 0 36px;background:var(--field);border:1px solid var(--field-b);border-radius:7px;font-size:13.5px}
[dir="rtl"] .gp-search .gp-search-ic{left:auto;right:12px}
[dir="rtl"] .gp-search input{padding:0 36px 0 12px}


/* ===== Buttons ===========================================================
   Three weights, all 40px on a list screen and 42px in a form footer. */

.gp-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:0 15px;height:40px;border:1px solid var(--border);border-radius:7px;background:var(--surface);font-size:13.5px;font-weight:500;color:var(--text-2);white-space:nowrap;cursor:pointer;text-decoration:none}
.gp-btn:hover{color:var(--text);border-color:var(--text-3);text-decoration:none}

.gp-btn-primary{padding:0 17px;border:none;background:var(--accent);font-weight:600;color:var(--accent-fg)}
.gp-btn-primary:hover{filter:brightness(1.14);color:var(--accent-fg);border-color:transparent}

/* Reads as a link but sits in a row of buttons - "Resend", "New invoice" on a
   client row. Keeps the border so the row stays on one baseline grid. */
.gp-btn-accent{font-weight:600;color:var(--accent)}
.gp-btn-accent:hover{background:var(--accent-soft);color:var(--accent);border-color:var(--border)}

.gp-btn-block{width:100%}

/* Row actions: the 28px icon-only buttons at the end of a table row. */
.gp-rowacts{display:flex;align-items:center;justify-content:flex-end;gap:2px}
.gp-iconbtn{display:grid;place-items:center;width:28px;height:28px;flex:0 0 28px;border:none;border-radius:6px;background:none;color:var(--text-4);cursor:pointer;text-decoration:none}
.gp-iconbtn:hover{color:var(--accent);background:var(--accent-soft);text-decoration:none}
.gp-iconbtn-danger:hover{color:var(--err);background:var(--err-soft)}


/* ===== KPI band ==========================================================
   Four cards across on desktop, two on a tablet, one on a phone. The value is
   tabular and clipped rather than wrapped: a KPI that reflows to two lines
   pushes the row below it out of alignment. */

.gp-kpis{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin:0 0 24px}
.gp-kpi{padding:18px 20px;background:var(--surface);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-sm)}
.gp-kpi-label{font-size:11.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--text-3)}
.gp-kpi-value{margin:12px 0 0;font-size:20px;font-weight:600;letter-spacing:-.03em;font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gp-kpi-sub{margin:6px 0 0;font-size:12.5px;color:var(--text-3)}
.gp-kpi-warn .gp-kpi-value{color:var(--warn)}
.gp-kpi-err .gp-kpi-value{color:var(--err)}
.gp-kpi-accent .gp-kpi-value{color:var(--accent)}


/* ===== Filter chips ======================================================
   The status row above a list. The count is part of the chip, in a lighter
   weight, so scanning for "how many are pending" needs no second element. */

.gp-chips{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 16px}
.gp-chip{display:inline-flex;align-items:center;gap:8px;padding:7px 13px;border:1px solid var(--border);border-radius:999px;background:var(--surface);font-size:12.5px;font-weight:500;color:var(--text-2);cursor:pointer;text-decoration:none}
.gp-chip:hover{text-decoration:none;color:var(--text)}
.gp-chip .gp-chip-n{font-size:11px;font-weight:600;color:var(--text-3)}
.gp-chip.is-on{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
.gp-chip.is-on .gp-chip-n{color:var(--accent)}


/* ===== Card ==============================================================
   The surface every table, panel and sidebar block sits on. .gp-card-head is
   the small uppercase strip; .gp-card-title is the larger one a modal uses. */

.gp-card{background:var(--surface);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-sm);overflow:hidden}
.gp-card+.gp-card{margin-top:20px}
.gp-card-head{padding:14px 20px;border-bottom:1px solid var(--border-2);background:var(--surface-3);font-size:11px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--text-3)}
.gp-card-body{padding:22px 20px}
.gp-card-foot{padding:13px 20px;border-top:1px solid var(--border-2);font-size:12.5px;color:var(--text-3)}

/* A card whose body is plain padding and whose head is a bare label rather
   than a strip - the right-hand rail on the detail screens. */
.gp-panel{padding:20px;background:var(--surface);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-sm)}
.gp-panel-label{font-size:11px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--text-3)}


/* ===== Table =============================================================
   Header cells are small caps in --text-3; body rows separate on --border-2
   and light up on --surface-3. Numeric columns are tabular and right-aligned.

   .gp-tablewrap is what scrolls, never the page - see CLAUDE.md. */

.gp-tablewrap{overflow-x:auto}
.gp-table{width:100%;border-collapse:collapse;font-size:13.5px}
.gp-table th{padding:14px 16px;border-bottom:1px solid var(--border-2);text-align:left;font-size:11.5px;font-weight:600;color:var(--text-3);white-space:nowrap}
.gp-table td{padding:14px 16px;border-bottom:1px solid var(--border-2);vertical-align:middle}
.gp-table th:first-child,.gp-table td:first-child{padding-left:20px}
.gp-table th:last-child,.gp-table td:last-child{padding-right:20px}
.gp-table tbody tr:hover{background:var(--surface-3)}
.gp-table tbody tr.gp-row-link{cursor:pointer}
[dir="rtl"] .gp-table th{text-align:right}
[dir="rtl"] .gp-table th:first-child,[dir="rtl"] .gp-table td:first-child{padding-left:16px;padding-right:20px}
[dir="rtl"] .gp-table th:last-child,[dir="rtl"] .gp-table td:last-child{padding-right:16px;padding-left:20px}

.gp-num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.gp-table th.gp-num,.gp-table td.gp-num{text-align:right}
[dir="rtl"] .gp-table th.gp-num,[dir="rtl"] .gp-table td.gp-num{text-align:left}
.gp-amount{font-size:14px;font-weight:600}
.gp-total{font-size:19px;font-weight:600;letter-spacing:-.02em}

/* The two-line cell: a strong primary line over a muted secondary one. */
.gp-cell-1{font-size:13.5px;font-weight:600}
.gp-cell-2{margin:4px 0 0;font-size:12px;color:var(--text-3)}
.gp-cell-mono{font-family:var(--mono);font-size:13px;font-weight:600}
.gp-muted{color:var(--text-3)}
.gp-faint{color:var(--text-4)}

/* Empty state - a table that matched nothing says so in its own body. */
.gp-empty{padding:60px 20px;text-align:center;font-size:14px;color:var(--text-3)}
.gp-empty-strong{font-size:15px;font-weight:600;color:var(--text)}

/* Arabic column - the design sets these RTL and right-aligned per cell. */
.gp-ar{font-family:var(--font-ar);font-size:13.5px;color:var(--text-2);text-align:right}
[dir="rtl"] .gp-ar{text-align:right}


/* ===== Status pill =======================================================
   Dot + label. The dot takes the text colour, so one modifier sets both. */

.gp-pill{display:inline-flex;align-items:center;gap:7px;padding:4px 11px 4px 8px;border:1px solid transparent;border-radius:999px;font-size:11.5px;font-weight:600;white-space:nowrap}
.gp-pill .gp-dot{width:6px;height:6px;flex:0 0 6px;border-radius:50%;background:currentColor}
button.gp-pill{cursor:pointer}
.gp-pill-ok{background:var(--ok-soft);color:var(--ok)}
.gp-pill-warn{background:var(--warn-soft);color:var(--warn)}
.gp-pill-err{background:var(--err-soft);color:var(--err)}
.gp-pill-accent{background:var(--accent-soft);color:var(--accent)}
.gp-pill-mute{background:var(--surface-2);border-color:var(--border);color:var(--text-3)}

/* The square tag - department, payment method, "used in" table. */
.gp-tag{display:inline-block;padding:3px 9px;border-radius:5px;background:var(--surface-2);font-size:11.5px;font-weight:600;color:var(--text-2)}
.gp-tag-accent{background:var(--accent-soft);color:var(--accent)}

/* Round initials avatar. */
.gp-ini{display:grid;place-items:center;width:34px;height:34px;flex:0 0 34px;border-radius:999px;background:var(--surface-2);font-size:12px;font-weight:600;color:var(--text-2)}
.gp-ini-lg{width:52px;height:52px;flex-basis:52px;font-size:16px}
.gp-ini-md{width:40px;height:40px;flex-basis:40px;font-size:13px}


/* ===== Two-column detail layout ==========================================
   Main column plus a 372px rail, collapsing to one column under 1100px. */

.gp-split{display:grid;grid-template-columns:minmax(0,1fr) 372px;gap:20px;align-items:start}
.gp-split-even{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
.gp-stack{display:flex;flex-direction:column;gap:20px}


/* ===== Meta list =========================================================
   Key/value rows hairlined apart by the container's background showing through
   a 1px gap - the design's trick, and it keeps the corners clean. */

.gp-meta{display:flex;flex-direction:column;gap:1px;background:var(--border-2);border:1px solid var(--border);border-radius:8px;overflow:hidden}
.gp-meta-row{display:flex;align-items:center;gap:14px;padding:11px 14px;background:var(--surface)}
.gp-meta-k{flex:1;font-size:12.5px;color:var(--text-3)}
.gp-meta-v{font-size:13px;font-weight:500;text-align:right;word-break:break-word}
[dir="rtl"] .gp-meta-v{text-align:left}

/* Totals block under a line-item table. */
.gp-totals{display:flex;flex-direction:column;gap:9px;padding:16px 20px;border-top:1px solid var(--border-2);background:var(--surface-3)}
.gp-totals-row{display:flex;align-items:center;gap:16px;font-size:13px;color:var(--text-2)}
.gp-totals-row span:first-child{flex:1}
.gp-totals-row.is-total{padding-top:10px;border-top:1px solid var(--border);font-size:14px;font-weight:600;color:var(--text)}


/* ===== Timeline ==========================================================
   A dot per step. Colour carries the state; the dot is set inline by the view
   because it is data, not decoration. */

.gp-timeline{display:flex;flex-direction:column;padding:20px}
.gp-tl-step{display:flex;gap:14px;padding:0 0 18px}
.gp-tl-mark{display:grid;place-items:center;width:14px;flex:0 0 14px}
.gp-tl-dot{width:9px;height:9px;border-radius:50%;background:var(--border)}
.gp-tl-dot.is-on{background:var(--ok)}
.gp-tl-dot.is-err{background:var(--err)}
.gp-tl-dot.is-warn{background:var(--warn)}
.gp-tl-t{display:block;font-size:13.5px;font-weight:600}
.gp-tl-d{display:block;margin:3px 0 0;font-size:12.5px;color:var(--text-3)}
.gp-tl-step.is-off .gp-tl-t{color:var(--text-3)}


/* ===== Bar rows and the trend chart ======================================
   The reports screen. Bars are plain divs with a width set inline from the
   percentage - no chart library, exactly as the design draws them. */

.gp-bars{display:flex;flex-direction:column;gap:18px;margin:22px 0 0}
.gp-bar-top{display:flex;align-items:baseline;gap:10px}
.gp-bar-name{flex:1;font-size:13.5px;font-weight:600}
.gp-bar-v{font-size:13px;color:var(--text-2);font-variant-numeric:tabular-nums}
.gp-bar-pct{width:42px;text-align:right;font-size:12.5px;font-weight:600;color:var(--text-3)}
.gp-bar-track{height:8px;margin:9px 0 0;background:var(--surface-2);border-radius:999px;overflow:hidden}
.gp-bar-fill{height:100%;background:var(--accent);border-radius:999px}
.gp-bar-fill.is-neutral{background:var(--text-2)}

.gp-trend{display:flex;align-items:flex-end;gap:10px;height:200px;margin:26px 0 0;overflow:hidden}
.gp-trend-col{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;gap:10px}
.gp-trend-v{font-size:11.5px;font-weight:600;color:var(--text-2);font-variant-numeric:tabular-nums}
.gp-trend-bar{width:100%;max-width:74px;border-radius:6px 6px 2px 2px;background:var(--accent)}
.gp-trend-l{font-size:12px;color:var(--text-3);white-space:nowrap}

/* Ranked list - "Top clients by collection". */
.gp-rank-row{display:flex;align-items:center;gap:14px;padding:14px 20px;border-bottom:1px solid var(--border-2)}
.gp-rank-row:last-child{border-bottom:none}
.gp-rank-name{flex:1;min-width:0}


/* ===== Segmented control =================================================
   The pill group used for VAT treatment, client mode and the report range. */

.gp-seg{display:inline-flex;gap:3px;padding:3px;background:var(--surface-2);border-radius:8px}
.gp-seg button,.gp-seg a{display:inline-flex;align-items:center;padding:9px 15px;border:none;border-radius:6px;background:none;font-size:13px;font-weight:500;color:var(--text-2);white-space:nowrap;cursor:pointer;text-decoration:none}
.gp-seg a:hover{color:var(--text);text-decoration:none}
.gp-seg button.is-on,.gp-seg a.is-on{background:var(--surface);font-weight:600;color:var(--text);box-shadow:var(--shadow-xs)}


/* ===== Form ==============================================================
   46px fields on a form screen. Labels sit above; the hint sits below in
   --text-3 and is part of the field, not a tooltip. */

.gp-form-grid{display:grid;grid-template-columns:1fr 1fr;gap:22px 28px;padding:24px 22px}
.gp-field{min-width:0}
.gp-label{display:block;margin:0 0 8px;font-size:13px;font-weight:500;color:var(--text-2)}
.gp-req{color:var(--err)}
.gp-input,.gp-select,.gp-textarea{width:100%;height:46px;padding:0 14px;background:var(--field);border:1px solid var(--field-b);border-radius:6px;font-size:14.5px}
.gp-select{padding:0 12px;cursor:pointer}
.gp-textarea{height:158px;padding:13px 14px;line-height:1.55;resize:vertical}
.gp-hint{margin:8px 0 0;font-size:12px;color:var(--text-3)}
.gp-error{margin:8px 0 0;font-size:12px;color:var(--err)}
.gp-span2{grid-column:span 2}

/* ===== Documents on a client =============================================
   A row per attachment: the extension as a small square, the kind of document
   over its size and date, and the way to detach it. The file's own name is not
   the line that matters - "Passport" is what somebody is looking for, and the
   name it happened to be saved under on a phone is not. */

.gp-docs{display:flex;flex-direction:column;gap:8px;margin:16px 0 0}
.gp-doc{display:flex;align-items:center;gap:11px;padding:9px 10px;border:1px solid var(--border);border-radius:8px;background:var(--surface)}
.gp-doc-ext{display:grid;place-items:center;width:34px;height:34px;flex:0 0 34px;border-radius:7px;background:var(--surface-3);font-size:10.5px;font-weight:700;letter-spacing:.03em;color:var(--text-3)}
.gp-doc-body{flex:1 1 auto;min-width:0}
.gp-doc-name{display:block;font-size:13.5px;font-weight:500;color:var(--text);text-decoration:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gp-doc-name:hover{color:var(--accent);text-decoration:none}
.gp-doc-meta{display:block;margin:2px 0 0;font-size:12px;color:var(--text-3)}
.gp-doc-none{margin:16px 0 0;font-size:13px;color:var(--text-3)}

.gp-doc-add{margin:18px 0 0;padding:16px 0 0;border-top:1px solid var(--border-2)}

/* The documents block at the foot of the form's second card - a rule across
   the card, then the rows. Inside the card rather than in a card of its own:
   what somebody handed over belongs with who they are, and a fifth heading for
   two controls was furniture. */
.gp-doc-stage{margin:0;padding:18px 22px 22px;border-top:1px solid var(--border-2)}
.gp-doc-stage-head{display:block;margin:0 0 14px}
.gp-doc-stage .gp-form-grid{padding-left:0;padding-right:0}
.gp-doc-stage .gp-doc-none a{color:var(--accent);text-decoration:none}
.gp-doc-stage .gp-doc-none a:hover{text-decoration:underline}

/* The file input's own button, which browsers style themselves and which
   otherwise arrives as a grey slab in the middle of a form that has none. */
.gp-file{height:auto;padding:9px 12px;font-size:13px;line-height:1.4}
.gp-file::file-selector-button{margin-inline-end:10px;padding:5px 11px;border:1px solid var(--border);border-radius:6px;background:var(--surface);font-size:12.5px;font-weight:500;color:var(--text-2);cursor:pointer}
.gp-file::file-selector-button:hover{border-color:var(--text-3);color:var(--text)}

/* A DIALLING CODE AND A NUMBER AS ONE FIELD. Two controls, one label, one
   baseline - the code is narrow because it holds "+973", not a country name. */
.gp-combo{display:flex;gap:8px;align-items:stretch}
.gp-combo-code{flex:0 0 124px;min-width:0}
.gp-combo-number{flex:1 1 auto;min-width:0}

/* SEARCHABLE SELECTS AT PANEL SIZE. components.js replaces a
   <select data-ui-search> with its own button - sized 36px for the admin
   forms, where every field is 36px. In a panel form every field is 46px, and
   a 36px control on that row reads as a different kind of thing. Only the
   metrics and the ink change here; the behaviour is the component's. */
.gp-page .gp-field .f-select-wrap{display:block}
.gp-page .gp-field .f-ss-btn{height:46px;padding:0 12px 0 14px;border-color:var(--field-b);border-radius:6px;background:var(--field);font-size:14.5px;color:var(--text)}
.gp-page .gp-field .f-select-wrap.is-open .f-ss-btn,
.gp-page .gp-field .f-ss-btn:focus-visible{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
.gp-page .gp-field .f-ss-btn .f-caret{font-size:19px;color:var(--text-3)}

/* THE PANEL IS NOT AS NARROW AS THE BOX THAT OPENS IT. The component sizes its
   dropdown at the field's own width (min 240px), which is right for a full-width
   select and wrong for the 124px dialling-code column: "Turks and Caicos
   Islands" arrived clipped to "Turks and Caicos Islan...". The rows are also
   set at the admin forms' 12.5px, which reads small under a 14.5px field. */
.gp-page .gp-combo-code .f-ss-panel{min-width:330px}
.gp-page .gp-field .f-ss-panel{max-height:340px}
.gp-page .gp-field .f-ss-opt,
.gp-page .gp-field .f-ss-search input{font-size:13.5px}
.gp-page .gp-field .f-ss-opt{padding:8px 10px}

/* The native select, for the seconds before the script runs and for the case
   where it never does - it is the field that actually posts. */
.gp-page .gp-field .f-select-wrap>select{width:100%;height:46px;padding:0 12px;background:var(--field);border:1px solid var(--field-b);border-radius:6px;font-size:14.5px}
.gp-input:focus,.gp-select:focus,.gp-textarea:focus{outline:none;border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}

/* Amount field with a currency suffix welded on. */
.gp-amountfield{display:flex;align-items:center;background:var(--field);border:1px solid var(--field-b);border-radius:6px;overflow:hidden}
.gp-amountfield input{flex:1;min-width:0;height:46px;padding:0 14px;background:none;border:none;font-size:14.5px;font-variant-numeric:tabular-nums}
.gp-amountfield input:focus{outline:none;box-shadow:none}
.gp-amountfield .gp-cur{padding:0 14px;font-size:12.5px;font-weight:600;color:var(--text-3);border-left:1px solid var(--border-2);line-height:46px}
[dir="rtl"] .gp-amountfield .gp-cur{border-left:none;border-right:1px solid var(--border-2)}

/* Picker field - a read-only value box plus its Select button. Never a typed
   id: see CLAUDE.md, every reference is picked. */
.gp-picker{display:flex;gap:10px}
.gp-picker-value{flex:1;display:flex;align-items:center;min-height:46px;padding:8px 14px;background:var(--field);border:1px solid var(--field-b);border-radius:6px;font-size:14.5px}
.gp-picker-value.is-empty{color:var(--text-4);background:var(--surface-3)}

/* Tabs across the top of a form card. */
.gp-tabs{display:flex;padding:0 12px;border-bottom:1px solid var(--border-2);background:var(--surface-3);overflow-x:auto}
.gp-tabs button{padding:15px 16px;border:none;background:none;font-size:13.5px;font-weight:500;color:var(--text-3);white-space:nowrap;cursor:pointer}
.gp-tabs button.is-on{font-weight:600;color:var(--accent);box-shadow:inset 0 -2px 0 var(--accent)}

/* Switch rows - label, hint and a toggle, hairlined like .gp-meta. */
.gp-switches{display:flex;flex-direction:column;gap:1px;background:var(--border-2);border:1px solid var(--border);border-radius:8px;overflow:hidden}
.gp-switch-row{display:flex;align-items:center;gap:16px;padding:16px 18px;background:var(--surface)}
.gp-switch-text{flex:1}
.gp-switch-label{font-size:14px;font-weight:600}
.gp-switch-hint{margin:4px 0 0;font-size:12.5px;color:var(--text-3)}
.gp-switch{position:relative;width:44px;height:25px;flex:0 0 44px;padding:0;border:none;border-radius:999px;background:var(--surface-2);cursor:pointer;transition:background .18s}
.gp-switch .gp-knob{position:absolute;top:3px;left:3px;width:19px;height:19px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.24);transition:left .18s}
.gp-switch.is-on{background:var(--accent)}
.gp-switch.is-on .gp-knob{left:22px}

/* The note strip a form shows when it is about to create a record. */
.gp-notice{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;background:var(--accent-soft2);border:1px solid var(--accent-soft);border-radius:8px;font-size:13px;color:var(--text-2)}
.gp-notice .gp-notice-ic{margin-top:1px;color:var(--accent);flex:0 0 auto}

/* Sticky action bar at the foot of a form screen. */
.gp-formbar{position:sticky;bottom:0;z-index:25;background:var(--surface);border-top:1px solid var(--border)}
.gp-formbar-in{display:flex;align-items:center;gap:12px;max-width:1180px;margin:0 auto;padding:14px 32px}
.gp-formbar-hint{flex:1;font-size:12.5px;color:var(--text-3)}
.gp-formbar .gp-btn{height:42px;padding:0 18px}
.gp-formbar .gp-btn-primary{padding:0 22px}


/* ===== Overlays ==========================================================
   Scrim + sheet, scrim + right drawer, scrim + picker. All three animate in;
   the scrim itself only fades so a slow machine never shows a sliding grey. */

@keyframes gpIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@keyframes gpFade{from{opacity:0}to{opacity:1}}

.gp-scrim{position:fixed;inset:0;z-index:60;background:rgba(22,22,26,.44);animation:gpFade .2s ease both}
.gp-scrim-sheet{display:flex;align-items:flex-start;justify-content:center;padding:70px 24px;overflow-y:auto}
.gp-scrim-drawer{z-index:62;display:flex;justify-content:flex-end;background:rgba(22,22,26,.36);animation-duration:.18s}
.gp-scrim-picker{z-index:64;display:flex;align-items:flex-start;justify-content:center;padding:80px 24px;animation-duration:.18s}

.gp-sheet{width:100%;max-width:620px;background:var(--surface);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-lg);overflow:hidden;animation:gpIn .26s cubic-bezier(.2,.8,.2,1) both}
.gp-sheet-sm{max-width:520px;animation-duration:.24s}
.gp-sheet-head{display:flex;align-items:flex-start;gap:12px;padding:18px 22px;border-bottom:1px solid var(--border-2)}
.gp-sheet-head-text{flex:1;min-width:0}
.gp-sheet-title{font-size:16.5px;font-weight:600;letter-spacing:-.02em}
.gp-sheet-sub{margin:4px 0 0;font-size:12.5px;color:var(--text-3)}
.gp-sheet-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px 22px;padding:22px}
.gp-sheet-grid .gp-input,.gp-sheet-grid .gp-select{height:44px;font-size:14px}
.gp-sheet-foot{display:flex;align-items:center;gap:12px;padding:16px 22px;border-top:1px solid var(--border-2);background:var(--surface-3)}
.gp-sheet-err{flex:1;font-size:12.5px;color:var(--err)}
.gp-close{display:grid;place-items:center;width:32px;height:32px;flex:0 0 32px;border:none;border-radius:6px;background:none;color:var(--text-3);cursor:pointer}
.gp-close:hover{color:var(--text);background:var(--surface-2)}

.gp-drawer{width:420px;max-width:100%;height:100%;display:flex;flex-direction:column;background:var(--surface);border-left:1px solid var(--border);box-shadow:var(--shadow-lg);animation:gpIn .24s cubic-bezier(.2,.8,.2,1) both}
[dir="rtl"] .gp-drawer{border-left:none;border-right:1px solid var(--border)}
.gp-drawer-head{display:flex;align-items:flex-start;gap:12px;padding:22px}
.gp-drawer-body{padding:0 22px;overflow-y:auto}
.gp-drawer .gp-meta-k{flex:0 0 112px}
.gp-drawer .gp-meta-v{flex:1;font-size:13.5px}
.gp-drawer-foot{margin-top:auto;display:flex;gap:10px;padding:20px 22px;border-top:1px solid var(--border-2)}
.gp-drawer-foot .gp-btn{height:42px}

.gp-picker-head{padding:18px 20px;border-bottom:1px solid var(--border-2);font-size:15.5px;font-weight:600}
.gp-picker-search{padding:14px 20px;border-bottom:1px solid var(--border-2)}
.gp-picker-search input{width:100%;height:42px;padding:0 14px;background:var(--field);border:1px solid var(--field-b);border-radius:6px;font-size:14px}
.gp-picker-list{max-height:340px;overflow-y:auto}
.gp-picker-item{display:flex;align-items:center;gap:14px;width:100%;padding:14px 20px;border:none;border-bottom:1px solid var(--border-2);background:none;text-align:left;cursor:pointer}
.gp-picker-item:hover{background:var(--surface-3)}
.gp-picker-item .gp-pi-text{flex:1;min-width:0}
.gp-picker-item .gp-pi-name{display:block;font-size:14px;font-weight:600}
.gp-picker-item .gp-pi-meta{display:block;margin:3px 0 0;font-size:12.5px;color:var(--text-3)}
.gp-picker-item .gp-pi-cta{font-size:12.5px;font-weight:600;color:var(--accent)}
[dir="rtl"] .gp-picker-item{text-align:right}


/* ===== Toast =============================================================
   Fixed, centred, dark in both schemes - it sits over the page, not in it. */

.gp-toast{position:fixed;left:50%;bottom:34px;z-index:96;transform:translateX(-50%);display:flex;align-items:center;gap:14px;padding:13px 16px 13px 18px;background:#26262b;border-radius:9px;box-shadow:var(--shadow-lg);animation:gpIn .2s ease both}
.gp-toast-msg{font-size:13.5px;font-weight:500;color:#fff}
/* Warm Gray 1c - the accent's dark-mode value, because the toast is always
   dark whichever scheme the page is in. */
.gp-toast-undo{border:none;background:none;font-size:13px;font-weight:600;color:#bfb5ab;cursor:pointer;text-decoration:underline}


/* ===== Bulk-select bar ===================================================
   Sits above the table body and swaps between a hint and the action row. */

.gp-bulkbar{display:flex;align-items:center;gap:14px;padding:13px 20px;border-bottom:1px solid var(--border-2)}
.gp-bulkbar.is-on{background:var(--accent-soft2)}
.gp-bulkbar-hint{flex:1;font-size:12.5px;color:var(--text-3)}
.gp-bulkbar-acts{display:flex;align-items:center;gap:12px;flex:1;flex-wrap:wrap}
.gp-bulkbar-n{font-size:13px;font-weight:600}
.gp-bulkbar-sep{width:1px;height:18px;background:var(--border)}
.gp-minibtn{padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--surface);font-size:12.5px;font-weight:500;color:var(--text-2);cursor:pointer}
.gp-minibtn:hover{color:var(--text)}
.gp-minibtn-danger{border-color:var(--err);background:var(--err-soft);font-weight:600;color:var(--err)}
.gp-linkbtn{border:none;background:none;font-size:12.5px;color:var(--text-3);cursor:pointer;text-decoration:underline}
.gp-check{width:15px;height:15px;accent-color:var(--accent);cursor:pointer}
.gp-select-sm{height:32px;padding:0 8px;background:var(--field);border:1px solid var(--field-b);border-radius:6px;font-size:12.5px;cursor:pointer}

/* Group heading inside a table body. */
.gp-grouprow td{padding:11px 20px 10px;background:var(--surface-3);border-top:1px solid var(--border-2)}
.gp-group-l{font-size:11px;font-weight:600;letter-spacing:.11em;text-transform:uppercase;color:var(--text-3)}
.gp-group-n{margin-left:9px;font-size:11px;font-weight:600;color:var(--text-4)}


/* ===== Pager ============================================================= */

.gp-pager{display:flex;align-items:center;gap:10px;padding:13px 20px;border-top:1px solid var(--border-2);flex-wrap:wrap}
.gp-pager-range{flex:1;font-size:12.5px;color:var(--text-3)}
.gp-pager button{min-width:32px;padding:7px 12px;border:1px solid var(--border);border-radius:6px;background:var(--surface);font-size:12.5px;color:var(--text-2);cursor:pointer}
.gp-pager button:hover{color:var(--text)}
.gp-pager button.is-on{border-color:var(--accent);background:var(--accent-soft);font-weight:600;color:var(--accent)}


/* ===== Payment-link block ================================================ */

.gp-linkbox{margin:14px 0 0;padding:12px 14px;background:var(--surface-3);border:1px solid var(--border-2);border-radius:7px;font-family:var(--mono);font-size:12.5px;color:var(--text-2);word-break:break-all}


/* ===== Vehicles / soft tiles ============================================= */

.gp-tile{padding:14px;background:var(--surface-3);border:1px solid var(--border-2);border-radius:8px}
.gp-tile-top{display:flex;align-items:center;gap:10px}
.gp-tile-name{flex:1;font-size:13.5px;font-weight:600}
.gp-tile-side{font-size:12px;font-weight:600;color:var(--text-3);font-variant-numeric:tabular-nums}
.gp-tile-meta{margin:5px 0 0;font-size:12.5px;color:var(--text-3)}


/* ===== Responsive ========================================================
   The design is drawn at desktop width. These are the collapses that keep it
   usable below it - nothing here changes the desktop rendering. */

@media (max-width:1180px){
    .gp-split,.gp-split-even{grid-template-columns:minmax(0,1fr)}
    .gp-kpis{grid-template-columns:repeat(2,minmax(0,1fr))}
}

@media (max-width:760px){
    .gp-kpis{grid-template-columns:minmax(0,1fr)}
    .gp-form-grid,.gp-sheet-grid{grid-template-columns:minmax(0,1fr)}
    .gp-span2{grid-column:auto}
    .gp-head h1{font-size:23px}
    .gp-search{width:100%}
    .gp-formbar-in{padding:14px 16px}
    .gp-drawer{width:100%}
}


/* ===========================================================================
   The declarative table, wearing the panel design.

   Lists on the panel are still built by get_<resource>_list_table() +
   arrayToTable() - that is the convention, and it is what gives these screens
   their filters, sorting, pagination, column manager and export for free. What
   changes here is only how table_container_v3.html LOOKS: the design draws a
   plain card with a quiet header strip and a range line under it, so the
   toolbar's chrome is dialled back to match.

   Scoped to .gp-page, so every list outside the panel keeps the stock look.
   =========================================================================== */

.gp-page .tblx-toolbar{background:var(--surface);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-sm);overflow:visible}

/* Toolbar: the design puts the title in the page head, so the table's own
   title block is dropped and the tools sit alone on a quiet strip. */
.gp-page .tblx-head{padding:13px 20px;border-bottom:1px solid var(--border-2);background:var(--surface-3);gap:10px}
.gp-page .tblx-titles{display:none}
.gp-page .tblx-tools{gap:8px}
.gp-page .tblx-search-input{height:34px;background:var(--field);border:1px solid var(--field-b);border-radius:7px;font-size:13px}
.gp-page .tblx-btn{height:34px;padding:0 12px;border:1px solid var(--border);border-radius:7px;background:var(--surface);font-size:12.5px;font-weight:500;color:var(--text-2)}
.gp-page .tblx-btn:hover{color:var(--text);border-color:var(--text-3)}
.gp-page .tblx-btn-main{border-color:transparent;background:var(--accent);font-weight:600;color:var(--accent-fg)}
.gp-page .tblx-btn-main:hover{filter:brightness(1.14);color:var(--accent-fg);border-color:transparent}

/* Body: no card padding - the table meets the card edge, as in the design. */
.gp-page .tblx-body{padding:0}
.gp-page .table-wrapper{overflow-x:auto}

.gp-page table.dynamic-table{width:100%;border-collapse:collapse;font-size:13.5px;margin:0}
.gp-page table.dynamic-table>thead{background:none}
.gp-page table.dynamic-table>thead th{padding:14px 16px;border:none;border-bottom:1px solid var(--border-2);background:none;text-align:left;font-size:11.5px;font-weight:600;color:var(--text-3);white-space:nowrap}
.gp-page table.dynamic-table>tbody td{padding:14px 16px;border:none;border-bottom:1px solid var(--border-2);vertical-align:middle;color:var(--text)}
.gp-page table.dynamic-table>thead th:first-child,.gp-page table.dynamic-table>tbody td:first-child{padding-left:20px}
.gp-page table.dynamic-table>thead th:last-child,.gp-page table.dynamic-table>tbody td:last-child{padding-right:20px}
.gp-page table.dynamic-table>tbody tr:hover{background:var(--surface-3)}
.gp-page table.dynamic-table>tbody tr:last-child td{border-bottom:none}
[dir="rtl"] .gp-page table.dynamic-table>thead th{text-align:right}

/* The row actions the data function emits as raw HTML land in a 'btns' cell -
   give that cell the design's right-aligned icon cluster. */
.gp-page table.dynamic-table td .gp-rowacts{justify-content:flex-end}

/* Pager and status strip: one quiet line, not a second card. */
.gp-page .tblx-body>div[id$="_pages"] .card-footer{padding:13px 20px;border-top:1px solid var(--border-2);background:none}

/* THE PAGER ITSELF, in this theme's ink.

   It used to appear only from page two, on screens nobody had reached yet, so
   nothing here described it and bootstrap's defaults stood: link-blue page
   numbers, a primary-blue Go button, a full-height select - three colours and
   a scale the panel uses nowhere else, sitting under a table that is all
   quiet borders. Now that a list declaring a count label carries the footer at
   every size, the pager is on screen from the first row and has to belong. */
.gp-page .card-footer .text-muted{color:var(--text-3)}
.gp-page .card-footer .small,.gp-page .card-footer p{font-size:12.5px}

.gp-page .pagination{gap:4px}
.gp-page .page-link{display:grid;place-items:center;min-width:30px;height:30px;padding:0 8px;border:1px solid var(--border);border-radius:7px;background:var(--surface);color:var(--text-2);font-size:12.5px;cursor:pointer}
.gp-page .page-link:hover{background:var(--surface);border-color:var(--text-3);color:var(--text)}
.gp-page .page-item.active .page-link{border-color:transparent;background:var(--accent);color:var(--accent-fg);font-weight:600}
.gp-page .page-item.disabled .page-link{background:var(--surface);color:var(--text-4);cursor:default}

.gp-page .card-footer .form-select,
.gp-page .card-footer .form-control{height:30px;padding:0 8px;border:1px solid var(--field-b);border-radius:7px;background:var(--field);color:var(--text);font-size:12.5px}
.gp-page .card-footer .btn-outline-primary{height:30px;padding:0 11px;border:1px solid var(--border);border-radius:7px;background:var(--surface);color:var(--text-2);font-size:12.5px}
.gp-page .card-footer .btn-outline-primary:hover{background:var(--surface);border-color:var(--text-3);color:var(--text)}
.gp-page .status-bar{border-top:1px solid var(--border-2)}
.gp-page .status-bar{padding:11px 20px;background:none;font-size:12px;color:var(--text-4)}
.gp-page .tblx-drawer{border-bottom:1px solid var(--border-2);background:var(--surface-3)}

/* A PLAIN CARD - what a screen that carries its own controls asks for with
   $settings['hide_toolbar']. The toolbar strip is gone, so the column-manager
   status line under the table goes with it (it describes a manager that is no
   longer reachable), and the header's sort and drag glyphs wait to be pointed
   at: the design draws neither, and a column cannot be dragged anywhere useful
   without the manager. Sorting still works - the whole header is the target. */
.gp-page .tblx-plain .status-bar{display:none}
.gp-page .tblx-plain table.dynamic-table .drag-handle{display:none}
.gp-page .tblx-plain table.dynamic-table .sort-icon{opacity:0;transition:opacity .12s ease}
.gp-page .tblx-plain table.dynamic-table th:hover .sort-icon{opacity:1}


/* ===========================================================================
   Sign in, and the signed-out screen.

   The design draws these as a split: the form on a --surface panel to the
   start side, a full-bleed brand panel to the end side carrying the Euro
   Motors line over a gradient. Below 900px the brand panel is dropped rather
   than stacked - on a phone it would push the form a screen down, and the form
   is the entire point of the page.

   FULL BLEED. pages.html wraps every page body in .wrap, and panel.css gives
   .wrap max-width:1520px, a centred margin and 32px/64px of padding. That is
   right for a page of cards and wrong for a screen that is meant to BE the
   window: it boxed the split inside gutters, and because .gp-auth then asks
   for a full viewport of height INSIDE 96px of vertical padding, the page grew
   ~96px taller than the window - a scrollbar on a page with nothing to scroll,
   and the brand panel's caption sitting on the crop line. So the two auth
   screens un-pad their own wrapper. :has() does that without a body class,
   which pages.html has no hook for; a browser too old for :has() simply keeps
   today's boxed rendering rather than breaking.

   HEIGHTS are 100vh with a 100dvh line behind them. On a phone 100vh is the
   viewport WITHOUT the browser's toolbars, so the sign-in button lands under
   the address bar; dvh is the live height. Browsers that do not know the unit
   drop the second line and keep the vh they understand.
   =========================================================================== */

.wrap:has(> .gp-auth),
.wrap:has(> .gp-signout){max-width:none;margin:0;padding:0}

/* Same un-padding for the customer portal, but as a real class rather than
   :has(). The portal is the one screen served to the public on whatever phone
   they own, so "a browser too old for :has() keeps today's boxed rendering"
   is not an acceptable fallback there: boxed means 32px of panel gutter on
   top of the portal's own 20px, which leaves a 360px screen rendering the
   payment form in 256px. index.php assigns $wrap_bare; view/pay/*.php set it.

   Written .wrap.wrap-bare, not .wrap-bare: the .wrap that boxes the page is
   declared further down this file, in the top-nav block, so a single class
   here would be the earlier rule of two at equal specificity and lose. */
.wrap.wrap-bare{max-width:none;margin:0;padding:0}

.gp-auth{min-height:100vh;min-height:100dvh;display:grid;
    grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);background:var(--bg)}

/* No justify-content:center. The auto margins on .gp-auth-brand and
   .gp-auth-foot already centre the middle of the form, and they do it safely:
   when the content is taller than the window autos collapse to 0 and the page
   scrolls, where justify-content:center would have pushed the top of the form
   off the top of the screen where it cannot be scrolled back to. */
.gp-auth-form{--gp-auth-col:420px;
    display:flex;flex-direction:column;background:var(--surface);
    padding:clamp(32px,6vh,64px) clamp(22px,5vw,64px)}

/* The form column is ~900px on a desktop and the fields are 420px, so without
   this the whole form hugs the start edge with a third of the panel empty
   beside it. Inline autos ONLY - the block autos above are what space the
   brand, the lede and the footnote apart, and a margin shorthand here would
   eat them. */
.gp-auth-form > *{width:100%;max-width:var(--gp-auth-col);margin-inline:auto}

.gp-auth-brand{display:flex;align-items:center;gap:11px;margin:0 0 auto}
.gp-auth-mark{display:grid;place-items:center;width:34px;height:34px;flex:0 0 34px;border-radius:9px;background:var(--accent);overflow:hidden}
.gp-auth-mark img{width:22px;height:22px;object-fit:contain}
.gp-auth-name{font-size:15px;font-weight:600;letter-spacing:-.015em;color:var(--text)}
.gp-auth-name span{font-weight:400;color:var(--text-3)}

.gp-auth-lede{padding:clamp(28px,4.5vh,48px) 0 clamp(26px,4vh,44px)}
.gp-eyebrow{font-size:11px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--text-3)}
.gp-auth-lede h1{margin:16px 0 0;font-size:clamp(24px,1.1vw + 19px,32px);font-weight:400;letter-spacing:-.035em;line-height:1.16;color:var(--text)}

.gp-auth-fields{display:flex;flex-direction:column;gap:18px}
.gp-auth-label{display:block;margin:0 0 8px;font-size:13px;font-weight:500;color:var(--text-2)}
.gp-auth-input{width:100%;height:48px;padding:0 14px;background:var(--field);border:1px solid var(--field-b);border-radius:6px;font-size:14.5px;color:var(--text)}
.gp-auth-input:focus{outline:none;border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
.gp-auth-pwhead{display:flex;align-items:baseline;gap:12px;margin:0 0 8px}
.gp-auth-pwhead .gp-auth-label{flex:1;margin:0}
.gp-auth-reveal{border:none;background:none;font-size:12.5px;font-weight:600;color:var(--accent);cursor:pointer;padding:0}
.gp-auth-row{display:flex;align-items:center;gap:10px 14px;flex-wrap:wrap}
.gp-auth-check{display:flex;align-items:center;gap:10px;flex:1 1 auto;font-size:13px;color:var(--text-2);cursor:pointer}
.gp-auth-check input{width:16px;height:16px;flex:0 0 16px;accent-color:var(--accent);cursor:pointer}
.gp-auth-link{border:none;background:none;font-size:13px;font-weight:600;color:var(--accent);cursor:pointer;text-decoration:none}
.gp-auth-link:hover{text-decoration:underline;color:var(--accent)}
.gp-auth-submit{height:50px;margin:6px 0 0;border:none;border-radius:7px;background:var(--accent);font-size:14.5px;font-weight:600;color:var(--accent-fg);cursor:pointer}
.gp-auth-submit:hover{filter:brightness(1.14)}
/* overflow-wrap: a refusal from the gateway and a spent token's reason are
   both server text of no fixed length, and one long word must not be allowed
   to widen the box it sits in. */
.gp-auth-alert{padding:12px 14px;background:var(--err-soft);border:1px solid var(--err);border-radius:7px;font-size:13px;line-height:1.45;color:var(--err);overflow-wrap:anywhere}
.gp-auth-alert-good{background:var(--ok-soft);border-color:var(--ok);color:var(--ok)}
.gp-auth-foot{margin:auto 0 0;padding:clamp(28px,4vh,44px) 0 0;font-size:12.5px;line-height:1.5;color:var(--text-3)}

/* The brand panel. min-height:100% and not 100vh - it is a grid item, so the
   row already stretches it to whatever .gp-auth resolved its own height to,
   and a second 100vh here only ever disagrees with that on a phone. */
.gp-auth-side{position:relative;min-height:100%;overflow:hidden;background:var(--surface-2)}
.gp-auth-side-art{position:absolute;inset:0;background-image:var(--gp-auth-image,none);background-size:cover;background-position:center;
    background-color:var(--accent);
    /* a soft vignette so the caption below stays readable over either */
    box-shadow:inset 0 -160px 200px -80px rgba(16,16,18,.75)}
.gp-auth-side-art::after{content:"";position:absolute;inset:0;
    background:radial-gradient(120% 90% at 20% 10%, rgba(255,255,255,.18), transparent 60%)}
.gp-auth-side-cap{position:absolute;inset:auto 0 0 0;padding:clamp(24px,3vw,40px) clamp(24px,3vw,40px) clamp(22px,2.6vw,34px);
    background:linear-gradient(to top,rgba(16,16,18,.72),rgba(16,16,18,0));pointer-events:none}
.gp-auth-side-cap .gp-eyebrow{color:rgba(255,255,255,.6)}
.gp-auth-side-cap p{margin:14px 0 0;max-width:440px;font-size:clamp(13.5px,.4vw + 11px,15px);line-height:1.5;color:rgba(255,255,255,.92)}

/* The signed-out screen - one centred card, not a split. */
.gp-signout{min-height:100vh;min-height:100dvh;display:grid;place-items:center;padding:clamp(24px,6vh,40px) clamp(16px,5vw,24px);background:var(--bg)}
.gp-signout-card{width:100%;max-width:430px;padding:clamp(28px,5vw,36px) clamp(20px,4vw,32px);background:var(--surface);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-sm);text-align:center}
.gp-signout-mark{display:grid;place-items:center;width:46px;height:46px;margin:0 auto;border-radius:999px;background:var(--ok-soft);color:var(--ok)}
.gp-signout-card h1{margin:20px 0 0;font-size:22px;font-weight:600;letter-spacing:-.025em;color:var(--text)}
.gp-signout-card p{margin:10px 0 0;font-size:13.5px;color:var(--text-3)}
.gp-signout-card .gp-auth-submit{width:100%;height:46px;margin:26px 0 0;font-size:14px;display:block}
.gp-signout-foot{margin:16px 0 0;font-size:12.5px;color:var(--text-3)}

/* ---- Laptops. The split holds; the brand panel gives back the width the
   photograph does not need, so the form keeps its column. ---- */
@media (max-width:1200px){
    .gp-auth{grid-template-columns:minmax(0,1fr) minmax(0,.9fr)}
}

/* ---- The brand panel goes. Stacking it would put a screen of photograph
   above the only thing the visitor came here to do. ---- */
@media (max-width:900px){
    .gp-auth{grid-template-columns:minmax(0,1fr)}
    .gp-auth-side{display:none}
    .gp-auth-form{--gp-auth-col:440px;padding:clamp(28px,5vh,48px) 24px}
    .gp-auth-lede{padding:36px 0 32px}
}

/* ---- Phones. 16px on the inputs is not a taste call: below 16px iOS Safari
   zooms the page in when a field takes focus and does not zoom back out, which
   is how a sign-in form ends up half off the screen after one tap. ---- */
@media (max-width:600px){
    .gp-auth-input{font-size:16px}
    .gp-auth-lede{padding:28px 0 26px}
    .gp-auth-foot{padding-top:32px}
}

@media (max-width:380px){
    .gp-auth-form{padding:24px 16px}
}

/* ---- Landscape phones and short windows. There is no spare height for the
   auto margins to centre with, so stop demanding a full viewport and let the
   page scroll from the top instead of centring a form it cannot fit. ---- */
@media (max-height:620px) and (max-width:900px){
    .gp-auth{min-height:0}
    .gp-auth-form{padding-block:32px}
    .gp-auth-brand,.gp-auth-foot{margin-block:0}
    .gp-auth-foot{padding-top:28px}
    .gp-signout{min-height:0;padding-block:32px}
}


/* ===========================================================================
   The top navigation bar - the Gate-E Admin Panel design's chrome.

   Replaces the sidebar + header pair. Loaded after shell.css, so the .app /
   .content / .wrap overrides below win over the flex-row shell those files
   set up for a sidebar that no longer exists.
   =========================================================================== */

/* The shell was a flex ROW (sidebar beside main). With the bar on top it is a
   column, and the page below it gets the design's own gutter and max width. */
.app{display:block;min-height:100vh;background:var(--bg)}
.content{flex:none;padding:0;display:block}
.wrap{display:block;max-width:1520px;width:100%;margin:0 auto;padding:32px 32px 64px;gap:0}

.gp-topnav{position:sticky;top:0;z-index:40;background:var(--surface);border-bottom:1px solid var(--border)}
.gp-topnav-in{display:flex;align-items:center;gap:20px;row-gap:10px;flex-wrap:wrap;max-width:1520px;margin:0 auto;padding:12px 32px;min-height:66px}

/* ---- Brand ---- */
.gp-brand{display:flex;align-items:center;gap:11px;text-decoration:none;flex:0 0 auto}
.gp-brand:hover{text-decoration:none}
.gp-brand-mark{display:grid;place-items:center;width:32px;height:32px;flex:0 0 32px;border-radius:8px;background:var(--accent);overflow:hidden}
.gp-brand-mark img{width:20px;height:20px;object-fit:contain}
.gp-brand-name{font-size:15px;font-weight:600;letter-spacing:-.015em;white-space:nowrap;color:var(--text)}
.gp-brand-name span{font-weight:400;color:var(--text-3)}

/* ---- The nav itself ----
   Scrolls sideways rather than wrapping: a bar that grows to two rows moves
   every page's content down the moment somebody is granted one more screen. */
.gp-nav{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:4px;overflow-x:auto;scrollbar-width:none}
.gp-nav::-webkit-scrollbar{display:none}

.gp-nav-item{display:flex;align-items:center;gap:8px;padding:8px 13px;border:none;border-radius:8px;background:transparent;font-size:13.5px;font-weight:500;color:var(--text-2);white-space:nowrap;cursor:pointer;text-decoration:none}
.gp-nav-item:hover{background:var(--surface-2);color:var(--text);text-decoration:none}
.gp-nav-ico{font-size:17px;width:17px;height:17px;flex:0 0 17px}
.gp-nav-chev{font-size:16px;margin-left:-2px;color:var(--text-3)}

/* Set by app.js from the current URL. */
.gp-nav-item.active{background:var(--accent-soft);font-weight:600;color:var(--accent)}
.gp-nav-item.active:hover{background:var(--accent-soft);color:var(--accent)}

/* ---- The overflow menu, for what the design did not draw ----

   .gp-nav-more MUST STAY OUTSIDE .gp-nav. It is a sibling of the nav in
   sections/topnav.html, not one of its items, because .gp-nav above sets
   overflow-x:auto - and CSS has no way to clip one axis while leaving the
   other visible, so overflow-y computes to 'auto' along with it. A panel
   opening 8px below a 34px-tall scroller is then clipped away entirely: nav
   bottom 50, panel top 54, zero pixels painted, and the click that should have
   landed on the first menu item lands on the page behind it. Put this back
   inside the nav and the Admin button goes dead again, silently.

   Anchored to the trailing edge, not the leading one. Out here the menu sits
   right beside the account block at the end of the bar, and a 230px panel
   opening rightward from there hangs off the viewport on a narrow screen. */
.gp-nav-more{position:relative;flex:0 0 auto}
.gp-nav-dd{position:absolute;top:calc(100% + 8px);right:0;left:auto;z-index:60;min-width:230px;max-height:70vh;overflow-y:auto;
    padding:6px;background:var(--surface);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-md)}
[dir="rtl"] .gp-nav-dd{right:auto;left:0}
.gp-nav-dd-group{padding:9px 10px 5px;font-size:10.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--text-4)}
.gp-nav-dd-item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:7px;font-size:13px;color:var(--text-2);text-decoration:none;white-space:nowrap}
.gp-nav-dd-item:hover{background:var(--surface-2);color:var(--text);text-decoration:none}
.gp-nav-dd-item .material-icons-outlined{font-size:17px;color:var(--text-3)}

/* ---- The end of the bar ---- */
.gp-topnav-end{display:flex;align-items:center;gap:10px;margin-left:auto;flex:0 0 auto}
[dir="rtl"] .gp-topnav-end{margin-left:0;margin-right:auto}

.gp-topnav-cta{display:flex;align-items:center;gap:8px;padding:0 15px;height:38px;border:none;border-radius:7px;background:var(--accent);font-size:13.5px;font-weight:600;color:var(--accent-fg);white-space:nowrap;text-decoration:none}
.gp-topnav-cta:hover{filter:brightness(1.14);color:var(--accent-fg);text-decoration:none}

.gp-topnav-icon{display:grid;place-items:center;width:38px;height:38px;flex:0 0 38px;border:1px solid var(--border);border-radius:7px;background:none;color:var(--text-2);cursor:pointer;text-decoration:none}
.gp-topnav-icon:hover{color:var(--text);border-color:var(--text-3);text-decoration:none}
.gp-topnav-icon .material-icons-outlined{font-size:19px}

.gp-topnav-user{position:relative;display:flex;align-items:center;gap:10px;padding-left:14px;border-left:1px solid var(--border-2)}
[dir="rtl"] .gp-topnav-user{padding-left:0;padding-right:14px;border-left:none;border-right:1px solid var(--border-2)}
.gp-user-btn{display:flex;align-items:center;gap:10px;padding:0;border:none;background:none;cursor:pointer;text-align:left}
[dir="rtl"] .gp-user-btn{text-align:right}
.gp-user-avatar{display:grid;place-items:center;width:32px;height:32px;flex:0 0 32px;border-radius:999px;background:var(--surface-2);font-size:12px;font-weight:600;color:var(--text-2);text-transform:uppercase}
.gp-user-text{line-height:1.25;min-width:0}
.gp-user-name{display:block;font-size:13px;font-weight:600;white-space:nowrap;color:var(--text)}
.gp-user-org{display:block;font-size:11px;color:var(--text-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:150px}

/* Sign-out on the bar itself - one press, not two. */
.gp-topnav-out{width:34px;height:34px;flex-basis:34px;border:none;color:var(--text-3)}
.gp-topnav-out:hover{color:var(--err);background:var(--err-soft);border-color:transparent}

.gp-user-dd{position:absolute;top:calc(100% + 10px);right:0;z-index:60;min-width:230px;
    padding:6px;background:var(--surface);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-md)}
[dir="rtl"] .gp-user-dd{right:auto;left:0}

/* ---- Narrow screens ----
   The bar keeps its nav; what goes is the text beside the avatar and the CTA's
   label, because those are the two things that cost the most width and say the
   least. The nav scrolls, so nothing becomes unreachable. */
@media (max-width:1100px){
    .gp-user-text{display:none}
    .gp-topnav-user{padding-left:10px}
    [dir="rtl"] .gp-topnav-user{padding-right:10px}
}

@media (max-width:860px){
    .gp-topnav-in{padding:10px 16px;gap:12px}
    .wrap{padding:20px 16px 48px}
    .gp-topnav-cta span:not(.material-icons-outlined){display:none}
    .gp-topnav-cta{padding:0;width:38px;justify-content:center}
    .gp-brand-name{display:none}
    .gp-nav{order:3;width:100%;flex-basis:100%}

    /* THE ADMIN MENU, ANCHORED TO THE BAR RATHER THAN TO ITS BUTTON.

       Here the nav wraps to its own row, which leaves the overflow button
       somewhere in the middle of the top row - and a 230px panel hung off
       either of its edges then runs off the screen. Measured at a 500px
       viewport: trailing-anchored it started at x=-80.

       position:static on the wrapper hands the panel back to the nearest
       positioned ancestor, which is .gp-topnav (sticky counts). Pinning both
       sides to that makes it a full-width sheet under the bar, which is the
       right shape on a phone anyway. */
    .gp-nav-more{position:static}
    .gp-nav-dd{left:12px;right:12px;min-width:0}
    [dir="rtl"] .gp-nav-dd{left:12px;right:12px}
}


/* ===========================================================================
   The Euro Motors lockup.

   em-logo-bilingual.png is WHITE on transparent, so on a light --surface it is
   invisible on its own. --logo-filter is the theme's answer: in light mode
   brightness(0) invert(25%), which lands the artwork on rgb(64,64,64) -
   Pantone 447C, the brand's own dark - and in dark mode none, leaving it
   white. One image, both schemes, no second file to keep in step.

   Width is never set - the lockup is 700x152 and squashing a wordmark is worse
   than any layout it would fix. Height drives it and width follows.
   =========================================================================== */

.gp-brand-logo{display:block;height:26px;width:auto;filter:var(--logo-filter)}
.gp-brand-logo-lg{height:34px}

/* On the dark caption panel and the toast the logo sits on its own dark ground
   already, so it must NOT be inverted there. */
.gp-auth-side .gp-brand-logo,.gp-toast .gp-brand-logo{filter:none}

.gp-signout-foot .gp-brand-logo{height:22px;margin:0 auto;opacity:.75}

/* The sign-in brand panel's photograph. Swap the file here to change it. */
.gp-auth-side-art{--gp-auth-image:url("../images/auth/showroom.jpg")}

@media (max-width:860px){
    .gp-brand-logo{height:22px}
}


/* ===========================================================================
   The declarative table engine, wearing the panel design.

   The palette is NOT set here any more. css_table.html declares its own
   --tblx-* tokens and every rule in it goes through them, so those defaults now
   read the design system directly (--accent, --text, --border-2 ...). That is
   one place deciding the colour instead of two fighting over specificity,
   and it fixes the whole app rather than the panel alone.

   What is left here is layout the design asks for and the engine does not.
   =========================================================================== */

/* The engine's own chrome that the design does not have. The column manager's
   drag hint and the "all columns visible" line are instructions for a control
   the design never drew; they sit under every list as a permanent footnote. */
.gp-page .status-bar{display:none}

/* The pager reads as the design's quiet range line rather than a second card. */
.gp-page .card-footer{padding:13px 20px;border:none;border-top:1px solid var(--border-2);background:none;font-size:12.5px;color:var(--text-3)}
.gp-page .card-footer .text-muted{color:var(--text-3) !important;font-size:12.5px}

/* Card views inherit the slate palette from the same block. Nothing in the
   panel offers them, but a stray ?card_style= should not paint a white-on-
   white card in dark mode. */
.gp-page .cardv{background:var(--surface);border-color:var(--border);color:var(--text)}
.gp-page .cardv .cardv-title{color:var(--text)}
.gp-page .cardv .cardv-index{background:var(--surface-2);color:var(--text-3)}
.gp-page .cardv .cardv-label{color:var(--text-4)}


/* ===========================================================================
   Things on the list screen that became pressable.

   A KPI tile is now an <a> to the rows behind its figure, and a table row is
   an <a> in all but name. Both need the anchor reset that .gp-btn already
   carries - an unstyled link inside a card inherits the theme's blue and an
   underline, which on a 20px money figure reads as a defect.
   =========================================================================== */

a.gp-kpi{display:block;color:inherit;text-decoration:none;transition:border-color .15s,box-shadow .15s}
a.gp-kpi:hover{border-color:var(--text-3);box-shadow:var(--shadow-md);text-decoration:none;color:inherit}
a.gp-kpi.is-on{border-color:var(--accent)}
a.gp-kpi .gp-kpi-value{color:var(--text)}
a.gp-kpi.gp-kpi-warn .gp-kpi-value{color:var(--warn)}
a.gp-kpi.gp-kpi-err .gp-kpi-value{color:var(--err)}
a.gp-kpi.gp-kpi-accent .gp-kpi-value{color:var(--accent)}

/* The row opens its invoice, so it says so under the cursor. Scoped to the
   invoice list's own body - the other panel tables have no row link yet, and a
   pointer over a row that does nothing is a promise the page cannot keep. */
#invoice_list_body tr{cursor:pointer}

/* ===========================================================================
   The empty state.

   A filter that matches nothing rendered a header with nothing under it: the
   same picture as a table still loading, and the same picture as a table that
   failed. The row template now emits one row saying which of the three it is.
   =========================================================================== */

.gp-page .tbl-empty td{padding:56px 20px;text-align:center;border-bottom:none}
.gp-page .tbl-empty .tbl-empty-t{font-size:14.5px;font-weight:600;color:var(--text-2)}
.gp-page .tbl-empty .tbl-empty-s{margin:7px 0 0;font-size:13px;color:var(--text-3)}
.gp-page .tbl-empty .material-icons-outlined{font-size:30px;color:var(--text-4)}
.tbl-empty td{padding:40px 20px;text-align:center;color:#6b7280}


/* ===========================================================================
   The new-invoice screen.

   A form on the start side and a summary that follows the operator down the
   page on the end side. The summary is not decoration: raising a payment link
   is irreversible in the way that matters - the client is sent a number and a
   deadline - so the screen says what is about to be created while there is
   still time to change it.
   =========================================================================== */

/* Follows the scroll, stopping clear of the top bar (sticky, 66px) and of the
   sticky Create bar at the foot. */
.gp-sticky{position:sticky;top:90px}

/* The chosen client, drawn as the record it is rather than as a line of text
   in a box: initials, name, and the CPR and mobile that are what an operator
   checks they picked the right person by. */
.gp-picked{display:flex;align-items:center;gap:14px;padding:12px 14px;background:var(--field);border:1px solid var(--field-b);border-radius:8px}
.gp-picked.is-empty{background:var(--surface-3)}
.gp-picked .gp-picked-text{flex:1;min-width:0}
.gp-picked .gp-picked-name{display:block;font-size:14.5px;font-weight:600;color:var(--text)}
.gp-picked.is-empty .gp-picked-name{font-weight:500;color:var(--text-4)}
.gp-picked .gp-picked-meta{display:block;margin:4px 0 0;font-size:12.5px;color:var(--text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gp-picked .gp-btn{height:38px;flex:0 0 auto}
.gp-picked.is-empty .gp-ini{color:var(--text-4)}

/* A delivery switch with nowhere to send to. Locked rather than hidden: the
   channel still exists, and an operator who cannot see the switch cannot see
   why the invoice went out without a text either. */
.gp-switch-row.is-off .gp-switch-label{color:var(--text-3)}
.gp-switch-row.is-off .gp-switch-hint{color:var(--warn)}
.gp-switch:disabled{opacity:.45;cursor:not-allowed}

/* An amount that has been typed wrong. .is-invalid is bootstrap's class and
   the theme paints it on .form-control only, which these fields are not. */
.gp-input.is-invalid,.gp-amountfield:has(.is-invalid){border-color:var(--err)}

/* On one column the summary stops following - a panel that sticks on a phone
   covers the form it describes. */
@media (max-width:1180px){
    .gp-sticky{position:static}
}


/* ===== Reports: the custom window ======================================== */

.gp-period{display:flex;align-items:flex-end;gap:14px;flex-wrap:wrap;margin:0 0 22px;padding:16px 18px;
    background:var(--surface);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-sm)}
.gp-period .gp-field{min-width:170px}
.gp-period .gp-input{height:40px;font-size:13.5px}
.gp-period .gp-label{margin:0 0 6px}


/* ===========================================================================
   Print.

   A report is a thing people take into a meeting, so it has to survive a
   printer. What goes is everything that is not the figures: the navigation,
   the buttons that cannot be pressed on paper, the window switcher.

   Backgrounds are forced to print with -webkit-print-color-adjust, because
   without it browsers drop them and the bars - which ARE the data - come out
   as empty outlines.
   =========================================================================== */

@media print{

    /* Chrome and controls: gone. */
    .gp-topnav,
    .gp-print-hide,
    .gp-seg,
    .gp-period,
    .tblx-head,
    .tblx-drawer,
    .filter-panel,
    .status-bar{display:none !important}

    /* The page itself, not a viewport. */
    html,body{background:#fff !important}
    .wrap{max-width:none;padding:0}
    .gp-page{padding:0}

    /* Cards keep their edges but lose the lift - a shadow prints as grey mud. */
    .gp-card,.gp-panel,.gp-kpi,.tblx-toolbar{
        box-shadow:none !important;
        border:1px solid #ccc !important;
        break-inside:avoid;
        page-break-inside:avoid}

    /* The bars and pills are data. Keep their fill. */
    .gp-trend-bar,.gp-bar-fill,.gp-pill,.gp-tag,.gp-kpi-value{
        -webkit-print-color-adjust:exact;
        print-color-adjust:exact}

    /* Don't split a panel across a page break if it can be helped. */
    .gp-split,.gp-split-even{display:block}
    .gp-split>*,.gp-split-even>*{margin-bottom:16px}

    .gp-kpis{grid-template-columns:repeat(4,minmax(0,1fr))}

    /* A URL printed after every link is noise on a report full of them. */
    a[href]:after{content:none !important}
}


/* ===========================================================================
   THE PANEL'S TABLES ON A NARROWER WINDOW.

   Eight columns of invoice do not fit a laptop, and what happened until now was
   that the last of them - Status, the one an operator scans FIRST - ran off the
   right-hand edge. The table scrolled sideways to reach it, which is a thing
   nobody discovers on a list they read top to bottom.

   So the columns that matter least go first, in order, as the window narrows.
   Nothing is lost: the wrapper still scrolls, the Columns button still lists
   every one of them, and at full width they are all back.

   BY FIELD NAME, NOT BY POSITION. An operator can drag the columns into another
   order and the browser remembers it, so nth-child would hide whichever column
   happened to have been moved into that slot. js_table.html stamps
   data-col-field onto every th and every cell from the declaration's own key,
   which is stable however they are arranged.

   The order things go, and why:

     Method    "Not paid yet" on every unpaid row - it says something only after
               the money has arrived, and by then the Status pill has said it too
     Item      what was sold, which the invoice page shows properly
     Expires   worth keeping as long as possible; it is the column the morning's
               worklist is built from

   Customer, Amount and Status stay to the end. An invoice with no name, no
   figure and no state is not a list anybody can work from.
   =========================================================================== */

@media (max-width:1400px){
    .gp-page .dynamic-table [data-col-field="Code_method_cell"],
    .gp-page .dynamic-table th[data-col-field="Code_method_cell"]{display:none}
}

@media (max-width:1180px){
    .gp-page .dynamic-table [data-col-field="Code_item_cell"],
    .gp-page .dynamic-table th[data-col-field="Code_item_cell"]{display:none}

    /* The gutters go before the content does. */
    .gp-page table.dynamic-table>thead th,
    .gp-page table.dynamic-table>tbody td{padding:12px 10px}
    .gp-page table.dynamic-table>thead th:first-child,
    .gp-page table.dynamic-table>tbody td:first-child{padding-left:14px}
    .gp-page table.dynamic-table>thead th:last-child,
    .gp-page table.dynamic-table>tbody td:last-child{padding-right:14px}
}

@media (max-width:920px){
    .gp-page .dynamic-table [data-col-field="Code_expiry_cell"],
    .gp-page .dynamic-table th[data-col-field="Code_expiry_cell"]{display:none}

    /* The seventeen-digit code is the widest thing in the first column and the
       least likely to be read on a phone - the reference above it is what an
       operator recognises a row by. Kept in the DOM: it is what the general
       search matches, and the invoice page shows it in full. */
    .gp-page .dynamic-table .gp-cell-mono{display:none}
}

/* The toolbar wraps rather than pushing the table wider than the card. */
@media (max-width:760px){
    .gp-page .tblx-head{flex-wrap:wrap}
    .gp-page .tblx-tools{flex-wrap:wrap;width:100%}
    .gp-page .tblx-search{flex:1 1 100%}
}

/* Whatever is still too wide scrolls sideways rather than being cut off. */
.gp-page .table-wrapper{overflow-x:auto;-webkit-overflow-scrolling:touch}
