/* ============================================================================
   Shared look and feel for the internal apps (portal, tickets, and whatever
   comes next). Load AFTER colors.css; it consumes those tokens and declares no
   colour values of its own.

       <link rel="stylesheet" href="<?= $base ?>branding/colors.css">
       <link rel="stylesheet" href="<?= $base ?>branding/branding.css">
       <link rel="stylesheet" href="<?= $base ?>assets/app.css">   <!-- app on top -->

   The house style in one line: white canvas, black text, gold for the things you
   click and the lines that divide, blue for information, light grey to lift a table
   off the page. Less is more — if a rule here needs a second colour to work, the
   rule is wrong.
   ============================================================================ */

/* ---- base ---------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--brand-bg);
  color: var(--brand-ink);
  font-family: var(--brand-font);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--brand-font-heading);
  color: var(--brand-ink);
  font-weight: 600;
  line-height: 1.2;
  margin: 0 0 .5em;
  text-wrap: balance;          /* headings break sensibly when they must break at all */
}
h1 { font-size: 1.65rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.08rem; }

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

a {
  color: var(--brand-support-text);          /* brand blue itself is too light to read */
  text-underline-offset: 2px;
}
a:hover { color: var(--brand-support-deep); }

small, .g-meta { color: var(--brand-ink-subtle); font-size: .82rem; }

/* The wide-tracked capitals from the logo's subtitle. The one typographic flourish
   the brand has; use it for section kickers, never for a whole sentence. */
.g-kicker {
  font-family: var(--brand-font-heading);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: var(--brand-tracking-kicker);
  text-transform: uppercase;
  color: var(--brand-accent-text);          /* NOT --brand-accent: that fails as text */
  white-space: nowrap;                   /* a kicker never wraps */
}

/* ---- rules ---------------------------------------------------------------------
   Gold marks a section; grey merely separates rows. Using gold for both makes it
   decoration and it stops meaning anything. */
.g-rule       { border: 0; border-top: 1px solid var(--brand-rule); margin: 1.5rem 0; }
.g-rule-gold  { border: 0; border-top: 2px solid var(--brand-rule-accent); margin: 1.5rem 0; }
.g-rule-short { width: 56px; border: 0; border-top: 2px solid var(--brand-rule-accent); margin: .75rem 0; }

/* ---- buttons -------------------------------------------------------------------
   One primary per screen. The primary used to be gold; it is now the blue gradient pill (see
   .g-btn-primary below), so its label colour comes from --brand-on-cta.

   The rule the gold era left behind still stands for any FULL-gold surface someone adds later:
   black on --brand-accent is 8.39:1, white on it is 2.50:1 and unreadable, so such a surface takes
   --brand-on-accent. Nothing in this app currently paints one — .g-badge-gold uses the soft tint
   with --brand-accent-text — which is why that token has no var() reader today. */
.g-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5em;
  min-height: 42px;
  padding: 0 1.15rem;
  border: 1px solid transparent;
  border-radius: var(--brand-radius-sm);
  background: var(--brand-white);
  color: var(--brand-ink);
  font-family: var(--brand-font-heading);
  font-size: .92rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;                   /* a button label never wraps */
  cursor: pointer;
  text-decoration: none;
  transition: background var(--brand-t-fast) var(--brand-ease-out),
              border-color var(--brand-t-fast) var(--brand-ease-out),
              color var(--brand-t-fast) var(--brand-ease-out);
}

/* The primary action is the blue gradient pill from the public site — one per screen. Gold is
   still the brand's line and accent colour; blue is the thing you click. */
.g-btn-primary {
  /* background-color APART, en background-image voor het verloop — niet de `background`-shorthand.
     Die shorthand zet background-color terug op `transparent`, en dan is er onder dit witte label
     geen meetbare kleur meer: verft het verloop niet (een oude renderer, een print, een extensie
     die achtergrondafbeeldingen uitzet), dan staat er wit op wit. Gemeten op 08-09-2026 door
     tests/contrast: 1,00:1. Visueel verandert er niets — het verloop dekt deze kleur volledig. */
  background-color: var(--brand-cta-to);
  background-image: linear-gradient(135deg, var(--brand-cta-from) 0%, var(--brand-cta-to) 100%);
  color: var(--brand-on-cta);
  border-color: transparent;
  border-radius: 999px;
  box-shadow: 0 6px 18px var(--brand-cta-shadow);
}
.g-btn-primary:hover {
  /* Restated, not inherited: any later `.g-btn:hover` rule would otherwise repaint this button
     and leave a white label on a light fill. Zelfde splitsing als hierboven, en om dezelfde reden. */
  background-color: var(--brand-cta-hover-to);
  background-image: linear-gradient(135deg, var(--brand-cta-hover-from) 0%, var(--brand-cta-hover-to) 100%);
  transform: translateY(-2px);
  box-shadow: 0 10px 26px var(--brand-cta-shadow);
}
.g-btn-primary:active { transform: none; }

