/* =========================================================
   Team area: parts & billing.
   Loaded after css/style.css and css/racing.css.

   racing.css carries the data-page primitives this page reuses as-is:
   .rstats, .rtabs/.rtab, .rpanel, .dt/.tablewrap, .chip, .fgroup,
   .sortbar, .filters, .rcount, .rsec__head, .srcnote, .scroll-fade-x.
   Only genuinely new components live here. teams.css is NOT loaded: the
   only things worth taking from it were the card grid and the modal, and
   a part card and an invoice sheet want different furniture from a livery
   card, so both are written fresh below.

   css/checkout.css also loads this file, for the toast, the confirm
   dialog, and the button variants.

    1. tokens               7. catalogue + part cards
    2. buttons + notices    8. quantity stepper
    3. toasts + confirm     9. cart drawer
    4. sign in             10. history + timeline
    5. page header         11. print
    6. billing + invoices  12. reduced motion  13. responsive
   ========================================================= */

/* ---------- 1. tokens ----------
   The site had no semantic layer, only domain tokens for racing classes in
   racing.css. These are the status equivalents, named for meaning rather
   than colour so a repaint is one edit.

   Base / soft pairs follow the Porsche notification tokens. The base is the
   foreground, the soft is the field behind it. --status-paid is the one
   exception: notificationSuccess green (#197E10) reads at about 2.4:1 on
   #0a0a0b, well under the 4.5:1 a text label needs, so the paid chip uses
   a lightened foreground over the soft field instead of the raw token.
   Every status also carries a text label and a shape, never colour alone. */
:root{
  --status-unpaid:     rgba(255,255,255,.72);
  --status-due:        #F3BE00;
  --status-overdue:    #FF6A6A;   /* lifted from #FC4040 to clear 4.5:1 */
  --status-processing: #7CA5FF;   /* lifted from #2762EC, same reason */
  --status-paid:       #56C95C;   /* lifted from #197E10, same reason */
  --status-disputed:   #F3BE00;

  --status-unpaid-soft:     rgba(255,255,255,.08);
  --status-due-soft:        rgba(243,190,0,.14);
  --status-overdue-soft:    rgba(252,64,64,.14);
  --status-processing-soft: rgba(39,98,236,.18);
  --status-paid-soft:       rgba(25,126,16,.22);

  --p-card:#101114;
  --p-card-2:#0d0e11;
  --p-row:rgba(255,255,255,.09);
  --p-row-hover:rgba(255,255,255,.045);

  /* --edge / --edge-hover / --surf / --surf-hover / --r-card moved to
     css/style.css: join.html reuses .notice and the card surfaces without
     loading this file. */
}

.ppage{padding-top:var(--nav-h)}

/* status chip. ::before is a shape, not decoration: it differs per status so
   the chips stay distinguishable in greyscale and to colour-blind readers. */
.st{
  display:inline-flex;align-items:center;gap:7px;height:23px;padding:0 9px;
  border-radius:3px;white-space:nowrap;
  font-size:.625rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase
}
.st::before{content:"";width:6px;height:6px;flex:none;background:currentColor;border-radius:50%}
.st--unpaid{color:var(--status-unpaid);background:var(--status-unpaid-soft)}
.st--unpaid::before{border-radius:0}                                  /* square */
.st--due{color:var(--status-due);background:var(--status-due-soft)}
.st--due::before{border-radius:0;transform:rotate(45deg);width:5px;height:5px} /* diamond */
.st--overdue{color:var(--status-overdue);background:var(--status-overdue-soft)}
.st--overdue::before{
  background:none;width:0;height:0;border-radius:0;                   /* triangle */
  border-left:4px solid transparent;border-right:4px solid transparent;
  border-bottom:7px solid currentColor
}
.st--processing{color:var(--status-processing);background:var(--status-processing-soft)}
.st--paid{color:var(--status-paid);background:var(--status-paid-soft)}
.st--paid::before{
  background:none;width:9px;height:5px;border-radius:0;               /* tick */
  border-left:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:rotate(-45deg) translate(1px,-1px)
}
.st--disputed{
  color:var(--status-disputed);background:transparent;
  box-shadow:inset 0 0 0 1px currentColor
}
.st--disputed::before{border-radius:0;transform:rotate(45deg);width:5px;height:5px}
.st--ready{color:var(--status-paid);background:transparent;box-shadow:inset 0 0 0 1px currentColor}

/* sample-data badge, same treatment as teams.html */
.pbadge{
  display:inline-flex;align-items:center;height:20px;padding:0 7px;border-radius:3px;
  font-size:.5625rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--status-due);background:rgba(22,17,2,.7)
}

/* ---------- 3. toasts + confirm ---------- */
.toasts{
  position:fixed;left:50%;bottom:24px;translate:-50% 0;z-index:500;
  display:flex;flex-direction:column;gap:10px;align-items:center;
  width:min(440px,calc(100vw - 2 * var(--pad)));pointer-events:none
}
.toast{
  display:flex;align-items:center;gap:12px;width:100%;
  padding:13px 18px;border-radius:var(--r);
  background:#16181c;border:1px solid rgba(255,255,255,.1);
  box-shadow:0 12px 34px rgba(0,0,0,.5);
  font-size:.875rem;color:rgba(255,255,255,.88);
  opacity:0;transform:translateY(12px);
  transition:opacity var(--t1),transform .4s var(--ease)
}
.toast.is-on{opacity:1;transform:none}
.toast__dot{width:6px;height:6px;border-radius:50%;flex:none;background:rgba(255,255,255,.5)}
.toast--ok .toast__dot{background:var(--status-paid)}
.toast--bad .toast__dot{background:var(--status-overdue)}
.toast--info .toast__dot{background:var(--status-processing)}

