/* OLB FORMS v1.0.1 — REPAIR RC1
   OLB FORMULARSYSTEM — Phase 1
   Onlinebutikken.com · Bricks + WooCommerce

   v1.0.1 (alle auditbegrundede, ingen visuel redesign):
     BUG-01 hover kun på fine pointer · BUG-02 fejlkant vinder over hover
     BUG-07 field-row → næste felt = --field-gap · BUG-08 spinner stopper ikke
     BUG-09 WooCommerce presentation adapter (§16) · X-02 ikoner fra fælles sprite
     X-05 .olb-selectable__input er altid en synlig ≥3:1-kontrol
     G-01/G-02 ARIA-hooks (data-attributter og modifier beholdt som deprecated aliaser)
     G-04 selectable-geometri ejes af Form & Dybde · G-07 --radius-checkout-card
     G-08 --field-chevron bruges; død nowrap på pris fjernet

   Laeste masters:

   Farver     : OLB_FARVESYSTEM_MASTER_v1.0.5 + OLB_FARVESYSTEM_v1.0.5.css (autoritativ)
   Typografi  : OLB_TYPOGRAFISYSTEM_MASTER_v0.9.8
   Layout     : OLB_LAYOUT_SPACING_MASTER_v1.0_LOCKED
   Form/dybde : OLB_FORM_OG_DYBDE_MASTER_v1.0
   Ikoner     : OLB_ICONOGRAPHY_MASTER_v1.0.1 (sprite olb-icons-v0.4.svg)
   Knapper    : OLB_BUTTONS_MASTER_v1.0.2
   Alt i denne fil refererer til deres tokens. Ingen vaerdi gentages.

   Denne fil ejer kun det, der ikke findes i en master: feltets hoejde,
   checkbox- og radiogeometri, select-chevronen, soege- og ryd-ikonet,
   tekstomraadets hoejde, autofill-haandteringen og raekkedelingen.

   Tre ting er baerende og maa ikke aendres uden at maale:

   1. Ingen fokuserbar komponent saetter sin egen box-shadow.
      Formmasteren §9 er bindende, fordi fokusringen er en box-shadow.
      Det udelukker ogsaa den saedvanlige autofill-teknik, der bruger en
      inset box-shadow; autofill haandteres derfor med en
      background-transition i stedet.

   2. Error-borderen er 2 px mod standardens 1 px. Uden
      paddingkompensation ville feltets indhold flytte sig 2 px, og alt
      under det ville rykke ved hver fejl. Kompensationen er derfor ikke
      kosmetisk, men det der holder formularens geometri stille.

   3. Checkbox og radio bruger --radius-hairline = 4 px. Formmasteren
      forbyder 6, 9, 11, 12, 14, 18 og 20 px, saa 4 px er den eneste
      lovlige vaerdi ud over 0 og pill.
*/

:root {
  /* --- formularsystemets egne tokens --- */
  --field-height: 48px;
  --field-padding-x: var(--input-padding-x);
  --field-radius: var(--radius-input);
  --field-border: var(--border-control);
  --field-border-error: var(--border-error);
  --field-gap: var(--gap-form-row);
  --field-label-gap: var(--gap-tight);
  --field-help-gap: var(--gap-hairline);
  --field-check-size: 24px;
  --field-check-radius: var(--radius-hairline);
  --field-chevron: 10px;
  /* X-02: ikonstørrelser ejes af Iconography. --field-status-icon er deprecated
     (16 px findes ikke i Iconography) og peger på sm; fjernes i v1.1. */
  --field-status-icon: var(--icon-size-sm);
  --field-inline-icon: var(--icon-size-sm);
  --field-textarea-min-height: 96px;
  --field-textarea-padding-y: 11px;
  --field-measure: 44ch;
}

/*
   Hvad hvert token er, og hvorfor:

   --field-height                   48px
     Knappens standardhoejde og typografimasterens touch-floor. Et felt og en
     knap paa samme raekke flugter derfor praecist.

   --field-padding-x                var(--input-padding-x)
     12 px, laast i formmasteren og identisk med --gap-inline.

   --field-radius                   var(--radius-input)
     8 px via --radius-control. Laast.

   --field-border                   var(--border-control)
     1 px solid --color-border-strong. Funktionel kant, ikke dekorativ.

   --field-border-error             var(--border-error)
     2 px solid --color-error. Laast.

   --field-gap                      var(--gap-form-row)
     20 px mellem to felter.

   --field-label-gap                var(--gap-tight)
     8 px fra label til felt.

   --field-help-gap                 var(--gap-hairline)
     4 px fra felt til hjaelpe- eller fejltekst.

   --field-check-size               24px
     Checkboksens og radioknappens flade. Ikke i nogen master.

   --field-check-radius             var(--radius-hairline)
     4 px. Formmasteren forbyder 6/9/11/12/14/18/20 px.

   --field-chevron                  10px
     Select-chevronens halve diagonal. Ikke i nogen master.

   --field-status-icon              var(--icon-size-sm)  [deprecated v1.0.1]
     Var 16 px. Iconography tillader kun 20/24 px; fejl-/statusikoner er nu
     .olb-icon--sm fra sprite.

   --field-inline-icon              var(--icon-size-sm)
     Ikonet inde i feltet: soeg, ryd, vis adgangskode (20 px, rem).

   --field-textarea-min-height      96px
     Tre linjer: 3 x 23,8 + 2 x 11 + 2 x 1 = 95,4 px, rundet op til 96.

   --field-textarea-padding-y       11px
     Afledt: (48 - 23,8 - 2) / 2 = 11,1 px. Goer at textareaens foerste linje
     staar paa linje med et inputfelts tekst.

   --field-measure                  44ch
     Hjaelpe- og fejltekstens maksimale linjelaengde, laast i typografimasteren.

*/