.g-btn-secondary {
  background: var(--brand-white);
  color: var(--brand-ink);
  border-color: var(--brand-grey-300);
}
.g-btn-secondary:hover { border-color: var(--brand-ink); }

.g-btn-ghost { background: transparent; color: var(--brand-ink); border-color: transparent; }
.g-btn-ghost:hover { background: var(--brand-grey-100); }

.g-btn-danger { background: var(--brand-danger); color: var(--brand-white); border-color: var(--brand-danger); }

.g-btn[disabled], .g-btn:disabled { opacity: .45; cursor: not-allowed; }

/* DE gedeelde toetsenbordring. Eén kleur, één dikte, overal — zo ziet focus er hetzelfde uit waar
   hij ook landt. --brand-support-TEXT (5,38:1), niet de vulblauw --brand-support (2,52:1): een
   focusring is een niet-tekstindicator en moet 3:1 halen.
   .g-field staat hier NIET bij; die krijgt zijn eigen regel ná .g-field:focus — zie daar. */
.g-btn:focus-visible,
a:focus-visible {
  outline: 2px solid var(--brand-support-text);
  outline-offset: 2px;
}

/* ---- fields --------------------------------------------------------------------- */
.g-label {
  display: block;
  margin-bottom: .3rem;
  font-size: .82rem;
  font-weight: 600;
  color: var(--brand-ink);
}
.g-field {
  width: 100%;
  min-height: 42px;
  padding: .5rem .7rem;
  border: 1px solid var(--brand-grey-300);
  border-radius: var(--brand-radius-sm);
  background: var(--brand-white);
  color: var(--brand-ink);
  font-family: var(--brand-font);
  font-size: .95rem;
}
/* DE GOUDEN GLOED IS DECORATIE, GEEN FOCUSINDICATOR — LEES DIT VOOR JE HEM KOPIEERT.
 *
 * `outline: none` hieronder staat op (0,2,0) en won daarmee van de gedeelde ring hierboven, die op
 * exact dezelfde (0,2,0) staat maar EERDER in dit bestand — en :focus-visible is altijd óók :focus,
 * dus bij toetsenbordfocus matchten ze allebei en gaf de laatste de doorslag. De ring was er dus wel
 * en werd stilletjes weggezet. Wat overbleef als enige teken "hier sta je" was de gloed zelf:
 * --brand-accent-soft is #F8F3E2 en dat is 1,11:1 op wit. Gemeten op select#typeFilter van het
 * ticketbord: banden 0-2 #F8F3E2, band 3 en verder #FFFFFF. Een niet-tekstindicator moet 3:1 halen;
 * ook de gouden rand eromheen komt niet verder dan 2,50:1. Voor wie met het toetsenbord werkt was er
 * feitelijk geen focus te zien — in 257 van de 578 invulvelden van deze app.
 *
 * De oplossing is dezelfde als een laag hoger in site/site.css (zie de notitie bij .form-card): de
 * gloed BLIJFT als muisdecoratie op :focus, en de ring komt terug op :focus-visible — maar nu ná de
 * :focus-regel, zodat de volgorde in ons voordeel werkt in plaats van tegen ons. :focus-visible en
 * niet :focus, zodat een muisklik geen toetsenbordring tekent.
 *
 * De ring is dezelfde als overal elders (--brand-support-text, 5,38:1 op wit en 4,90:1 op de gouden
 * gloed waar hij bij offset 2px deels overheen valt) — beide ruim boven de 3:1.
 *
 * Schrijf je ergens een eigen :focus met `outline: none`, zet er dan ALTIJD een :focus-visible
 * ONDER met deze ring. Anders haal je de indicator weg zonder er een terug te geven. */
.g-field:focus { border-color: var(--brand-accent); outline: none; box-shadow: 0 0 0 3px var(--brand-accent-soft); }
.g-field:focus-visible { outline: 2px solid var(--brand-support-text); outline-offset: 2px; }

/* De eigen chevron. `appearance:none` haalt het pijltje van het besturingssysteem weg zodat er niet
   twee staan. Een data-URI kan geen CSS-variabele lezen, dus de streekkleur is de URL-gecodeerde
   (%23...) vorm van --brand-ink-subtle; houd die twee gelijk als dat token ooit verschuift.
 *
 * DEZE SELECTOR IS MET OPZET ZWAARDER DAN DE REST VAN DIT BESTAND (0,3,1).
 *
 * De basisregel hierboven staat bewust laag zodat modules hun eigen doos mogen tekenen. Maar het
 * PIJLTJE is geen smaakkwestie: zonder pijl is een keuzelijst niet van een tekstveld te
 * onderscheiden, en je ziet dat pas als iemand het meldt. Gemeten stond het er in 149 van de 203
 * keuzelijsten in deze app niet — in vier modules die er los van elkaar overheen schreven, elke keer
 * op dezelfde twee manieren:
 *
 *   background: var(--x)    de SHORTHAND zet background-image impliciet op none
 *   padding: 9px 11px       de SHORTHAND gooit de gereserveerde padding-right weg
 *
 * Beide zijn onschuldig ogende regels die je niet als "ik sloop het pijltje" leest. Met (0,3,1) wint
 * deze regel van elke gewone klasseregel (0,1,1) en blijft de pijl staan, terwijl een module die het
 * écht anders wil dat nog steeds bewust kan doen met een zwaardere selector.
 *
 * `[multiple]` en `[size]` zijn uitgezonderd: dat zijn keuzeLIJSTEN, geen uitklapmenu's, en die
 * hebben geen pijl. Flatpickr's maanddropdown ook: dat is een vendor-widget met een eigen native
 * pijl in een krappe kalenderkop, en 32px padding erin duwen breekt zijn layout. */