.cfm{position:fixed;inset:0;z-index:520;display:grid;place-items:center;padding:var(--pad)}
.cfm__scrim{
  position:absolute;inset:0;background:rgba(4,4,5,.74);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  opacity:0;transition:opacity var(--t1)
}
.cfm.is-on .cfm__scrim{opacity:1}
.cfm__box{
  position:relative;width:min(440px,100%);padding:clamp(22px,3vw,30px);
  background:#101216;border:1px solid rgba(255,255,255,.1);
  border-radius:calc(var(--r) + 4px);
  box-shadow:0 24px 60px rgba(0,0,0,.6);
  opacity:0;transform:translateY(14px) scale(.98);
  transition:opacity var(--t1),transform .3s var(--ease)
}
.cfm.is-on .cfm__box{opacity:1;transform:none}
.cfm__title{font-size:1.0625rem;font-weight:700;margin-bottom:10px}
.cfm__body{font-size:.875rem;line-height:1.6;color:rgba(255,255,255,.66)}
.cfm__row{display:flex;flex-wrap:wrap;gap:10px;justify-content:flex-end;margin-top:22px}

/* ---------- 4. sign in ----------
   Replaces the whole of <main>. Nothing behind it is rendered — the gate is
   not a visual overlay over live data, because the data is not there. */
.signin{
  max-width:var(--wrap);margin-inline:auto;
  padding:clamp(48px,9vw,120px) var(--pad) clamp(56px,8vw,120px);
  display:grid;grid-template-columns:minmax(0,440px) minmax(0,1fr);
  gap:clamp(28px,5vw,80px);align-items:start
}
.signin__title{
  font-size:clamp(2rem,1rem + 4.4vw,4.5rem);font-weight:700;
  line-height:.98;letter-spacing:-.02em;margin-bottom:14px
}
.signin__sub{font-size:.9375rem;color:rgba(255,255,255,.62);max-width:40ch}
.signin__form{margin-top:clamp(24px,3vw,34px)}
.field--code{display:grid;gap:8px;max-width:340px}
.field--code label{
  font-size:.625rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;
  color:rgba(255,255,255,.5)
}
.field--code input{
  height:52px;padding:0 16px;border-radius:var(--r);
  background:rgba(255,255,255,.04);border:1px solid var(--edge);color:#fff;
  font-size:1rem;letter-spacing:.1em;
  transition:border-color var(--t1),background-color var(--t1)
}
.field--code input::placeholder{color:rgba(255,255,255,.28)}
.field--code input:hover{border-color:var(--edge-hover)}
.field--code input:focus-visible{border-color:rgba(255,255,255,.45)}
.field--code input[aria-invalid="true"]{border-color:var(--status-overdue);background:var(--status-overdue-soft)}
.ferr{min-height:1.2em;font-size:.8125rem;color:var(--status-overdue)}
.ferr:empty{min-height:0}
.signin__cta{margin-top:16px}
.signin__help{margin-top:22px;font-size:.8125rem;color:rgba(255,255,255,.5)}

/* the demo codes, deliberately quiet: it is a hint, not a call to action */
.demohint{
  padding:clamp(20px,2.6vw,28px);border-radius:var(--r-card);
  background:rgba(255,255,255,.03);border:1px solid var(--edge)
}
.demohint__k{
  font-size:.625rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;
  color:rgba(255,255,255,.42);margin-bottom:12px
}
.demohint p{font-size:.8125rem;line-height:1.7;color:rgba(255,255,255,.55)}
.demohint code{
  display:inline-block;margin:6px 6px 0 0;padding:4px 9px;border-radius:3px;
  background:rgba(255,255,255,.08);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.75rem;letter-spacing:.06em;color:rgba(255,255,255,.85)
}

/* ---------- 5. page header ----------
   One band. The identity and the balance are a single left column so nothing
   floats between them, and the car spans the full height of the right column
   so it has something to sit against. Behind it all, the car number set
   enormous and hollow — the thing that fills the half of the header the
   layout used to leave empty. */
.phead{
  position:relative;isolation:isolate;overflow:hidden;
  max-width:var(--wrap);margin-inline:auto;
  padding:clamp(26px,4vw,48px) var(--pad) clamp(26px,3.4vw,40px);
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,42%);
  align-items:center;gap:clamp(16px,3vw,40px)
}
.phead__body{min-width:0}
.phead__id{display:flex;flex-wrap:wrap;align-items:center;gap:14px}
.phead__title{
  font-size:clamp(2rem,1rem + 4.2vw,4.25rem);font-weight:700;
  line-height:.95;letter-spacing:-.035em
}

/* the car number, hollow, behind everything */
.phead__ghost{
  position:absolute;z-index:-1;pointer-events:none;user-select:none;
  /* bled off the bottom edge and tucked behind the car, the way a number
     sits on a garage wall. Cropped by the header's overflow:hidden. */
  right:clamp(8px,7vw,120px);bottom:-.3em;
  font-size:clamp(12rem,32vw,30rem);font-weight:700;line-height:.7;
  letter-spacing:-.07em;font-variant-numeric:tabular-nums;
  color:transparent;-webkit-text-stroke:1.5px rgba(255,255,255,.085)
}
/* -webkit-text-stroke is not universal; without it the number would paint as
   a solid slab over the header, so anything that cannot hollow it hides it */