/* =====================================================================
   1. FELTETS ANATOMI
   Label og control er obligatoriske. Hjaelpetekst og fejltekst er
   valgfrie og tilfoejes kun, naar de goer en forskel.

   Raekkefoelgen i DOM er label, control, hjaelpetekst, fejltekst. Den
   raekkefoelge er ogsaa den visuelle, saa skaermlaeser og oje laeser det
   samme.
   ===================================================================== */

.olb-field {
  display: flex;
  flex-direction: column;
  gap: var(--field-label-gap);
  margin-block-end: var(--field-gap);
}

/* Sidste felt i en gruppe maa ikke laegge afstand til det naeste. */
.olb-field:last-child,
.olb-field:last-of-type {
  margin-block-end: 0;
}

.olb-field__label {
  display: block;
  font-family: var(--font-family-body);
  font-size: var(--font-size-label);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-ui);
  color: var(--color-text-primary);
}

/* "Valgfrit" staar i samme linje som labelen, i normal vaegt. Det er den
   eneste markering; paakraevede felter markeres ikke. */
.olb-field__optional {
  font-weight: var(--font-weight-regular);
  color: var(--color-text-muted);
}

.olb-field__help {
  font-size: var(--font-size-help);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-help);
  color: var(--color-text-muted);
  max-width: var(--field-measure);
}

.olb-field__error {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-hairline);
  font-size: var(--font-size-error);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-help);
  color: var(--color-error);
  max-width: var(--field-measure);
}

/* Fejlen baerer tre signaler: kantens tykkelse og farve, ikonet og
   teksten. Farve alene er aldrig nok.
   X-02 (v1.0.1): ikonet er et sprite-barn, ikke en data-URI-maske:
   <svg class="olb-icon olb-icon--sm" aria-hidden="true" focusable="false"><use href="#olb-i-warning"/></svg>
   Farven arves (currentColor = --color-error). Gaelder ogsaa
   .olb-form-message--error (warning), --success (success) og
   .olb-error-summary__title (warning). */

/* Fejlteksten erstatter hjaelpeteksten; begge vises ikke samtidig.
   G-01 (v1.0.1): canonical hook er aria-invalid paa kontrollen.
   [data-invalid] paa wrapperen er deprecated alias; fjernes i v1.1. */
.olb-field:has([aria-invalid="true"]) .olb-field__help,
.olb-field[data-invalid] .olb-field__help {
  display: none;
}


/* =====================================================================
   2. FELTET SELV

   48 px er knappens standardhoejde og typografimasterens touch-floor.
   Inputteksten er 17 px, saa der er 11,1 px over og under den.
   ===================================================================== */

.olb-input,
.olb-select,
.olb-textarea {
  display: block;
  width: 100%;
  min-height: var(--field-height);
  padding-block: var(--field-textarea-padding-y);
  padding-inline: var(--field-padding-x);
  font-family: var(--font-family-body);
  font-size: var(--font-size-input);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-ui);
  color: var(--color-text-primary);
  background-color: var(--color-surface);
  border: var(--field-border);
  border-radius: var(--field-radius);
  /* Ingen egen box-shadow. Formmasteren §9. */
  appearance: none;
}

/* Placeholderen er et eksempel, ikke en label. Den bruger text-muted,
   som er maalt til 6,12:1 mod hvid. */
.olb-input::placeholder,
.olb-textarea::placeholder {
  color: var(--color-text-muted);
  opacity: 1;
}

/* BUG-01 (v1.0.1): hover kun paa aegte hover-enheder (F&D §35.10, Behavior §4).
   BUG-02 (v1.0.1): fejlkanten vinder over hover (Behavior §3: error > selected > hover).
   Hover-reglen rammer derfor ikke et felt med aria-invalid — uden !important. */
@media (hover: hover) and (pointer: fine) {
  .olb-input:hover:not(:disabled):not([aria-invalid="true"]),
  .olb-select:hover:not(:disabled):not([aria-invalid="true"]),
  .olb-textarea:hover:not(:disabled):not([aria-invalid="true"]) {
    /* Samme tykkelse, staerkere farve. Formmasteren §18. */
    border-color: var(--color-text-secondary);
  }
}

/* Fejl. 2 px kant, og padding reduceres med 1 px, saa indholdet staar
   stille. Uden kompensationen ville alt under feltet flytte sig. */
.olb-input[aria-invalid="true"],
.olb-select[aria-invalid="true"],
.olb-textarea[aria-invalid="true"] {
  border: var(--field-border-error);
  padding-inline: calc(var(--field-padding-x) - 1px);
  padding-block: calc(var(--field-textarea-padding-y) - 1px);
}

/* Disabled. Farvesystemets disabled-tekst er 2,77:1 og dermed for svag
   for en 45+ kunde. Button-masteren loeste det med --color-text-muted;
   den samme laesbare token bruges her, maalt til 5,25:1 mod soft.
   Det er et upstream-fund, ikke en lokal farve. */
.olb-input:disabled,
.olb-select:disabled,
.olb-textarea:disabled {
  color: var(--color-text-muted);
  background-color: var(--color-disabled-bg);
  border-color: var(--color-border);
  cursor: not-allowed;
}

.olb-input:disabled::placeholder,
.olb-textarea:disabled::placeholder {
  color: var(--color-text-muted);
}