select:not([multiple]):not([size]):not(.flatpickr-monthDropdown-months) {
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236B6B6B' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  /* background-size hoort er expliciet bij. Deze regel wint background-IMAGE van een moduleregel,
     maar niet automatisch diens background-SIZE — en die blijft dan staan. tickets.css tekende zijn
     eigen pijl als twee linear-gradient-driehoekjes van 5px; zonder deze regel werd onze 16px-svg in
     dat 5px-vakje geperst en bleef er op alle 48 keuzelijsten van het ticketbord een haarlijntje
     over (1,77:1, ónder de 3:1 die deze pijl juist moet halen). Een half overschreven achtergrond is
     erger dan geen: de module denkt dat hij het pijltje bepaalt, wij denken dat ook, en samen maken
     we hem onzichtbaar. */
  background-size: 16px 16px;
  padding-right: 32px;
}

.g-field[aria-invalid="true"] { border-color: var(--brand-danger); }
/* Dark UAs restyle native controls; state both sides so a select never renders
   grey-on-grey (a recurring bug in this repo). */
select.g-field, select.g-field option { background: var(--brand-white); color: var(--brand-ink); }

/* Headings: brand heading face, tight and confident. Colour comes from the token, not the rule. */
h1, h2, h3 {
  font-family: var(--brand-font-heading);
  color: var(--brand-ink);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.15;
  margin: 0;
}
a { color: var(--brand-support-text); }   /* brand blue itself is too light to carry text */

.app-icon { width: 18px; height: 18px; stroke-width: 1.75; vertical-align: middle; }

/* ===== Formuliervelden — de BASIS, en met opzet op het element =====================
 *
 * Een veld ziet er zo uit omdat het een veld IS, niet omdat iemand de juiste wrapper eromheen heeft
 * gezet. Dat was hier het terugkerende probleem: de opmaak hing aan drie verschillende
 * ouderklassen -- `.form-row select`, `.detail-edit select` en `.pl-field select` -- die per module
 * verschillen. Alles wat buiten die drie viel kreeg het kale besturingssysteem-widget: grijs,
 * hoekig, met een eigen pijltje. Je zag het pas als het scherm af was, en de oplossing was elke keer
 * "vergeet de wrapper niet" -- een regel die je alleen kunt naleven door hem te onthouden.
 *
 * Deze regel staat BEWUST vooraan en met lage specificiteit (0,0,1). Elke bestaande klasse-regel
 * hieronder wint er dus gewoon van; dit verandert niets aan wat al goed stond en vangt alleen wat
 * anders door de mand viel.
 *
 * De typen staan expliciet opgesomd in plaats van `input:not([type=checkbox])`: een checkbox, radio,
 * range of file-veld mag deze rand en padding juist NIET krijgen, en een opsomming die per ongeluk
 * te veel pakt is precies hoe je dat stuk maakt.
 *
 * Geen `width` hier. Een veld in een `.pl-field`-grid hoort 100% te zijn, maar een los veld tussen
 * tekst hoort zijn eigen breedte te houden -- een globale 100% zou elke inline keuzelijst over de
 * hele regel uitrekken.
 */
input[type="text"], input[type="email"], input[type="tel"], input[type="url"],
input[type="number"], input[type="password"], input[type="search"],
input[type="date"], input[type="time"], input:not([type]),
select, textarea {
  font: inherit;
  font-size: 14px;
  color: var(--brand-ink);
  background-color: var(--brand-surface);
  border: 1px solid var(--brand-grey-300);
  border-radius: var(--brand-radius-sm);
  padding: 8px 10px;
  max-width: 100%;
  transition: border-color var(--brand-t-fast) var(--brand-ease-out),
              box-shadow var(--brand-t-base) var(--brand-ease-out);
}
textarea { resize: vertical; }

/* Hover on a field says "this one is yours to fill in" before you click it. Gold, because that is
   this app's colour for an interactive edge — the same answer a select, an icon-trigger and a
   message row already give. Hover only, so nothing here can outrank the focus ring. */