@supports not (-webkit-text-stroke:1px #000){ .phead__ghost{display:none} }

/* Livery stripe: the team's two colours cut on the diagonal, the way they
   meet on a car's flank. Replaces two small swatches that read as a legend. */
.phead__stripe{
  display:block;width:clamp(120px,17vw,190px);height:7px;margin-top:18px;
  background:linear-gradient(100deg,
    rgb(var(--c)) 0 46%, rgb(var(--c2)) 46% 100%)
}

/* The livery render. Ornament, so it never takes a click. No wash behind it:
   the car carries the team's colours already, and a second coloured field in
   the header only competed with the balance figure. */
.phead__car{
  position:relative;isolation:isolate;margin:0;justify-self:end;
  width:min(100%,540px);
  pointer-events:none;user-select:none
}
/* Sign out is a utility, not part of the composition — it sits out of the
   way in the corner rather than stacked above the car. */
.phead__out{position:absolute;top:clamp(20px,2.6vw,30px);right:var(--pad);z-index:2}
/* The shadow is a blurred ellipse behind the image, not drop-shadow() on the
   <img>: on a raster this wide the filter is expensive and traces every
   wing-mirror and aerial instead of reading as a car on a floor. */
.phead__car::after{
  content:"";position:absolute;left:12%;right:12%;bottom:2%;height:16px;
  border-radius:50%;background:rgba(0,0,0,.6);filter:blur(14px);z-index:-1
}
/* height:auto is required. The height attribute is in the markup so the space
   is reserved before the webp decodes, and without this the image renders at
   that literal height. */
.phead__car img{width:100%;height:auto}
/* no artwork on file: the silhouette is dimmed, not shadowed */
.phead__car--nolivery img{opacity:.45}
.phead__car--nolivery::after{display:none}

/* The balance is the one number the page exists to show, so it gets the
   display scale and everything else steps down from it. */
.phead__bal{margin-top:clamp(22px,3vw,34px)}
.phead__balk{
  font-size:.625rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;
  color:rgba(255,255,255,.5);margin-bottom:10px
}
.phead__balv{
  font-size:clamp(2.5rem,1rem + 6vw,5.5rem);font-weight:700;
  line-height:.9;letter-spacing:-.04em;font-variant-numeric:tabular-nums
}
.phead__balv.is-clear{font-size:clamp(1.75rem,1rem + 3vw,3rem);color:var(--status-paid)}
.phead__balsub{margin-top:14px;font-size:.9375rem;color:rgba(255,255,255,.6)}
.phead__balsub b{color:var(--status-overdue);font-weight:400}

/* ---------- 6. billing + invoices ---------- */
/* Six status chips plus three sort chips do not fit a 375px viewport, and
   .filters from racing.css only wraps — so on a phone the last chip sat off
   the right edge with no way to reach it. Each group scrolls on its own
   instead, with the same edge fade the tab rail uses. Scoped to .ppage so
   racing.html and teams.html keep the behaviour they already have. */
/* Chips keep the pill, on the soft edge rather than the hard --line one.
   The pressed state stays a solid fill: it is the only way to read the
   active filter at a glance across a rail of nine. */
.ppage .chip{
  flex:none;white-space:nowrap;
  height:32px;padding:0 13px;border-radius:var(--r);
  border:1px solid var(--edge);background:transparent;
  color:rgba(255,255,255,.68)
}
.ppage .chip:hover{color:#fff;border-color:var(--edge-hover);background:rgba(255,255,255,.04)}
.ppage .chip[aria-pressed="true"]{background:#fff;color:var(--ink);border-color:#fff;font-weight:700}
.ppage .filters{align-items:stretch}
.ppage .filters .fgroup{
  min-width:0;max-width:100%;
  overflow-x:auto;scrollbar-width:none;padding-bottom:2px
}
.ppage .filters .fgroup::-webkit-scrollbar{display:none}
.ppage .filters .fgroup__k{flex:none;position:sticky;left:0;background:var(--ink);z-index:1}

.invhead{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:18px}

.invlist{display:grid;gap:8px}

/* One component, two layouts. Above 900px an invoice is a five-track grid
   that lines the amounts up into a column you can read down. Below, it
   becomes a card and the tracks stack — the same DOM either way, because a
   table that turns into cards by re-rendering loses the checkbox state. */
/* Read as a timing-screen row, not a table row: a race-number tag on the
   left, then the identity, then the figure set large enough to scan down a
   column of them. The old version put everything at 13-15px and let the
   amount sit at the same weight as the metadata, which is what made it look
   like a generic dashboard. */
.inv{
  position:relative;overflow:hidden;
  display:grid;
  grid-template-columns:auto auto minmax(0,1fr) auto auto;
  align-items:center;gap:clamp(12px,1.6vw,20px);
  padding:16px clamp(14px,1.8vw,20px) 16px 0;
  background:var(--surf);
  border:1px solid var(--edge);border-radius:var(--r-card);
  transition:background-color var(--t1),border-color var(--t1)
}
.inv:hover{background:var(--surf-hover);border-color:var(--edge-hover)}
/* the status edge rides inside the rounded corner, hence overflow:hidden.
   It widens on hover — the row's only movement, and it reads as the row
   arming rather than as a card lifting. */
.inv::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:4px;
  background:rgba(255,255,255,.16);
  transition:width .4s var(--ease)
}
.inv:hover::before,.inv.is-sel::before{width:7px}
.no-motion .inv::before{transition:none}

/* race-number board */
.inv__tag{
  display:grid;justify-items:center;gap:3px;
  min-width:58px;padding:2px 12px 2px 0;
  border-right:1px solid var(--edge)
}
.inv__tagk{
  font-size:.5rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;
  color:rgba(255,255,255,.38)
}
.inv__tagv{
  font-size:1.5rem;font-weight:700;line-height:1;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;color:rgba(255,255,255,.9)
}
.inv--overdue .inv__tagv{color:var(--status-overdue)}
.inv--due .inv__tagv{color:var(--status-due)}
.inv--overdue::before{background:var(--status-overdue)}
.inv--due::before{background:var(--status-due)}
.inv--processing::before{background:var(--status-processing)}
.inv--paid::before{background:var(--status-paid)}
.inv--disputed::before{background:var(--status-disputed)}
.inv.is-sel{background:#171a20;border-color:rgba(255,255,255,.26)}

.inv__pick{display:grid;place-items:center;width:22px;margin-left:clamp(14px,1.8vw,20px)}
.inv__pick input{
  width:18px;height:18px;margin:0;accent-color:rgb(var(--accent));cursor:pointer
}
.inv__pick input:disabled{cursor:not-allowed;opacity:.35}

.inv__main{min-width:0}
.inv__top{display:flex;flex-wrap:wrap;align-items:center;gap:9px}
.inv__id{
  font-size:1.0625rem;font-weight:700;letter-spacing:.05em;
  font-variant-numeric:tabular-nums
}
/* the circuit and dates, set like a session header rather than body copy */
.inv__ctx{
  margin-top:6px;font-size:.75rem;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:rgba(255,255,255,.72)
}
.inv__meta{margin-top:4px;font-size:.75rem;color:rgba(255,255,255,.42)}
.inv__meta b{font-weight:700;color:var(--status-overdue)}
.inv__meta .due-soon{color:var(--status-due);font-weight:700}

/* the figure of the row. Large, tabular and tight, so a column of them
   reads down the page the way a results screen does. */
.inv__money{text-align:right}
.inv__amt{
  font-size:clamp(1.375rem,1rem + 1vw,1.875rem);font-weight:700;
  line-height:1;letter-spacing:-.025em;white-space:nowrap;
  font-variant-numeric:tabular-nums
}
.inv__amtk{
  margin-top:6px;font-size:.5rem;font-weight:700;letter-spacing:.18em;
  text-transform:uppercase;color:rgba(255,255,255,.36)
}
.inv__act{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end}

/* sticky multi-select bar: appears at one selected, gone at zero */
.invsel{
  position:sticky;bottom:0;z-index:40;margin-top:12px;
  display:flex;flex-wrap:wrap;align-items:center;gap:14px;
  padding:15px clamp(14px,1.8vw,20px);
  background:rgba(16,18,22,.94);
  -webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);
  border:1px solid rgba(255,255,255,.18);border-radius:var(--r-card)
}
.invsel__n{font-size:.9375rem;font-weight:700;font-variant-numeric:tabular-nums}
.invsel__act{margin-left:auto;display:flex;flex-wrap:wrap;gap:8px}

/* empty state, shared by all four panels */
.pempty{
  padding:clamp(44px,7vw,88px) clamp(20px,3vw,40px);text-align:center;
  background:var(--surf);border:1px solid var(--edge);border-radius:var(--r-card)
}
.pempty__t{font-size:1.125rem;font-weight:700;margin-bottom:10px}
.pempty__b{font-size:.875rem;line-height:1.7;color:rgba(255,255,255,.55);max-width:46ch;margin-inline:auto}

/* ---------- invoice / receipt modal ---------- */
.pmodal{position:fixed;inset:0;z-index:450;display:grid;place-items:center;padding:var(--pad)}
.pmodal__scrim{
  position:absolute;inset:0;background:rgba(4,4,5,.76);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  opacity:0;transition:opacity var(--t2)
}
.pmodal.is-on .pmodal__scrim{opacity:1}
.pmodal__box{
  position:relative;width:min(720px,100%);max-height:calc(100vh - 2 * var(--pad));
  overflow-y:auto;overscroll-behavior:contain;
  background:#101216;border:1px solid rgba(255,255,255,.1);
  border-radius:calc(var(--r) + 6px);
  box-shadow:0 30px 80px rgba(0,0,0,.6);
  opacity:0;transform:translateY(18px);
  transition:opacity var(--t1),transform .4s var(--ease)
}
.pmodal.is-on .pmodal__box{opacity:1;transform:none}
.pm__head{
  position:relative;padding:clamp(22px,3vw,32px);
  border-bottom:1px solid var(--line)
}
.pm__x{
  position:absolute;right:12px;top:12px;width:40px;height:40px;
  display:grid;place-items:center;border-radius:var(--r);
  background:rgba(255,255,255,.06);transition:background-color var(--t1)
}
.pm__x:hover{background:rgb(var(--accent))}
.pm__k{
  font-size:.625rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;
  color:rgba(255,255,255,.45);margin-bottom:10px
}
.pm__id{
  display:flex;flex-wrap:wrap;align-items:center;gap:12px;
  font-size:clamp(1.25rem,1rem + 1.2vw,1.75rem);font-weight:700;
  font-variant-numeric:tabular-nums;padding-right:48px
}
.pm__facts{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:18px;
  padding:clamp(20px,2.6vw,28px) clamp(22px,3vw,32px);border-bottom:1px solid var(--line)
}
.pm__fk{font-size:.5625rem;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.42);margin-bottom:6px}
.pm__fv{font-size:.9375rem}
.pm__body{padding:clamp(20px,2.6vw,28px) clamp(22px,3vw,32px)}

/* line items. scope="row" is on the item cell, so the name is what a screen
   reader reads back for each amount. */
.pm__lines{width:100%;border-collapse:collapse;font-size:.875rem}
/* thead th only. The row header is `th scope="row"` on the item name, so
   letting the column-header rules cascade into tbody set every part name in
   9px uppercase. */
.pm__lines thead th{
  padding:0 0 10px;text-align:left;
  font-size:.5625rem;font-weight:700;letter-spacing:.18em;text-transform:uppercase;
  color:rgba(255,255,255,.42);border-bottom:1px solid var(--line)
}
.pm__lines tbody th{
  padding:12px 0;text-align:left;font-weight:400;
  border-bottom:1px solid var(--p-row);vertical-align:top
}
.pm__lines td{padding:12px 0;border-bottom:1px solid var(--p-row);vertical-align:top}
.pm__lines th.r,.pm__lines td.r{text-align:right;white-space:nowrap}
.pm__lines td.r{font-variant-numeric:tabular-nums}
.pm__lines th:not(:first-child),.pm__lines td:not(:first-child){padding-left:14px}
.pm__lines tbody th{padding-right:14px}
.pm__ln{font-weight:700}
.pm__lspec{display:block;margin-top:3px;font-size:.75rem;font-weight:400;color:rgba(255,255,255,.45)}

.pm__sums{margin-top:20px;display:grid;gap:9px;justify-content:end}
.pm__sum{display:grid;grid-template-columns:auto minmax(120px,auto);gap:28px;font-size:.875rem;color:rgba(255,255,255,.7)}
.pm__sum span:last-child{text-align:right;font-variant-numeric:tabular-nums}
.pm__sum--total{
  margin-top:6px;padding-top:12px;border-top:1px solid var(--line);
  font-size:1.25rem;font-weight:700;color:#fff
}
.pm__foot{
  display:flex;flex-wrap:wrap;align-items:center;gap:12px;
  padding:clamp(18px,2.4vw,24px) clamp(22px,3vw,32px);
  border-top:1px solid var(--line);background:rgba(255,255,255,.02)
}
.pm__foot .pm__spacer{margin-left:auto}
.pm__pay{
  display:grid;gap:6px;font-size:.8125rem;color:rgba(255,255,255,.6)
}
.pm__pay b{color:#fff;font-weight:400}
.pm__ref{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.75rem;letter-spacing:.02em}

/* The cart lives on the tab rail, but it is not a tab: it opens a drawer.
   So it is a plain button with aria-expanded, sits outside the tablist
   element, and is set apart by the divider. */
.rtabs__tabs{display:flex;gap:clamp(4px,1.4vw,22px);min-width:0}
.rtab--cart{
  display:inline-flex;align-items:center;gap:8px;
  height:34px;align-self:center;padding:0 13px;border-radius:var(--r);
  border:1px solid var(--edge);color:rgba(255,255,255,.75);font-size:.8125rem;
  transition:background-color var(--t1),border-color var(--t1),color var(--t1)
}
.rtab--cart:hover{color:#fff;border-color:var(--edge-hover);background:rgba(255,255,255,.05)}
.rtab--cart[aria-expanded="true"]{background:#fff;color:var(--ink);border-color:#fff;font-weight:700}

/* ---------- 7. catalogue + part cards ---------- */
.pctl{display:grid;gap:14px;margin-bottom:22px;padding-bottom:20px;border-bottom:1px solid var(--line)}
.pctl__row{display:flex;flex-wrap:wrap;align-items:center;gap:10px}
.pctl__row .fgroup__k{flex:none}
/* the category rail is long: it scrolls rather than wrapping to four lines */
.pctl__rail{
  display:flex;gap:8px;overflow-x:auto;scrollbar-width:none;
  padding-bottom:2px;min-width:0;flex:1
}
.pctl__rail::-webkit-scrollbar{display:none}
.pctl__count{margin-left:auto;font-size:.8125rem;color:rgba(255,255,255,.45);font-variant-numeric:tabular-nums;flex:none}

.chip--on{background:#fff;color:var(--ink);border-color:#fff;font-weight:700}
.chip--icon{display:inline-flex;align-items:center;gap:7px}

.pgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(12px,1.4vw,18px)}
.pgrid--list{grid-template-columns:1fr;gap:8px}

.pcard{
  display:flex;flex-direction:column;min-width:0;overflow:hidden;
  background:var(--surf);
  border:1px solid var(--edge);border-radius:var(--r-card);
  transition:border-color var(--t1),background-color var(--t1)
}
.pcard:hover{border-color:var(--edge-hover);background:var(--surf-hover)}
.pcard__art{
  position:relative;aspect-ratio:16/10;background:#0b0c0e;
  display:grid;place-items:center;overflow:hidden
}
.pcard__art img,.pcard__art svg{width:100%;height:100%;object-fit:cover}
/* the category placeholder is a line drawing, not a photo: it sits inset so
   it never reads as a badly cropped image */
.pcard__art svg{width:66%;height:66%;object-fit:contain;opacity:.5}
.pcard__flags{position:absolute;left:10px;top:10px;display:flex;flex-wrap:wrap;gap:6px;max-width:calc(100% - 20px)}
.pflag{
  display:inline-flex;align-items:center;height:20px;padding:0 7px;border-radius:3px;
  font-size:.5625rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  background:rgba(8,9,11,.82);color:rgba(255,255,255,.82);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)
}
.pflag--spec{color:#9ec8ff}
.pflag--mand{color:var(--status-due)}
.pflag--low{color:var(--status-due)}
.pflag--out{color:var(--status-overdue)}

.pcard__body{padding:14px clamp(13px,1.4vw,17px) 16px;display:flex;flex-direction:column;flex:1;gap:8px}
.pcard__cat{font-size:.5625rem;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.4)}
.pcard__name{font-size:.9375rem;font-weight:700;line-height:1.3}
.pcard__spec{font-size:.75rem;color:rgba(255,255,255,.5)}
.pcard__desc{font-size:.8125rem;line-height:1.6;color:rgba(255,255,255,.55)}
.pcard__price{margin-top:auto;display:flex;flex-wrap:wrap;align-items:baseline;gap:7px}
.pcard__pv{font-size:1.125rem;font-weight:700;font-variant-numeric:tabular-nums}
.pcard__pu{font-size:.75rem;color:rgba(255,255,255,.45)}
.pcard__stock{display:flex;align-items:center;gap:7px;font-size:.75rem;color:rgba(255,255,255,.6)}
.pcard__stock::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--status-paid);flex:none}
.pcard--low .pcard__stock::before{background:var(--status-due)}
.pcard--out .pcard__stock::before{background:var(--status-overdue)}
.pcard__foot{display:flex;align-items:center;gap:10px;padding-top:4px}
.pcard__foot .btn--sm{flex:1;min-height:38px;padding:0 12px;font-size:.8125rem}

/* does-not-fit: still listed, so the team can see the part exists, but it
   cannot be ordered and the reason is written on the card */
.pcard--nofit{opacity:.5}
.pcard--nofit:hover{border-color:var(--line)}
.pcard__nofit{
  display:flex;align-items:center;gap:7px;font-size:.75rem;color:var(--status-overdue)
}

/* list view: the same card, laid out as a row */
.pgrid--list .pcard{flex-direction:row;align-items:stretch}
.pgrid--list .pcard__art{aspect-ratio:auto;width:118px;flex:none}
.pgrid--list .pcard__body{
  flex-direction:row;align-items:center;gap:clamp(12px,1.6vw,22px);flex-wrap:wrap
}
.pgrid--list .pcard__desc{display:none}
.pgrid--list .pcard__txt{flex:1;min-width:180px}
.pgrid--list .pcard__price{margin-top:0}
.pgrid--list .pcard__foot{padding-top:0;margin-left:auto}
.pgrid--list .pcard__foot .btn--sm{flex:none}

/* ---------- 8. quantity stepper ----------
   Real buttons and a real labelled input. A div with a click handler cannot
   be reached by keyboard and is not announced as a control. */
.qty{
  display:inline-flex;align-items:center;flex:none;
  border:1px solid var(--edge);border-radius:var(--r);overflow:hidden
}
.qty button{
  width:32px;height:36px;display:grid;place-items:center;
  color:rgba(255,255,255,.75);font-size:1rem;line-height:1;
  transition:background-color var(--t1),color var(--t1)
}
.qty button:hover:not(:disabled){background:rgba(255,255,255,.1);color:#fff}
.qty button:disabled{opacity:.3;cursor:not-allowed}
.qty input{
  width:38px;height:36px;padding:0;border:0;background:transparent;text-align:center;
  font-size:.875rem;font-weight:700;font-variant-numeric:tabular-nums;
  -moz-appearance:textfield;appearance:textfield
}
.qty input::-webkit-outer-spin-button,.qty input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}

/* ---------- 9. cart drawer ---------- */
.cart{
  position:fixed;inset:0 0 0 auto;z-index:460;
  width:min(420px,100vw);background:var(--p-card-2);border-left:1px solid var(--line);
  display:flex;flex-direction:column;
  transform:translateX(100%);transition:transform var(--t3) var(--ease)
}
.cart.is-on{transform:none}
.cart__head{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:18px 20px;border-bottom:1px solid var(--line);flex:none
}
.cart__title{font-size:1rem;font-weight:700}
.cart__x{width:40px;height:40px;display:grid;place-items:center;border-radius:var(--r);flex:none}
.cart__x:hover{background:rgba(255,255,255,.1)}
.cart__body{flex:1;overflow-y:auto;overscroll-behavior:contain}
.cart__lines{padding:6px 20px}
.cart__line{display:grid;gap:9px;padding:16px 0;border-bottom:1px solid var(--p-row)}
.cart__ln{font-size:.875rem;font-weight:700;line-height:1.35}
.cart__lmeta{font-size:.75rem;color:rgba(255,255,255,.5)}
.cart__lrow{display:flex;align-items:center;gap:12px}
.cart__lamt{margin-left:auto;font-size:.875rem;font-weight:700;font-variant-numeric:tabular-nums}
.cart__rm{
  font-size:.75rem;color:rgba(255,255,255,.5);
  border-bottom:1px solid transparent;transition:color var(--t1),border-color var(--t1)
}
.cart__rm:hover{color:var(--status-overdue);border-color:currentColor}

.cart__sum{padding:18px 20px;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.cart__sumrow{display:flex;align-items:baseline;justify-content:space-between;gap:14px}
.cart__sumk{font-size:.8125rem;color:rgba(255,255,255,.6)}
.cart__sumv{font-size:1.25rem;font-weight:700;font-variant-numeric:tabular-nums}
.cart__note{margin-top:10px;font-size:.75rem;line-height:1.6;color:rgba(255,255,255,.45)}

.cart__form{padding:18px 20px;display:grid;gap:14px}
.cfield{display:grid;gap:6px}
.cfield label{font-size:.625rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:rgba(255,255,255,.5)}
.cfield select,.cfield input,.cfield textarea{
  min-height:44px;padding:10px 12px;border-radius:var(--r);
  background:rgba(255,255,255,.04);border:1px solid var(--edge);color:#fff;font-size:.875rem;
  transition:border-color var(--t1)
}
.cfield textarea{min-height:74px;resize:vertical;line-height:1.5}
.cfield select:hover,.cfield input:hover,.cfield textarea:hover{border-color:var(--edge-hover)}
.cfield select:focus-visible,.cfield input:focus-visible,.cfield textarea:focus-visible{border-color:rgba(255,255,255,.45)}
.cfield select:disabled{opacity:.6}
.cfield [aria-invalid="true"]{border-color:var(--status-overdue)}
.cfield__hint{display:flex;justify-content:space-between;gap:10px;font-size:.6875rem;color:rgba(255,255,255,.4)}
.cart__foot{padding:18px 20px;border-top:1px solid var(--line);display:grid;gap:12px;flex:none}
.cart__sla{font-size:.75rem;color:rgba(255,255,255,.5)}

/* ---------- 10. history + timeline ---------- */
.hsec{margin-bottom:clamp(32px,4.5vw,60px)}
.hsec:last-child{margin-bottom:0}

.req{
  display:grid;grid-template-columns:minmax(0,1fr) auto auto;
  align-items:center;gap:clamp(12px,1.6vw,22px);
  padding:17px clamp(14px,1.8vw,20px);
  background:var(--surf);
  border:1px solid var(--edge);border-radius:var(--r-card);
  text-align:left;width:100%;
  transition:background-color var(--t1),border-color var(--t1)
}
.req:hover{background:var(--surf-hover);border-color:var(--edge-hover)}
.req__main{display:block;min-width:0}
.req__id,.req__meta,.req__sub{display:block}
.req .ico{color:rgba(255,255,255,.4)}
.req:hover .ico{color:#fff}
.req__id{font-size:.9375rem;font-weight:700;font-variant-numeric:tabular-nums}
.req__meta{margin-top:5px;font-size:.8125rem;color:rgba(255,255,255,.6)}
.req__sub{margin-top:3px;font-size:.75rem;color:rgba(255,255,255,.42)}
.reqlist,.invlist--paid{display:grid;gap:8px}

/* status timeline in the request modal. The rail is a background gradient on
   the list, so a step never floats free of the line. */
.timeline{display:grid;gap:0;margin-top:6px}
.tstep{
  position:relative;display:grid;grid-template-columns:26px minmax(0,1fr);
  gap:12px;padding-bottom:18px
}
.tstep:last-child{padding-bottom:0}
.tstep::before{
  content:"";position:absolute;left:12px;top:18px;bottom:0;width:1px;
  background:var(--line)
}
.tstep:last-child::before{display:none}
.tstep__dot{
  width:11px;height:11px;margin:5px auto 0;border-radius:50%;
  background:#2a2d33;box-shadow:inset 0 0 0 1px rgba(255,255,255,.2)
}
.tstep--done .tstep__dot{background:var(--status-paid);box-shadow:none}
.tstep--now .tstep__dot{background:#fff;box-shadow:0 0 0 4px rgba(255,255,255,.14)}
.tstep--todo{opacity:.42}
.tstep__k{font-size:.875rem;font-weight:700}
.tstep__t{margin-top:2px;font-size:.75rem;color:rgba(255,255,255,.45)}

/* the dev step control, tucked behind the reset row */
.devrow{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:14px}
.devrow__k{font-size:.625rem;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.3)}

.pfoot{
  max-width:var(--wrap);margin-inline:auto;
  padding:0 var(--pad) clamp(48px,7vw,96px);
  display:grid;gap:14px;justify-items:start
}

/* ---------- 11. print ----------
   A receipt is the one thing on this page anyone prints. Everything that is
   not the modal box comes off the page, and the box loses its own chrome so
   it prints as a document rather than as a screenshot of a dialog. */
@media print{
  /* .phead is a grandchild of .ppage (main.ppage > #app > header.phead), so
     a child selector here silently matched nothing and printed the header. */
  .nav,.ftr,.rtabs,.phead,.rstats,.pfoot,.toasts,.cart,.scrim,.drawer,
  .pmodal__scrim,.cfm,.invsel,.pm__x,.pm__foot .btn,.pm__foot .btnq,.skip{
    display:none!important
  }
  html,body{background:#fff!important;color:#000!important}
  .rpanel{display:none!important}
  .pmodal{position:static;display:block;padding:0}
  .pmodal[hidden]{display:none!important}
  .pmodal__box{
    width:100%;max-height:none;overflow:visible;opacity:1;transform:none;
    background:#fff!important;border:0;border-radius:0;color:#000
  }
  .pm__head,.pm__facts,.pm__foot{border-color:#ccc}
  .pm__k,.pm__fk,.pm__lspec,.pm__sum,.pm__lines th{color:#444!important}
  .pm__lines td{border-color:#ddd}
  .pm__id,.pm__fv,.pm__ln,.pm__sum--total{color:#000!important}
  .st{box-shadow:inset 0 0 0 1px #999;background:transparent!important;color:#000!important}
  .pm__foot{background:transparent}
}

/* ---------- 12. reduced motion ---------- */
.no-motion .cart,.no-motion .toast,.no-motion .pmodal__box,.no-motion .cfm__box,
.no-motion .pmodal__scrim,.no-motion .cfm__scrim{transition:none}
.no-motion .cart{transform:none}
.no-motion .cart[hidden]{display:none!important}
.no-motion .spin{animation:none}
@media (prefers-reduced-motion:reduce){
  .cart,.toast,.pmodal__box,.cfm__box,.pmodal__scrim,.cfm__scrim{transition:none}
  .cart{transform:none}
  .spin{animation:none}
}

/* ---------- 13. responsive ----------
   The site's existing breakpoints only: 1300, 1100, 900/820, 520. */
@media (min-width:1300px){
  .pgrid{grid-template-columns:repeat(4,minmax(0,1fr))}
  .pgrid--list{grid-template-columns:1fr}
}
@media (max-width:1100px){
  .signin{grid-template-columns:1fr}
  /* the balance figure keeps its scale; the car gives up width first */
  .phead{grid-template-columns:minmax(0,1fr) minmax(0,38%)}
  .pgrid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .pgrid--list{grid-template-columns:1fr}
}
@media (max-width:820px){
  /* each filter group gets its own line once they start competing for width */
  .ppage .filters{flex-direction:column;gap:12px}
  .ppage .filters .rcount{margin-left:0}
  /* An invoice becomes a card: the money block and the actions drop under
     the identity rather than being squeezed into their own tracks. The race
     number stays beside the invoice number — it is the fastest way to tell
     two rows apart at a glance.

     The row carries its own left padding here. On the wide layout the inset
     comes from a margin on the checkbox, because the status bar has to sit
     flush at x=0 — but then anything spanning back to column 1 starts
     outside the padding, which clipped the amount and sheared the T off
     "Total inc. VAT". Padding on the row, no margin on the checkbox, and
     every child lines up on one edge. */
  .inv{
    grid-template-columns:auto auto minmax(0,1fr);
    row-gap:16px;align-items:start;
    padding:16px clamp(14px,1.8vw,20px)
  }
  .inv__pick{margin-left:0;padding-top:3px}
  .inv__tag{padding-top:0;min-width:50px;padding-right:11px}
  .inv__tagv{font-size:1.375rem}
  .inv__money{grid-column:1 / -1;text-align:left}
  .inv__amt{font-size:1.75rem}
  .inv__amtk{margin-top:5px}
  .inv__act{grid-column:1 / -1;justify-content:flex-start;gap:10px}
  .inv__act .btnq,.inv__act .btn{flex:1;min-width:0}
  .req{grid-template-columns:minmax(0,1fr) auto;row-gap:10px}
  .cart{width:100vw}
  .pctl__count{margin-left:0;width:100%}
  .pm__sums{justify-content:stretch}
  .pm__sum{grid-template-columns:minmax(0,1fr) auto}
}
@media (max-width:520px){
  .pgrid{grid-template-columns:1fr}
  /* at phone width the tag and the checkbox together eat a third of the row,
     so the tag loses its rule and tightens up */
  .inv{gap:11px}
  .inv__tag{min-width:42px;padding-right:9px}
  .inv__tagv{font-size:1.25rem}
  .inv__tagk{font-size:.4375rem;letter-spacing:.16em}
  .inv__id{font-size:.9375rem;letter-spacing:.03em}
  .inv__ctx{letter-spacing:.1em}
  .inv__amt{font-size:1.625rem}
  .pgrid--list .pcard{flex-direction:column}
  .pgrid--list .pcard__art{width:100%;aspect-ratio:16/10}
  .pgrid--list .pcard__body{flex-direction:column;align-items:flex-start}
  .pgrid--list .pcard__foot{margin-left:0;width:100%}
  .pgrid--list .pcard__foot .btn--sm{flex:1}
  /* one column: the car drops under the balance at a reduced size, and the
     ghost number goes — at this width it crowds the figure instead of
     filling space behind it */
  .phead{grid-template-columns:1fr;gap:clamp(18px,4vw,28px)}
  .phead__ghost{display:none}
  .phead__car{width:min(74%,340px);justify-self:start}
  .phead__out{position:static;justify-self:start;margin-top:18px}
  .pm__facts{grid-template-columns:1fr}
  .invsel{flex-direction:column;align-items:stretch}
  .invsel__act{margin-left:0}
  .invsel__act .btn{width:100%}
  .toasts{width:calc(100vw - 2 * var(--pad))}
}