/* Read-only er ikke disabled. Feltet virker, kan fokuseres, markeres og
   kopieres, men tager ikke imod input. Teksten forbliver laesbar. */
.olb-input[readonly],
.olb-textarea[readonly] {
  /* Tre ting skal kunne ses samtidig:

       normal     hvid flade, staerk kant, staerk tekst
       read-only  soft flade, staerk kant, staerk tekst
       disabled   soft flade, dekorativ kant, daempet tekst

     Fladen siger "ikke redigerbar her". Kanten og teksten siger, om
     indholdet er rigtigt og laesbart. Read-only beholder derfor baade
     den funktionelle kant og den fulde tekstkontrast, saa kunden kan
     se, at der staar noget rigtigt, som kan markeres og kopieres.
     Disabled daempes paa begge, fordi feltet hverken kan bruges eller
     kopieres meningsfuldt. */
  background-color: var(--color-surface-soft);
  color: var(--color-text-primary);
  border-color: var(--color-border-strong);
  cursor: text;
}

/* Autofill. Den saedvanlige teknik bruger en inset box-shadow, hvilket
   formmasteren forbyder paa fokuserbare elementer. I stedet holdes
   baggrunden hvid med en meget lang transition, og tekst, caret, font og
   vaegt laases, saa browseren ikke aendrer dem. */
.olb-input:-webkit-autofill,
.olb-input:-webkit-autofill:hover,
.olb-input:-webkit-autofill:focus,
.olb-select:-webkit-autofill,
.olb-textarea:-webkit-autofill {
  -webkit-text-fill-color: var(--color-text-primary);
  caret-color: var(--color-text-primary);
  transition: background-color 6000000s 0s;
  font-family: var(--font-family-body);
  font-size: var(--font-size-input);
  font-weight: var(--font-weight-regular);
}

/* Firefox og Safari uden -webkit- praefiks. */
.olb-input:autofill,
.olb-textarea:autofill {
  background-color: var(--color-surface);
  color: var(--color-text-primary);
}


/* =====================================================================
   3. SELECT

   Native select. Den aabner operativsystemets egen vaelger paa mobil,
   virker med skaermlaeser uden JavaScript og sender korrekt med i
   WooCommerce' formular. Chevronen tegnes med to kanter i
   --color-text-secondary, saa der ikke indfoeres en farve.
   ===================================================================== */

.olb-select-wrap {
  position: relative;
  display: block;
}

.olb-select {
  padding-inline-end: calc(var(--field-padding-x) + var(--field-inline-icon) + var(--gap-tight));
  cursor: pointer;
}

.olb-select-wrap::after {
  content: "";
  position: absolute;
  inset-inline-end: var(--field-padding-x);
  inset-block-start: 50%;
  width: var(--field-chevron);    /* G-08: tokenet var deklareret men ubrugt */
  height: var(--field-chevron);
  margin-block-start: -7px;
  border-right: var(--border-width-strong) solid var(--color-text-secondary);
  border-bottom: var(--border-width-strong) solid var(--color-text-secondary);
  transform: rotate(45deg);
  pointer-events: none;
}

/* En select uden valgt vaerdi er ikke tom; den viser sin
   pladsholder-option. Den er disabled, saa den ikke kan vaelges igen. */
.olb-select:has(option[value=""]:checked) {
  color: var(--color-text-muted);
}


/* =====================================================================
   4. TEXTAREA

   Tre linjer som minimum, resize kun lodret, og ingen auto-grow. En
   auto-grow flytter alt indhold under feltet, mens kunden skriver.
   ===================================================================== */

.olb-textarea {
  min-height: var(--field-textarea-min-height);
  resize: vertical;
  max-height: 40vh;
  /* Hoejre padding holder teksten fri af resize-haandtaget. */
  padding-inline-end: calc(var(--field-padding-x) + var(--gap-tight));
}


/* =====================================================================
   5. CHECKBOX OG RADIO

   24 x 24 px flade med 4 px radius. Hele linjen er klikomraadet, saa
   maalet er mindst 48 px hoejt uden at boksen bliver stor.
   ===================================================================== */

.olb-choice {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-inline);
  min-inline-size: 0;
  min-height: var(--field-height);
  padding-block: var(--gap-hairline);
  cursor: pointer;
  /* The checkmark is drawn on the wrapper, not on the input. A mask on
     the input would mask the input's own petrol fill as well, leaving a
     checkmark with no box behind it. The wrapper can carry both: the
     input keeps the fill, the pseudo-element draws the mark on top. */
  position: relative;
}

/* X-02 (v1.0.1): fluebenet er kontrolgeometri, ikke et ikon. Det tegnes med
   to kanter i --border-width-strong (2 px = Iconography-stregen) roteret 45°,
   ligesom select-chevronen — ingen data-URI, ingen ny farve. Placeringen er
   afledt af boksen: 24 px flade, 6 px fra toppen (4 px padding + 2 px loeft). */
.olb-choice::before {
  content: "";
  position: absolute;
  inset-inline-start: 9px;
  inset-block-start: 11px;
  width: 6px;
  height: 12px;
  border: solid var(--color-selected-strong-fg);
  border-width: 0 var(--border-width-strong) var(--border-width-strong) 0;
  transform: rotate(45deg);
  pointer-events: none;
  display: none;
}

/* X-05 (v1.0.1): .olb-selectable__input er samme synlige kontrol som
   .olb-choice__input (1 px --border-control, 3,66:1). Kortets kant er kun
   container; kontrollen baerer affordancen. */