input[type="text"]:hover:not(:disabled), input[type="email"]:hover:not(:disabled),
input[type="tel"]:hover:not(:disabled), input[type="url"]:hover:not(:disabled),
input[type="number"]:hover:not(:disabled), input[type="password"]:hover:not(:disabled),
input[type="search"]:hover:not(:disabled), input[type="date"]:hover:not(:disabled),
input[type="time"]:hover:not(:disabled), input:not([type]):hover:not(:disabled),
textarea:hover:not(:disabled) {
  border-color: var(--brand-accent);
}

/* De chevron van een keuzelijst staat in branding/branding.css, niet hier.
 *
 * Reden: `assets/app.css` wordt niet door élk scherm geladen — processdocumenter/ laadt alleen
 * colors.css + branding.css + zijn eigen stylesheet, en had daardoor 14 keuzelijsten zonder pijl.
 * branding.css is wél de gedeelde laag (33 schermen), dus daar hoort de regel die overal moet gelden.
 * Eén definitie, geen kopie die stilletjes uit de pas gaat lopen. */

/* Huisregel: noem de kleuren van een option altijd expliciet. Een donkere UA rendert de lijst
   anders grijs-op-grijs en dat merk je niet op een licht scherm. */
select option { background: var(--brand-white); color: var(--brand-ink); }
input[type="text"]:focus-visible, input[type="email"]:focus-visible, input[type="tel"]:focus-visible,
input[type="url"]:focus-visible, input[type="number"]:focus-visible, input[type="password"]:focus-visible,
input[type="search"]:focus-visible, input[type="date"]:focus-visible, input[type="time"]:focus-visible,
input:not([type]):focus-visible, select:focus-visible, textarea:focus-visible {
  /* --brand-support-TEXT, not --brand-support: the fill blue is 2.52:1 on white and a focus ring is
     a non-text indicator that needs 3:1 — this one is 5.38:1, and it is the same ring the buttons,
     cards and rows already draw, so keyboard focus looks identical wherever it lands. The BORDER
     stays the softer blue: it sits inside the ring and only has to read as "this field is live". */
  outline: 2px solid var(--brand-support-text);
  outline-offset: 1px;
  border-color: var(--brand-support);
}

/* ── ÉÉN BEDIENING, ÉÉN AANDUIDING (09-09-2026) ──────────────────────────────────────────────
 *
 * De regel hierboven is goed voor een LOS veld. Maar sommige velden zitten in een omhulsel dat zélf
 * al oplicht: een zoekvak met een vergrootglas ernaast, een kaartje met een vinkje erin. Dan staan
 * er twee rechthoeken om elkaar heen — en dat leest niet als "twee ringen" maar als één heel dikke
 * rand. Gemeld door de klant op de {clienten}lijst; daarna teruggevonden op nog drie plekken, twee
 * ervan met de ringen in verschillende kleuren (goud buiten, blauw binnen).
 *
 * HET OMHULSEL WINT, want dat is wat de gebruiker als "het veld" ziet: het draagt het icoon, het
 * label en de invoer. Het besturingselement erbinnen zwijgt.
 *
 * DIT MAG NOOIT EEN KALE `outline: none` WORDEN OP ALLES. Elk omhulsel in deze lijst tekent zijn
 * eigen `:focus-within`-aanduiding; staat die er niet, dan hoort het veld hier ook niet tussen —
 * anders is er straks helemaal geen zichtbare focus meer en is het scherm onbruikbaar met een
 * toetsenbord. Voeg dus een klasse toe én controleer dat hij oplicht. */
.deb-search input:focus,        .deb-search input:focus-visible,
.st-search  input:focus,        .st-search  input:focus-visible,
.ts-search  input:focus,        .ts-search  input:focus-visible,
.deb-toggle-card input:focus,   .deb-toggle-card input:focus-visible {
  outline: none;
  border-color: transparent;
}
input:disabled, select:disabled, textarea:disabled {
  background-color: var(--brand-grey-100);
  color: var(--brand-ink-subtle);
  cursor: not-allowed;
}

/* ===== Buttons ===== */
/* Primary actions use the shared blue gradient; secondary actions use the neutral surface. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
  border: 1px solid var(--brand-grey-300);
  /* Pill, matching the button language of the public site that this house style now follows. */
  border-radius: 999px;
  background: var(--brand-surface);
  color: var(--brand-ink);
  font: inherit;
  font-weight: 600;
  /* The header nav is built from .btn on <a> elements; without this the browser underlines every
     one of them and the chrome turns noisy. */
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--brand-t-fast) var(--brand-ease-out),
              border-color var(--brand-t-fast) var(--brand-ease-out),
              box-shadow var(--brand-t-fast) var(--brand-ease-out),
              transform var(--brand-t-fast) var(--brand-ease-out);
}
/* HOVER IS PHYSICAL (motion.css contract): the control rises and its shadow blooms; the colour
   change alone read as a picture of a button rather than a button. Transform + box-shadow only,
   so a toolbar of twelve of these still hovers at full frame rate. */