.olb-choice__input,
.olb-selectable__input {
  flex: 0 0 auto;
  width: var(--field-check-size);
  height: var(--field-check-size);
  margin: 0;
  /* Lofter boksen op paa linje med den foerste tekstlinje. */
  margin-block-start: 2px;
  appearance: none;
  background-color: var(--color-surface);
  border: var(--field-border);
  border-radius: var(--field-check-radius);
  cursor: pointer;
}

.olb-choice__input[type="radio"],
.olb-selectable__input[type="radio"] {
  border-radius: var(--radius-pill);
}

.olb-choice__input[type="checkbox"]:checked {
  background-color: var(--color-selected-strong-bg);
  border-color: var(--color-selected-strong-bg);
}

.olb-choice__input[type="radio"]:checked,
.olb-selectable__input[type="radio"]:checked {
  border-color: var(--color-selected-strong-bg);
}

.olb-choice:has(.olb-choice__input:checked[type="checkbox"])::before {
  display: block;
}

.olb-choice__input:checked[type="radio"],
.olb-selectable__input:checked[type="radio"] {
  border-width: 7px;
}

/* Indeterminate: en vandret streg, ikke et flueben. */
.olb-choice__input:indeterminate {
  background-color: var(--color-selected-strong-bg);
  border-color: var(--color-selected-strong-bg);
}

.olb-choice:has(.olb-choice__input:indeterminate[type="checkbox"])::before {
  display: block;
  inset-block-start: 17px;
  inset-inline-start: 5px;
  width: 14px;
  height: 2px;
  border: 0;
  transform: none;
  background-color: var(--color-selected-strong-fg);
}

.olb-choice__input:disabled,
.olb-selectable__input:disabled {
  background-color: var(--color-disabled-bg);
  border-color: var(--color-border);
  cursor: not-allowed;
}

.olb-choice__input:disabled:checked,
.olb-selectable__input:disabled:checked {
  background-color: var(--color-text-muted);
  border-color: var(--color-text-muted);
}

.olb-choice:has(.olb-choice__input:disabled) {
  cursor: not-allowed;
  color: var(--color-text-muted);
}

.olb-choice__label {
  font-size: var(--font-size-label);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-ui);
  color: var(--color-text-primary);
  min-inline-size: 0;
  /* Flere linjer i en checkbox-label flugter under teksten, ikke under
     boksen. */
}

.olb-choice__label a {
  color: var(--color-link);
}

.olb-choice__help {
  display: block;
  font-size: var(--font-size-help);
  line-height: var(--line-height-help);
  color: var(--color-text-muted);
  max-width: var(--field-measure);
}

/* Fejl paa en enkelt checkbox: teksten bliver roed og der tilfoejes en
   besked. Boksen faar ikke en 2 px kant, fordi den er 24 px og ville
   se ude af proportion.
   G-02 (v1.0.1): canonical hook er aria-invalid paa inputtet.
   .olb-choice--invalid er deprecated alias; fjernes i v1.1. */
.olb-choice:has(.olb-choice__input[aria-invalid="true"]) .olb-choice__label,
.olb-choice--invalid .olb-choice__label {
  color: var(--color-error);
}

.olb-form-message--error {
  display: flex;
  align-items: flex-start;
  gap: var(--field-help-gap);
  font-size: var(--font-size-error);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-help);
  color: var(--color-error);
  max-width: var(--field-measure);
}

/* Bekraeftelse. Bruges kun hvor den forhindrer en reel fejl. */
.olb-form-message--success {
  display: flex;
  align-items: flex-start;
  gap: var(--field-help-gap);
  font-size: var(--font-size-help);
  line-height: var(--line-height-help);
  color: var(--color-success);
  max-width: var(--field-measure);
}


/* =====================================================================
   6. VALGBARE KORT

   Altid 2 px kant, ogsaa uvalgt. Formmasteren §8. Skiftede kanten fra
   1 til 2 px ved valg, ville kortet vokse 2 px og skubbe resten af
   formularen ned.
   ===================================================================== */

.olb-selectable-group {
  display: flex;
  flex-direction: column;
  gap: var(--gap-inline);
  border: 0;
  padding: 0;
  margin: 0;
  /* A fieldset has min-inline-size:min-content by default, so it refuses
     to shrink below its widest child and overflows its grid column. This
     is the only reason the rule below is needed; it is not cosmetic. */
  min-inline-size: 0;
}

/* G-04 (v1.0.1): kant (2 px --border-selectable) og radius ejes af
   Form & Dybde (.olb-selectable). Forms gentager dem ikke. */
.olb-selectable {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-inline);
  min-inline-size: 0;
  padding: var(--gap-component);
  background-color: var(--color-surface);
  cursor: pointer;
}

/* BUG-01 (v1.0.1): kun aegte hover. */
@media (hover: hover) and (pointer: fine) {
  .olb-selectable:hover {
    background-color: var(--color-hover-bg);
  }
}

.olb-selectable.is-selected,
.olb-selectable:has(.olb-selectable__input:checked) {
  background-color: var(--color-selected-subtle-bg);
  border-color: var(--color-selected-subtle-border);
}

.olb-selectable__body {
  display: flex;
  flex-direction: column;
  gap: var(--gap-hairline);
  flex: 1 1 auto;
  min-inline-size: 0;
}

.olb-selectable__title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  /* When the card is narrow, the price drops below the title instead of
     forcing the card wider. A nowrap price beside a title needs about
     230 px; below that the row would otherwise overflow its column. */
  flex-wrap: wrap;
  gap: var(--gap-inline);
  font-size: var(--font-size-radio-title);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
}