.btn:hover { border-color: var(--brand-ink); background: var(--brand-grey-100); transform: translateY(-1px); box-shadow: var(--brand-shadow-sm); }
/* Press feedback: a real counter-movement, the same gesture as .m-press. Faster than the lift —
   a control that yields under the finger and snaps back reads as a physical object. */
.btn:active:not(:disabled) { transform: translateY(1px) scale(.985); box-shadow: none; transition-duration: .08s; }
/* The primary action: the blue gradient pill from the public site, adopted as the standard CTA.
   Gold stays the brand's line/accent colour; blue is what you click. One primary per screen.
   Colours come from --brand-cta-* — see the note there on why the light end is deeper than the
   site's (white on the site's #77AAC3 is 2.50:1). */
.btn-primary {
  /* background-color apart van background-image, precies zoals bij .g-btn-primary: de
     `background`-shorthand zet de kleur op `transparent`, en dan ligt er onder dit witte label
     niets meer als het verloop niet verft. Het verloop dekt deze kleur volledig, dus je ziet geen
     verschil — tot de dag dat het uitmaakt. */
  background-color: var(--brand-cta-to);
  background-image: linear-gradient(135deg, var(--brand-cta-from) 0%, var(--brand-cta-to) 100%);
  border-color: transparent;
  color: var(--brand-on-cta);
  box-shadow: 0 6px 18px var(--brand-cta-shadow);
}
/* The background MUST be restated here. `.btn:hover` is (0,2,0) and `.btn-primary` is only
   (0,1,0), so without this the generic hover repaints the primary button light grey while it keeps
   its white label — the words vanish (1.05:1). Deepening the gradient is the hover feedback. */
.btn-primary:hover {
  background-color: var(--brand-cta-hover-to);
  background-image: linear-gradient(135deg, var(--brand-cta-hover-from) 0%, var(--brand-cta-hover-to) 100%);
  border-color: transparent;
  color: var(--brand-on-cta);
  transform: translateY(-2px);
  box-shadow: 0 10px 26px var(--brand-cta-shadow);
}
.btn-ghost { background: transparent; border-color: transparent; }
.btn-ghost:hover { background: var(--brand-grey-100); border-color: transparent; }
/* In the header, ghost links take the gold tint — the huisstijl accent in the chrome. The label
   must be gold-TEXT there: --brand-accent-deep on --brand-accent-soft is only 3.09:1. */
.app-header .btn-ghost:hover { background: var(--brand-accent-soft); color: var(--brand-accent-text); }
.btn-danger { border-color: var(--brand-danger); color: var(--brand-danger); }
.btn-danger:hover { background: var(--brand-danger-soft); border-color: var(--brand-danger); }
.btn-block { width: 100%; justify-content: center; }
.btn-sm { padding: 6px 12px; font-size: 13px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn:focus-visible { outline: 2px solid var(--brand-support-text); outline-offset: 2px; }

/* ---- Grol components: canonical contract in branding/STANDARD.md ------------------
   Existing app class names are aliases, so all internal pages inherit the same foundation.
   Page styles own layout. Component appearance and interaction belong here. */
.g-card, .panel, .proc-card, .ov-card, .card-edit, .shoe-card, .card,
.login-card, .cat-service, .prod-card, .order-card,
.pd-master-card, .pd-process-card, .ovl-card, .dos-blok,
.pd-suggest-card, .pd-analyze-card, .doc-edit-section {
  background: var(--g-card-bg, var(--brand-surface));
  color: var(--brand-ink);
  border: 1px solid var(--g-card-border, var(--brand-rule));
  border-radius: var(--brand-radius);
  box-shadow: var(--g-card-shadow, var(--brand-shadow-sm));
  transition: border-color var(--brand-t-base) var(--brand-ease-out),
              background var(--brand-t-base) var(--brand-ease-out),
              box-shadow var(--brand-t-base) var(--brand-ease-out),
              transform var(--brand-t-base) var(--brand-ease-out);
}
.g-card, .shoe-card, .cat-service, .prod-card, .pd-master-card, .pd-process-card { padding: var(--brand-space-4); }
.card { padding: 10px var(--brand-space-3); }
.panel, .ov-card { padding: var(--brand-space-5); }
.login-card { padding: 32px 28px; --g-card-shadow: var(--brand-shadow-lg); }
.order-card { --g-card-shadow: var(--brand-shadow); }
.ovl-card { padding: 14px var(--brand-space-4); }
.pd-suggest-card { padding: 10px var(--brand-space-3); border-style: dashed; --g-card-bg: var(--brand-grey-100); }
.pd-analyze-card { padding: 9px 11px; }
.g-card--accent { border-left: 3px solid var(--g-card-accent, var(--brand-support-text)); }
.g-card-accent { border-top: 3px solid var(--brand-accent); }
.g-card--empty { padding-block: var(--brand-space-3); }
:is(.g-card--interactive, .proc-card, .ov-card, .shoe-card, .card, .cat-service, .pd-process-card, .pd-analyze-card):not(.is-disabled):not([aria-disabled="true"]):hover {
  box-shadow: var(--g-card-hover-shadow, var(--brand-shadow));
  transform: translateY(-2px);
}
:is(.g-card--interactive, .proc-card, .ov-card, .shoe-card, .card, .cat-service, .pd-process-card, .pd-analyze-card):not(.is-disabled):active { transform: translateY(0); }
:is(.g-card--passive, .prod-card, .ovl-card):hover { box-shadow: var(--g-card-hover-shadow, var(--brand-shadow)); }
:is(.g-card--interactive, .proc-card, .ov-card, .shoe-card, .card):focus-visible,
input:focus-visible + .g-card, input:focus-visible + .g-choice {
  outline: 3px solid var(--brand-support-text); outline-offset: 3px;
}
input:checked + .g-card {
  border-color: var(--g-card-accent, var(--brand-support-text));
  background: color-mix(in srgb, var(--g-card-accent, var(--brand-support-text)) 6%, var(--brand-white));
  box-shadow: inset 0 0 0 1px var(--g-card-accent, var(--brand-support-text));
}
.g-card-icon, .g-card .g-card-icon {
  display: grid; place-items: center; flex-shrink: 0;
  width: var(--brand-card-icon); height: var(--brand-card-icon);
  border-radius: var(--brand-radius);
  color: var(--g-card-accent, var(--brand-support-text));
  background: color-mix(in srgb, var(--g-card-accent, var(--brand-support-text)) 10%, var(--brand-white));
}
.g-card-icon svg, .g-card .g-card-icon svg { width: 24px; height: 24px; stroke-width: 1.6; }
.g-card-title, .g-card .g-card-title { margin: 0; font-size: var(--brand-card-title); font-weight: 600; line-height: 1.4; text-wrap: pretty; }

/* Dense records still share one material language, but use smaller corners and no built-in inset:
   their children own the grid/expanded form layout. */
.g-row, .ts-row, .ts-ticket-card, .deb-row, .msg-row, .req-item, .mi-msg,
.arch-open-item, .st-row, .worker-row, .pl-list-item, .ts-list-row,
.pd-detail-item, .pd-admin-row, .pd-imp-item {
  background: var(--g-card-bg, var(--brand-surface));
  color: var(--brand-ink);
  border: 1px solid var(--g-card-border, var(--brand-rule));
  border-radius: var(--brand-radius-sm);
  box-shadow: var(--g-card-shadow, var(--brand-shadow-sm));
  transition: border-color var(--brand-t-base) var(--brand-ease-out),
              background var(--brand-t-base) var(--brand-ease-out),
              box-shadow var(--brand-t-base) var(--brand-ease-out),
              transform var(--brand-t-fast) var(--brand-ease-out);
}
.msg-row, .req-item, .mi-msg, .arch-open-item, .st-row, .worker-row, .pl-list-item,
.ts-list-row, .pd-detail-item, .pd-admin-row, .pd-imp-item { padding: var(--brand-space-3) 14px; }
:is(.g-row--interactive, .ts-row.is-collapsed, .ts-ticket-card.is-collapsed,
    .deb-row:not(.is-open), .msg-row, .req-item, .mi-msg, .arch-open-item, .pl-list-item):hover {
  border-color: var(--brand-grey-300);
  box-shadow: var(--g-card-hover-shadow, var(--brand-shadow));
  transform: translateY(-2px);
}
:is(.g-row--interactive, .ts-row.is-collapsed, .ts-ticket-card.is-collapsed,
    .deb-row:not(.is-open), .msg-row, .req-item, .mi-msg, .arch-open-item, .pl-list-item):active { transform: translateY(0); }
:is(.g-row--interactive, .msg-row, .req-item, .mi-msg, .arch-open-item, .pl-list-item):focus-visible {
  outline: 3px solid var(--brand-support-text); outline-offset: 2px;
}
:is(.g-row--passive, .ts-list-row):hover {
  border-color: var(--brand-grey-300); box-shadow: var(--brand-shadow);
}
.pd-imp-item { --g-card-bg: var(--brand-warning-soft); --g-card-border: var(--brand-warning); }

/* Flat navigation/menu records stay inside their parent panel instead of becoming nested cards. */
.g-list-item, .ov-attn-row, .hb-page-item, .pd-search-row {
  padding: var(--brand-space-2) 10px;
  border: 0;
  border-radius: var(--brand-radius-sm);
  background: transparent;
  color: var(--brand-ink);
  transition: background var(--brand-t-fast) var(--brand-ease-out),
              transform var(--brand-t-fast) var(--brand-ease-out);
}

/* A choice card wraps its native control. Selection and focus stay visible on the whole target. */
.g-choice-card, .deb-toggle-card, .clean-row, .choice-row .choice {
  padding: 13px 15px;
  border: 1px solid var(--brand-grey-300);
  border-radius: var(--brand-radius-sm);
  background: var(--brand-surface);
  color: var(--brand-ink);
  box-shadow: var(--brand-shadow-sm);
  transition: background var(--brand-t-fast) var(--brand-ease-out),
              border-color var(--brand-t-fast) var(--brand-ease-out),
              box-shadow var(--brand-t-fast) var(--brand-ease-out);
}
:is(.g-choice-card, .deb-toggle-card, .clean-row, .choice-row .choice):hover { border-color: var(--brand-support-text); }
:is(.g-choice-card, .deb-toggle-card, .clean-row):has(input:checked) {
  border-color: var(--brand-support-text); background: var(--brand-support-soft);
  box-shadow: inset 0 0 0 1px var(--brand-support-text);
}
:is(.g-choice-card, .deb-toggle-card, .clean-row, .choice-row .choice):focus-within {
  outline: 3px solid var(--brand-support-text); outline-offset: 2px;
}

/* KPI tiles are passive instruments: common material, tabular content supplied by each screen. */
.g-kpi, .kpi, .ov-kpi, .ts-summary-card {
  background: var(--g-card-bg, var(--brand-surface));
  color: var(--brand-ink);
  border: 1px solid var(--g-card-border, var(--brand-rule));
  border-radius: var(--brand-radius);
  box-shadow: var(--g-card-shadow, var(--brand-shadow-sm));
  transition: border-color var(--brand-t-base) var(--brand-ease-out),
              background var(--brand-t-base) var(--brand-ease-out),
              box-shadow var(--brand-t-base) var(--brand-ease-out);
}
.g-kpi, .kpi, .ts-summary-card { padding: var(--brand-space-4) 18px; }
.ov-kpi { padding: 10px var(--brand-space-1); }
:is(.g-kpi, .kpi, .ov-kpi, .ts-summary-card):hover {
  border-color: var(--brand-grey-300); box-shadow: var(--brand-shadow);
}
.g-section {
  padding: var(--brand-space-5); border: 1px solid var(--brand-rule);
  border-radius: var(--brand-radius); background: var(--brand-surface-sunken);
  color: var(--brand-ink); box-shadow: none;
}
.g-section-head { display: flex; align-items: center; justify-content: space-between; gap: var(--brand-space-3); margin-bottom: var(--brand-space-4); }
.g-section-title, .panel .g-section-title { display: flex; align-items: center; gap: var(--brand-space-3); margin: 0; font-size: 18px; }
.g-banner {
  padding: var(--brand-space-5) var(--brand-space-6); border-radius: var(--brand-radius);
  border-left: 3px solid var(--brand-accent);
  background: linear-gradient(110deg, var(--brand-support-deep), var(--brand-cta-hover-to)); color: var(--brand-white);
}
.g-banner h1, .g-banner h2 { color: inherit; }
.btn.g-button-inverse { background: transparent; color: var(--brand-white); border: 1px solid var(--brand-support); }
.btn.g-button-inverse:hover { background: var(--brand-support-deep); border-color: var(--brand-white); }
.g-choice {
  min-height: 42px; padding: var(--brand-space-2) var(--brand-space-3);
  border: 1px solid var(--brand-grey-300); border-radius: var(--brand-radius-sm);
  background: var(--brand-surface); color: var(--brand-ink); font-size: 13px; font-weight: 600;
  transition: background var(--brand-t-fast), border-color var(--brand-t-fast);
}
.g-choice:hover { border-color: var(--brand-support-text); }
input:checked + .g-choice { background: var(--brand-support-soft); border-color: var(--brand-support-text); box-shadow: inset 0 0 0 1px var(--brand-support-text); }
input:disabled + .g-choice { background: var(--brand-grey-100); color: var(--brand-ink-muted); border-color: var(--brand-grey-300); cursor: not-allowed; }
@media (max-width: 640px) {
  .g-section, .panel, .ov-card { padding: var(--brand-space-4); }
  .g-card, .cat-service, .prod-card, .pd-master-card, .pd-process-card { padding: var(--brand-space-3); }
  .g-section-head { align-items: flex-start; flex-direction: column; gap: var(--brand-space-2); }
  .g-section-title, .panel .g-section-title { font-size: 16px; }
  .kpi { padding: var(--brand-space-3) 14px; }
}

/* ---- tables ---------------------------------------------------------------------
   Light grey is the table's own colour: grey header, white body, grey zebra. The only
   gold on a table is the rule under the header. */
.g-table { width: 100%; border-collapse: collapse; font-size: .92rem; }
.g-table th {
  padding: .6rem .75rem;
  background: var(--brand-grey-100);
  border-bottom: 2px solid var(--brand-rule-accent);
  color: var(--brand-ink);
  font-family: var(--brand-font-heading);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  text-align: left;
  white-space: nowrap;
}
.g-table td { padding: .6rem .75rem; border-bottom: 1px solid var(--brand-rule); vertical-align: top; }
.g-table tbody tr:nth-child(even) td { background: var(--brand-surface-alt); }
.g-table tbody tr:hover td { background: var(--brand-accent-soft); }
.g-table tbody tr:last-child td { border-bottom: 0; }

/* ---- badges ---------------------------------------------------------------------
   Solid light fills with dark text. Never a translucent tint: rgba(brand, .16) over
   white is a pastel that light text cannot sit on, and the "gold" chip turns olive. */
.g-badge {
  display: inline-block;
  padding: .18rem .55rem;
  border-radius: 999px;
  font-size: .74rem;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
}
.g-badge-neutral { background: var(--brand-grey-100);    color: var(--brand-ink); }
.g-badge-gold    { background: var(--brand-accent-soft);   color: var(--brand-accent-text); }
.g-badge-blue    { background: var(--brand-support-soft);   color: var(--brand-support-text); }
.g-badge-success { background: var(--brand-success-soft); color: var(--brand-success); }
.g-badge-warning { background: var(--brand-warning-soft); color: var(--brand-warning); }
.g-badge-danger  { background: var(--brand-danger-soft);  color: var(--brand-danger); }

/* ---- logo -----------------------------------------------------------------------
   Brand sheet: the wordmark is at least 80px wide on screen, and keeps clear space all round of
   at least the height of the 'o' in the wordmark (~12% of the logo width).

   NEITHER IS ENFORCED BY THIS RULE, AND THAT IS DELIBERATE — the comment here used to claim both
   were "encoded so no template has to remember them", which was not true:

     * Every call site applies .g-logo-sm/-md/-lg ON ITS OWN, so the bare .g-logo rule never fires.
     * The clear space was declared and withdrawn in the same rule (`margin: 12%; margin: 0`),
       because a fixed margin fights the header, login card and worker layouts that each place the
       logo themselves. It lives on as the opt-in .g-logo-clear instead.
     * The 80px floor is deliberately undercut where the mark, not the wordmark, is used: the app
       header runs it at 64px (46px on a phone) via `.app-header img` in assets/app.css.

   So: sizes below are the house sizes, clear space is opt-in, and the 80px minimum is a rule for
   the WORDMARK that a call site has to honour by picking an appropriate size class. */
.g-logo { display: block; width: auto; height: auto; }
.g-logo-clear { padding: 12%; }
.g-logo-sm { width: 96px; }
.g-logo-md { width: 150px; }
.g-logo-lg { width: 240px; }

/* ---- utilities ------------------------------------------------------------------ */
.g-stack > * + * { margin-top: 1rem; }
.g-row { display: flex; align-items: center; gap: .75rem; }
.g-spacer { flex: 1 1 auto; }
.g-nowrap { white-space: nowrap; }

/* ─────────────────────────────────────────────────────────────────────────────────────────────
   TURNED OFF ON PURPOSE — `not all` never matches. Do not remove, and certainly do not "restore".

   This block used to be live, and it was the most expensive one in the app: branding.css loads on
   all 39 screens, so on the machine this app is demonstrated on — Windows reports
   `prefers-reduced-motion: reduce` at the OS level while the owner explicitly wants the motion —
   EVERY branded button in the product was already motionless before anyone animated anything. The
   press, the hover, the settle: all of it flattened, silently, and the only symptom is that a
   careful motion pass "makes no difference". That conclusion has now been reached three separate
   times in this repo; once the same mechanism pinned a toast to opacity:0 and every message in the
   app — errors and confirmations alike — lived 3.6 seconds invisibly and read as "the API is broken".

   The old comment argued that a SHARED layer must honour the setting for whoever else loads it.
   That argument does not survive contact with the facts: the only things that load this file are
   the internal apps, which have the opposite preference on record. `site/` — the public marketing
   site — may honour the setting for decorative motion. Nothing inside an app may.

   Same rule and same pattern as the block at the bottom of assets/app.css and the shared
   vocabulary in assets/motion.css. If motion here ever really does need tempering, do it per
   element and never with a media query that catches the whole file.
   ───────────────────────────────────────────────────────────────────────────────────────────── */
@media not all {
  .g-btn { transition: none; }
}

@media print {
  .g-card, .g-section, .panel, .proc-card, .ov-card, .card-edit, .shoe-card, .card,
  .login-card, .cat-service, .prod-card, .order-card, .pd-master-card, .pd-process-card,
  .ovl-card, .dos-blok, .pd-suggest-card, .pd-analyze-card, .doc-edit-section,
  .g-row, .ts-row, .ts-ticket-card, .deb-row, .msg-row, .req-item, .mi-msg,
  .arch-open-item, .st-row, .worker-row, .pl-list-item, .ts-list-row,
  .pd-detail-item, .pd-admin-row, .pd-imp-item,
  .g-list-item, .ov-attn-row, .hb-page-item, .pd-search-row,
  .g-kpi, .kpi, .ov-kpi, .ts-summary-card { box-shadow: none; }
}