.olb-selectable__price {
  font-size: var(--font-size-radio-title);
  font-weight: var(--font-weight-semibold);
  /* G-08 (v1.0.1): white-space:nowrap fjernet – den blev ubetinget annulleret
     af zoom-reglen nederst (white-space:normal). Prisen deler kun ved mellemrum. */
  font-variant-numeric: tabular-nums lining-nums;
  /* Prisen maa ikke holde kortet bredere end sin kolonne. Ved 200 %
     zoom bliver den effektive bredde 160 px, og '39,00 kr' kan ikke
     vaere bredere end den plads, der er tilbage. */
  max-inline-size: 100%;
}

.olb-selectable__desc {
  font-size: var(--font-size-radio-description);
  line-height: var(--line-height-help);
  color: var(--color-text-muted);
}

.olb-selectable:has(.olb-selectable__input:disabled) {
  background-color: var(--color-disabled-bg);
  border-color: var(--color-border);
  cursor: not-allowed;
}

.olb-selectable:has(.olb-selectable__input:disabled) .olb-selectable__title,
.olb-selectable:has(.olb-selectable__input:disabled) .olb-selectable__desc {
  color: var(--color-text-muted);
}

/* Legenden ser ud som en label, fordi gruppen er et felt, ikke en
   sektion. */
.olb-fieldset__legend {
  display: block;
  padding: 0;
  margin-block-end: var(--field-label-gap);
  font-size: var(--font-size-label);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-ui);
  color: var(--color-text-primary);
}


/* =====================================================================
   7. FELTER I RAEKKE

   To felter maa dele en raekke, naar der er maalt luft til den laengste
   vaerdi. Ved 320 px er der 3,2 px til 'Frederiksberg' og -27,0 px til
   'Soerensen-Jensen', saa raekker er ikke mulige der. Ved 390 px er
   begge over 5 px og ved 430 px over 24 px, men ingen af de bredder er
   en systemzone.

   Graensen er derfor layoutmasterens globale 768 px (§8, governance 14).
   768 px er systemets tablet-breakpoint, og 480 px findes ikke i nogen
   master. Et lokalt komponentbreakpoint ville bryde governance 14.

   Mobil er altid én kolonne. Det er ikke en tilpasning; det er
   udgangspunktet, og raekken er undtagelsen.
   ===================================================================== */

/* BUG-07 (v1.0.1): raekken ejer sin afstand til naeste felt, og felterne i
   raekken laegger ingen egen margin (raekkens gap goer det). Dermed:
   felt → felt = 20 · field-row → naeste felt = 20 · intern raekkeafstand
   20 (mobil, 1 kolonne) / 12 (≥768, to kolonner) – uaendret. */
.olb-field-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--field-gap);
  margin-block-end: var(--field-gap);
}

.olb-field-row:last-child {
  margin-block-end: 0;
}

.olb-field-row > .olb-field {
  margin-block-end: 0;
}

@media (min-width: 768px) {
  .olb-field-row--pair {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--gap-inline);
  }
}

/* Et felt med en handling ved siden af, fx soeg eller en sekundaer
   handling. Raekken kraever, at begge dele kan blive smalle, og under
   768 px staar knappen derfor under feltet. Samme graense som for to
   felter i raekke, og af samme grund: der skal vaere maalt luft til
   baade feltets indhold og knappens label. */
.olb-field-inline {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-inline);
}

.olb-field-inline > .olb-field {
  flex: 1 1 auto;
  min-inline-size: 0;
}

.olb-field-inline > .olb-button {
  flex: 0 0 auto;
}

@media (max-width: 767.98px) {
  .olb-field-inline {
    flex-direction: column;
    align-items: stretch;
  }
  .olb-field-inline > .olb-button {
    width: 100%;
  }
}


/* =====================================================================
   8. SEKTIONER

   Ét kort pr. sektion, 10 px radius, 1 px dekorativ kant, ingen skygge.
   Ingen kort inde i kort. Formmasteren §17 og §35.
   ===================================================================== */

.olb-form-section {
  background-color: var(--color-surface);
  border: var(--border-card);
  border-radius: var(--radius-checkout-card);
  padding: var(--gap-component);
}

.olb-form-section + .olb-form-section {
  margin-block-start: var(--checkout-section-gap);
}

.olb-form-section__heading {
  display: block;
  margin: 0 0 var(--checkout-heading-gap);
  font-family: var(--font-family-checkout-heading);
  font-size: var(--font-size-checkout-section);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-subheading);
  color: var(--color-text-primary);
}

.olb-form-section--flush {
  background-color: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
}

/* Indholdet i en formular bliver ikke bredere end containeren. */
.olb-form {
  display: flow-root;
}

.olb-form__actions {
  margin-block-start: var(--checkout-total-to-cta);
}

.olb-form__actions .olb-button {
  width: 100%;
}


/* =====================================================================
   9. FEJLOPSUMMERING

   Bruges i checkout, hvor der kan vaere fejl baade over og under folden.
   Den faar fokus ved fejlet submit, saa skaermlaeseren laeser fejlene op
   og kunden staar ved den foerste.
   ===================================================================== */

.olb-error-summary {
  border: var(--field-border-error);
  border-radius: var(--radius-checkout-card);   /* G-07: semantisk, samme 10 px */
  padding: var(--gap-component);
  margin-block-end: var(--checkout-section-gap);
  background-color: var(--color-surface);
  color: var(--color-error);
}

.olb-error-summary__title {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-tight);
  font-size: var(--font-size-error);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-help);
}

.olb-error-summary__list {
  margin: var(--gap-tight) 0 0;
  padding-inline-start: var(--gap-component);
  font-size: var(--font-size-help);
  line-height: var(--line-height-help);
}

.olb-error-summary__list a {
  color: var(--color-error);
  font-weight: var(--font-weight-semibold);
}


/* =====================================================================
   10. SEARCH

   Samme feltgeometri som alle andre felter. Kun ikonet og ryd-knappen
   tilfoejes. Soegningen er ikke sin egen formstil.
   ===================================================================== */

.olb-search {
  position: relative;
  display: block;
}

.olb-search .olb-input {
  padding-inline-start: calc(var(--field-padding-x) + var(--field-inline-icon) + var(--gap-tight));
}

/* Ryd-knappen er kun i vejen, naar der er noget at rydde. */
.olb-search .olb-input:placeholder-shown ~ .olb-search__clear {
  display: none;
}

.olb-search__icon,
.olb-search__clear {
  position: absolute;
  inset-block-start: 50%;
  translate: 0 -50%;
  display: grid;
  place-items: center;
  width: var(--field-height);
  height: var(--field-height);
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--color-text-secondary);
}

.olb-search__icon {
  inset-inline-start: 0;
  pointer-events: none;
}

.olb-search__clear {
  inset-inline-end: 0;
  color: var(--color-text-secondary);
}

/* X-02 (v1.0.1): soeg- og ryd-ikonerne er sprite-boern:
   <span class="olb-search__icon" aria-hidden="true"><svg class="olb-icon olb-icon--sm" …><use href="#olb-i-search"/></svg></span>
   <button class="olb-search__clear" aria-label="Ryd soegning"><svg class="olb-icon olb-icon--sm" …><use href="#olb-i-close"/></svg></button> */


/* =====================================================================
   11. INLINE HANDLINGER

   Ikonknappen inde i feltet er 48 px, saa den er et lovligt touch-maal,
   ogsaa naar feltet kun er 48 px hoejt.
   ===================================================================== */

.olb-field__action {
  position: absolute;
  inset-inline-end: 0;
  inset-block-start: 0;
  display: grid;
  place-items: center;
  width: var(--field-height);
  height: var(--field-height);
  padding: 0;
  background: none;
  border: 0;
  color: var(--color-text-secondary);
  cursor: pointer;
}

/* X-02 (v1.0.1): vis/skjul-adgangskode bruger sprite-ikonerne eye/eye-off.
   Begge ligger i knappen; aria-pressed (canonical ARIA-hook) vaelger hvilket vises:
   <button class="olb-field__action olb-field__action--password" aria-pressed="false" aria-label="Vis adgangskode">
     <svg class="olb-icon olb-icon--sm olb-field__action-icon--show" …><use href="#olb-i-eye"/></svg>
     <svg class="olb-icon olb-icon--sm olb-field__action-icon--hide" …><use href="#olb-i-eye-off"/></svg>
   </button> */
.olb-field__action--password[aria-pressed="true"] .olb-field__action-icon--show,
.olb-field__action--password:not([aria-pressed="true"]) .olb-field__action-icon--hide {
  display: none;
}

.olb-field--with-action {
  position: relative;
}

.olb-field--with-action .olb-input {
  padding-inline-end: calc(var(--field-padding-x) + var(--field-height));
}


/* =====================================================================
   12. KUPONKODE

   Sammenklappet som standard. Ved 320 px maaler feltet 195,7 px og
   knappen 87,8 px, saa koden 'SOMMER2026' paa 117,8 px har 53,9 px
   luft.
   ===================================================================== */

.olb-coupon {
  border: var(--border-card);
  border-radius: var(--radius-checkout-card);
  background-color: var(--color-surface);
}

.olb-coupon__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: var(--field-height);
  padding-inline: var(--gap-component);
  font-size: var(--font-size-label);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
  background: none;
  border: 0;
  cursor: pointer;
  text-align: start;
}

.olb-coupon__row {
  display: flex;
  gap: var(--gap-inline);
  padding: 0 var(--gap-component) var(--gap-component);
}

.olb-coupon__row .olb-input {
  flex: 1 1 auto;
  min-width: 0;
}

.olb-coupon__row .olb-button {
  flex: 0 0 auto;
}

/* Ved 320 px er kortets indre bredde 251,5 px. Felt og knap kraever
   219,5 px og passer derfor i bredden — men feltets indre bredde bliver
   kun 82,3 px, mens koden 'SOMMER2026' maaler 117,8 px. Kunden kan ikke
   se, hvad hun skriver. Under 768 px staar knappen derfor under feltet,
   hvor den indre bredde bliver 193,5 px og koden har 75,7 px luft. */
@media (max-width: 767.98px) {
  .olb-coupon__row {
    flex-direction: column;
    align-items: stretch;
  }
  .olb-coupon__row .olb-button {
    width: 100%;
  }
}


/* =====================================================================
   13. FRAGTBREGNING

   Land og postnummer staar tidligt. Naar begge er gyldige, beregnes
   fragten. Beskeden staar i hjaelpetekstens plads og i dens farve, og
   submit forbliver aktiv. Det maa ikke foeles som en fejl, at systemet
   blot regner.
   ===================================================================== */

.olb-field__status {
  display: flex;
  align-items: center;
  gap: var(--gap-hairline);
  font-size: var(--font-size-help);
  line-height: var(--line-height-help);
  color: var(--color-text-muted);
  max-width: var(--field-measure);
}

/* G-01 (v1.0.1): canonical hook er aria-busy="true" paa statuslinjen
   (Behavior §16). [data-state="busy"] er deprecated alias; fjernes i v1.1. */
.olb-field__status[aria-busy="true"]::before,
.olb-field__status[data-state="busy"]::before {
  content: "";
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  border: var(--border-width-strong) solid var(--color-border);
  border-top-color: var(--color-text-secondary);
  border-radius: var(--radius-pill);
  animation: olb-spin 800ms linear infinite;
}

@keyframes olb-spin {
  to { transform: rotate(360deg); }
}

/* BUG-08 (v1.0.1): spinneren er Behavior §12's ene undtagelse – den stopper
   ikke under reduced motion, den saenkes (samme 2,4 s som Buttons). */
@media (prefers-reduced-motion: reduce) {
  .olb-field__status[aria-busy="true"]::before,
  .olb-field__status[data-state="busy"]::before {
    animation-duration: 2.4s;
  }
}


/* =====================================================================
   14. IKONER — fra faelles sprite (X-02, v1.0.1)

   Forms' seks data-URI-masker (--olb-icon-check/-warning/-search/-close/
   -eye/-eye-off) er fjernet. Alle ikoner er nu .olb-icon fra
   olb-icons-v0.4.svg: warning, success, search, close, eye, eye-off.
   Fluebenet i checkbox er kontrolgeometri (se §5). currentColor bevares.
   ===================================================================== */




/* =====================================================================
   15. NATIVE SELECT I WOODCOMMERCE-TABELLER

   Woo bruger sine egne klasser til land, maaned og aar. De styles
   direkte, saa ingen ekstra wrapper er noedvendig.
   ===================================================================== */

.woocommerce form .form-row select,
.woocommerce-page form .form-row select,
.woocommerce-input-wrapper select {
  min-height: var(--field-height);
  padding: var(--field-textarea-padding-y) var(--field-padding-x);
  border: var(--field-border);
  border-radius: var(--field-radius);
  background-color: var(--color-surface);
  color: var(--color-text-primary);
  font-family: var(--font-family-body);
  font-size: var(--font-size-input);
  line-height: var(--line-height-ui);
  width: 100%;
}


/* =====================================================================
   16. ZOOM

   Ved 200 % zoom halveres den effektive viewportbredde. 320 px bliver
   160 px. Feltet maa ikke blive smallere end sit indhold, og teksten maa
   ikke klippes.
   ===================================================================== */

.olb-input,
.olb-select,
.olb-textarea {
  min-width: 0;
  max-width: 100%;
}

/* Ved 200 % zoom halveres den effektive viewportbredde: 320 px bliver
   160 px. Ved den bredde kan et sammensat dansk ord som
   'handelsbetingelserne' ikke vaere bredere end pladsen, og browseren
   bryder det ikke selv. Reglen er derfor ubetinget — den bryder kun ord,
   der ellers ikke kan vaere der — saa den ogsaa daekker zoom uden et
   breakpoint, der ikke findes i nogen master. */

.olb-field__label,
.olb-field__help,
.olb-field__error,
.olb-field__status,
.olb-choice__label,
.olb-choice__help,
.olb-selectable__title,
.olb-selectable__desc,
.olb-form-message--error,
.olb-form-message--success,
.olb-error-summary__title,
.olb-error-summary__list,
.olb-fieldset__legend {
  overflow-wrap: anywhere;
}
/* Prisen holder normalt én linje, ogsaa naar titlen ombrydes. Ved
   200 % zoom bliver den effektive bredde 160 px, og '39,00 kr' kan
   ikke vaere bredere end den plads, kortet har tilbage. Paa det
   bredde tages derfor hensyn til, at prisen kan dele sig ved
   mellemrummet; det er stadig en laesbar pris, hvorimod et
   vandret scroll er en fejl. */
.olb-selectable__price {
  white-space: normal;
}


/* =====================================================================
   16. WOOCOMMERCE PRESENTATION ADAPTER (BUG-09, v1.0.1)

   Forms-master §10 kraever at Woo's egen markup mappes direkte til de
   eksisterende Forms-visuals. Kun praesentation: ingen DOM-refactor,
   ingen nye felter, ingen checkout-logik. Alle vaerdier er de samme
   tokens som .olb-field / .olb-input / .olb-choice / .olb-error-summary.
   ===================================================================== */

/* p.form-row  →  .olb-field */
.woocommerce form .form-row {
  display: flex;
  flex-direction: column;
  gap: var(--field-label-gap);
  margin: 0 0 var(--field-gap);
  padding: 0;
}

/* .form-row label  →  .olb-field__label */
.woocommerce form .form-row > label {
  display: block;
  font-family: var(--font-family-body);
  font-size: var(--font-size-label);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-ui);
  color: var(--color-text-primary);
  overflow-wrap: anywhere;
}

/* "(valgfrit)" som .olb-field__optional; paakraevet markeres ikke (Forms §18 #3) */
.woocommerce form .form-row .optional {
  font-weight: var(--font-weight-regular);
  color: var(--color-text-muted);
}

.woocommerce form .form-row .required {
  display: none;
}

/* .woocommerce-input-wrapper fylder bredden (Forms §10) */
.woocommerce form .form-row .woocommerce-input-wrapper {
  display: block;
  width: 100%;
}

/* .input-text / .woocommerce-Input / textarea  →  .olb-input / .olb-textarea */
.woocommerce form .form-row .input-text,
.woocommerce form .form-row .woocommerce-Input,
.woocommerce form .form-row textarea {
  display: block;
  width: 100%;
  min-width: 0;
  max-width: 100%;
  min-height: var(--field-height);
  padding-block: var(--field-textarea-padding-y);
  padding-inline: var(--field-padding-x);
  font-family: var(--font-family-body);
  font-size: var(--font-size-input);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-ui);
  color: var(--color-text-primary);
  background-color: var(--color-surface);
  border: var(--field-border);
  border-radius: var(--field-radius);
  appearance: none;
}

.woocommerce form .form-row textarea {
  min-height: var(--field-textarea-min-height);
  resize: vertical;
}

@media (hover: hover) and (pointer: fine) {
  .woocommerce form .form-row:not(.woocommerce-invalid) .input-text:hover:not(:disabled),
  .woocommerce form .form-row:not(.woocommerce-invalid) select:hover:not(:disabled),
  .woocommerce form .form-row:not(.woocommerce-invalid) textarea:hover:not(:disabled) {
    border-color: var(--color-text-secondary);
  }
}

/* .woocommerce-invalid  →  samme fejl som aria-invalid (2 px + 1 px kompensation) */
.woocommerce form .form-row.woocommerce-invalid .input-text,
.woocommerce form .form-row.woocommerce-invalid select,
.woocommerce form .form-row.woocommerce-invalid textarea {
  border: var(--field-border-error);
  padding-inline: calc(var(--field-padding-x) - 1px);
  padding-block: calc(var(--field-textarea-padding-y) - 1px);
}

/* .woocommerce-validated sættes ikke visuelt (Forms §10) – bevidst ingen regel. */

/* Woo-checkbox/-radio  →  .olb-choice / .olb-choice__input */
.woocommerce form .woocommerce-form__label-for-checkbox {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--gap-inline);
  min-height: var(--field-height);
  padding-block: var(--gap-hairline);
  font-size: var(--font-size-label);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-ui);
  color: var(--color-text-primary);
  cursor: pointer;
}

.woocommerce form .woocommerce-form__input-checkbox,
.woocommerce form .woocommerce-form__input-radio,
.woocommerce form input.input-radio,
.woocommerce form input.input-checkbox {
  flex: 0 0 auto;
  width: var(--field-check-size);
  height: var(--field-check-size);
  margin: 0;
  margin-block-start: 2px;
  appearance: none;
  background-color: var(--color-surface);
  border: var(--field-border);
  border-radius: var(--field-check-radius);
  cursor: pointer;
}

.woocommerce form .woocommerce-form__input-radio,
.woocommerce form input.input-radio {
  border-radius: var(--radius-pill);
}

.woocommerce form .woocommerce-form__input-checkbox:checked,
.woocommerce form input.input-checkbox:checked {
  background-color: var(--color-selected-strong-bg);
  border-color: var(--color-selected-strong-bg);
}

.woocommerce form .woocommerce-form__input-radio:checked,
.woocommerce form input.input-radio:checked {
  border-color: var(--color-selected-strong-bg);
  border-width: 7px;
}

.woocommerce form .woocommerce-form__label-for-checkbox::before {
  content: "";
  position: absolute;
  inset-inline-start: 9px;
  inset-block-start: 11px;
  width: 6px;
  height: 12px;
  border: solid var(--color-selected-strong-fg);
  border-width: 0 var(--border-width-strong) var(--border-width-strong) 0;
  transform: rotate(45deg);
  pointer-events: none;
  display: none;
}

.woocommerce form .woocommerce-form__label-for-checkbox:has(input[type="checkbox"]:checked)::before {
  display: block;
}

/* To felter i raekke kun fra 768 (Forms §7): Woo's floats neutraliseres under 768. */
@media (max-width: 767.98px) {
  .woocommerce form .form-row-first,
  .woocommerce form .form-row-last {
    float: none;
    width: 100%;
  }
}

/* .woocommerce-error (ul)  →  .olb-error-summary; semantik og links bevares */
.woocommerce-error {
  list-style: none;
  margin: 0 0 var(--checkout-section-gap);
  padding: var(--gap-component);
  border: var(--field-border-error);
  border-radius: var(--radius-checkout-card);
  background-color: var(--color-surface);
  color: var(--color-error);
  font-size: var(--font-size-help);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-help);
  overflow-wrap: anywhere;
}

.woocommerce-error a {
  color: var(--color-error);
  font-weight: var(--font-weight-semibold);
}

/* .woocommerce-message  →  .olb-form-message--success (kun hvor det forhindrer tvivl, Forms §8) */
.woocommerce-message {
  margin: 0 0 var(--checkout-section-gap);
  font-size: var(--font-size-help);
  line-height: var(--line-height-help);
  color: var(--color-success);
  overflow-wrap: anywhere;
}

/* .woocommerce-info: Forms har ingen info-visual. Ingen regel her – se
   OLB_REPAIR_OPEN_ITEMS_RC1 (kraever status/notice-komponent, G-15). */


/* =====================================================================
   AUDITNOTER TIL BUILD
   =====================================================================
   Denne fil er genereret. Ret build/ i stedet.

   v1.0.1: genverificeret i repair RC1-harnessen (OLB_REPAIR_REGRESSION_MATRIX_RC1).
   Kontrolleret af build/verify.py i browseren (v1.0):
     - ingen fokuserbar komponent saetter sin egen box-shadow
     - ingen komponent saetter outline eller outline:none
     - error-border giver 0 px layoutshift
     - valgbart kort har 2 px geometry i begge tilstande
     - ingen radiusvaerdi uden for formmasterens skala
     - ingen HEX uden for variabeldefinitionerne
     - feltet er 48 px ved hver bredde
     - to felter staar kun side om side fra 768 px (layoutmasterens tablet-breakpoint)
*/

