/* forms.css — the frontend-forms (F3) server-primitive tier: error summary,
   formset host/row/template, form-card__actions alignment modifiers, and
   two moved-in-place families — `.imp-file` (from pages/import-orders.css)
   and `.seg`/`.seg__opt` (from pages/loads-placement.css). `.fld`,
   `.form-row`, `.form-card__actions` (the bare/`end` rendering) and the
   `.cs` family stay in shell.css / custom-select.css, UNCHANGED — this
   sheet only adds what those do not already cover.

   Slot in base.html: immediately AFTER custom-select.css and BEFORE
   feedback-widget.css (architecture §3) — the `.cs` family this sheet's
   `.seg`/`.imp-file` rules sit beside must precede it. Tokens only. */

/* ---------------------------------------------------------------------
   Form error summary — .enr-form-errors* (contract §D "Form summary")
   --------------------------------------------------------------------- */
.enr-form-errors {
  background: var(--enroute-rose-50);
  color: var(--enroute-rose-700);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  box-shadow: inset 0 0 0 1px var(--enroute-rose-200);
  font-size: 13px;
  margin-bottom: 16px;
}
.enr-form-errors__title {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 700;
}
.enr-form-errors__list {
  margin: 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.enr-form-errors__item { font-size: 13px; }
.enr-form-errors__link,
.enr-form-errors__text { color: inherit; }
.enr-form-errors__link { text-decoration: underline; text-underline-offset: 2px; }
.enr-form-errors__link:hover { text-decoration-thickness: 2px; }
.enr-form-errors__link:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 3px; }

/* ---------------------------------------------------------------------
   Formset — .enr-formset* (contract §A "Formset guarantees")
   --------------------------------------------------------------------- */
.enr-formset { display: flex; flex-direction: column; gap: 14px; }
.enr-formset__rows { display: flex; flex-direction: column; gap: 14px; }
/* A bare `<fieldset>` inherits browser chrome (a min-width auto flex/grid
   item quirk, plus default border/padding/margin) that no `.enr-formset__row`
   consumer has asked for — reset it to a plain block, then let the row's own
   body (the caller's `{% ui_form_fields %}`/`.form-row` content) and the
   trailing Remove control lay out. */
.enr-formset__row {
  min-width: 0;
  border: 0;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* `<template>` content is inert by HTML spec — this rule exists so the
   class reads as real CSS backing (`test_template_css_backing.py`), and as
   a defensive belt-and-braces guard rather than relying on spec inertness
   alone. */
.enr-formset__template { display: none; }
.enr-formset__add { align-self: flex-start; }
/* The primitive's own Remove control default position: trailing, within
   whatever flow the caller's row body establishes. A caller with a grid/flex
   row body (e.g. place order's `.pl-drop`/`.drop-row`, D6) re-targets this
   in its own page sheet — see `pages/loads-placement.css`. */
.enr-formset__remove { align-self: flex-end; }

/* ---------------------------------------------------------------------
   Form actions alignment modifiers — the base `.form-card__actions`
   (flex, gap, `justify-content: flex-end`) stays in shell.css; `end` is
   that bare rendering, so it gets no modifier class here.
   --------------------------------------------------------------------- */
.form-card__actions--start { justify-content: flex-start; }
.form-card__actions--split { justify-content: space-between; }
.form-card__actions--stack { flex-direction: column; align-items: stretch; }

/* ---------------------------------------------------------------------
   .imp-file(+--error) — moved verbatim from pages/import-orders.css
   (frontend-forms SP2; the single backing field is a real
   <input type="file">, restyled to match the V05 form vocabulary).
   --------------------------------------------------------------------- */
.imp-file {
  display: block;
  width: 100%;
  font: inherit;
  font-size: 14px;
  color: var(--fg-1);
  padding: 9px 12px;
  border: 1px solid var(--border-2);
  border-radius: var(--radius-md);
  background: var(--bg-paper);
  min-height: 44px;
  cursor: pointer;
}
.imp-file::file-selector-button {
  margin-right: 12px;
  padding: 7px 14px;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--brand-soft);
  color: var(--enroute-green-800);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.imp-file:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: var(--focus-ring);
}
.imp-file--error { border-color: var(--enroute-rose-400); }

/* ---------------------------------------------------------------------
   .seg / .seg__opt — moved verbatim from pages/loads-placement.css
   (lines 9-147 there before this move; frontend-forms SP2).
   frontend-forms M-A3 (2026-09-17): both consumers of `seg-thumb.js`
   (`loads/load_place.html`, `load_add_delivery.html`) now render through
   `{% ui_segmented_field %}` and are measured by `enr.segmented` (SP7) off
   its own `[data-enr-segmented-thumb]` marker — the `data-seg="thumb"`
   selector half `seg-thumb.js` used to stamp is retired with the script.
   --------------------------------------------------------------------- */
/* Report 9 (2026-08-31, JJ) — recorded under "Post-lock rulings (2026-08-31, JJ)"
   in docs/components/fuel-terms-book/04-build-log.md: "a selection slider like
   how we select party type in the price list adder — pills, and the pill moves
   to the active selection."
   The look is the price book's `.plr-seg` (ink-100 track, paper pill on the
   chosen one); the movement is new — `.plr-seg` has none, so what JJ is
   describing is built here for the first time.

   THE PILL IS A `::before` ON THE TRACK, NOT A BACKGROUND ON THE OPTION. One
   element can be transitioned between positions; a background handed from one
   option to the next cannot. It is sized `100% / var(--seg-n)` and slid by
   `var(--seg-i) * 100%` — which is only true while every option is the same
   width and there is no gap between them, hence `flex: 1 1 0` and `gap: 0` in
   the measured state. `enr.segmented` (SP7) owns both properties and stamps
   `data-enr-segmented-thumb="live"`; WITHOUT it no `::before` is generated at
   all and the control falls back to the static paper pill below, which is
   exactly what it looked like before this change.

   Platform review A1 (kept): with 6 products the control used to overlap the
   volume input and overflow a 375px viewport. Unmeasured, and on phones, the
   options still WRAP onto extra rows — a wrapped row is the one geometry a
   single sliding pill cannot describe, so the pill stands down there rather
   than pointing at the wrong option. */
.seg {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 3px;
  background: var(--enroute-ink-100);
  border-radius: var(--radius-pill);
  width: 100%;
}

/* Measured by enr.segmented (`data-enr-segmented-thumb="live"`, frontend-forms
   D5) → one un-gapped row of equal options, which is what the pill's
   arithmetic assumes. */
.seg[data-enr-segmented-thumb="live"] {
  flex-wrap: nowrap;
  gap: 0;
}

.seg__opt {
  position: relative;
  z-index: calc(var(--z-base) + 1);
  flex: 1 1 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  /* 3px of track padding + 38px + 3px = the 44px every `.fld` control is held to
     (`shell.css`, ADR 0005). At 36px the track computed 42px and sat 2px
     above the volume input beside it — measured at 1366x900, `.seg` top 1608.6
     h42.0 against the input's 1606.6 h44.0, bottoms agreeing exactly under
     `.drop-row__pick { align-items: flex-end }` (JJ, 2026-08-31). The moving
     pill's `::before` is derived from the track's padding box, so a taller
     option is neutral to it. */
  min-height: 38px;
  padding: 7px 8px;
  border-radius: var(--radius-pill);
  font-size: 12.5px;
  font-weight: 600;
  text-align: center;
  color: var(--fg-2);
  background: transparent;
  cursor: pointer;
  user-select: none;
  transition: background var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

/* The real radio sits inside the label but is visually hidden — the label is the
   button. Keep it in the layout for hit-testing + keyboard focus. */
.seg__opt input[type="radio"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

/* Selected option → paper pill. This is the NO-SCRIPT and wrapped-row state; it
   is also what renders while the page is still parsing. */
.seg__opt:has(input:checked) {
  background: var(--bg-paper);
  color: var(--fg-1);
  box-shadow: var(--shadow-sm);
}

/* ---- The moving pill ----
   Generated only for a measured group that HAS a selection: an untouched
   product line shows a bare track, exactly as it did before. */
.seg[data-enr-segmented-thumb="live"]:has(.seg__opt input:checked)::before {
  content: "";
  position: absolute;
  z-index: var(--z-base);
  top: 3px;
  bottom: 3px;
  left: 3px;
  /* The containing block is the track's PADDING box, so subtract both 3px
     paddings to get the row the options share. */
  width: calc((100% - 6px) / var(--seg-n, 1));
  transform: translateX(calc(var(--seg-i, 0) * 100%));
  background: var(--bg-paper);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-base) var(--ease-out);
  pointer-events: none;
}

/* With the pill drawn, the option underneath must not paint a second one. */
.seg[data-enr-segmented-thumb="live"] .seg__opt:has(input:checked) {
  background: transparent;
  box-shadow: none;
}

/* a11y-code-08: tokens.css carries the global reduced-motion kill switch; this
   states it locally too, because a pill that jumps is the intended behaviour
   here rather than a side effect worth inheriting silently. */
@media (prefers-reduced-motion: reduce) {
  .seg[data-enr-segmented-thumb="live"]:has(.seg__opt input:checked)::before {
    transition: none;
  }
}

/* Keyboard focus → brand-green ring on the option (the input is hidden). Last,
   so it survives the pill rule above clearing the checked option's shadow. */
.seg__opt:has(input:focus-visible) {
  box-shadow: var(--focus-ring);
}

.seg__opt:hover:not(:has(input:checked)) {
  color: var(--fg-1);
}

/* `.seg__opt`'s own `[hidden]` guard — moved out of
   `pages/loads-placement.css`'s combined `.fld[hidden], .btn[hidden],
   .seg__opt[hidden]` rule (that file keeps its own two selectors; `.seg__opt`
   is this family's, so it moves here with the rest of it). No `!important`
   needed: `[hidden]` is an attribute selector, so `.seg__opt[hidden]` at
   specificity (0,1,1) already outranks the bare `.seg__opt { display:
   inline-flex }` at (0,1,0) — the same technique the rule it was split from
   used, cascade origin aside. */
.seg__opt[hidden] { display: none; }

/* ---- Segmented control — phone (moved verbatim from
   pages/loads-placement.css's `@media (max-width: 640px)` block,
   frontend-forms SP2; the page's own `.drop-row`/`.pl-seg` rules in that
   same media block stay where they are). ---- */
/* ADR 0005's floor, gated on the INPUT DEVICE (ADR 0079): the seg option LABEL is
   the tap surface (its radio is visually hidden) and measured 38px, under the floor,
   on every coarse-pointer device wider than 640px — a phone in landscape, a tablet,
   a touch convertible. The width arm is kept beside the pointer arm so a narrow
   mouse window is unaffected. A pointer-gated floor only; `.seg__opt`'s phone FLEX
   basis stays width-gated below, because a 45% basis at 1440 would wreck the
   desktop track. Desktop-with-a-mouse keeps its compact 38px, which makes the track
   exactly as tall as the input beside it. */
@media (max-width: 640px), (hover: none) and (pointer: coarse) {
  .seg__opt { min-height: 44px; }
}

@media (max-width: 640px) {
  /* Two per line, ~144px each: at a 45% basis a third cannot fit beside them, so
     every label keeps ONE line. Left to `flex: 1 1 0` the options pack by
     min-content and six products land five-and-one, which reads as a mistake. */
  .seg__opt {
    flex: 1 1 45%;
  }
  /* Six products across a 292px track is 48px an option, and every label would
     take two lines to say "Diesel 50ppm". Phones wrap the options instead — and
     a wrapped row is the one geometry a single sliding pill cannot describe, so
     it stands down there and the chosen option paints its own paper pill. */
  .seg[data-enr-segmented-thumb="live"] {
    flex-wrap: wrap;
    gap: 4px;
  }
  /* ...and a wrapped track cannot be a lozenge. `--radius-pill` clamps to half
     the box, so the 98px two-row track that four graded products make at 390px
     was drawn with a 49px corner arc cutting diagonally across the first and
     last option rows, and the chosen paper pill painted outside the grey.
     Bare `.seg`, NOT `[data-enr-segmented-thumb]`: with no script that marker
     is never stamped and the base `flex-wrap: wrap` still applies. The
     desktop track is one row under `nowrap`, where the stadium above is
     correct and stays. */
  .seg { border-radius: var(--radius-lg); }
  .seg[data-enr-segmented-thumb="live"]:has(.seg__opt input:checked)::before { content: none; }
  .seg[data-enr-segmented-thumb="live"] .seg__opt:has(input:checked) {
    background: var(--bg-paper);
    box-shadow: var(--shadow-sm);
  }
}

/* ---------------------------------------------------------------------
   Date-range host — the class-less wrapper `enr.date.enhance` (SP6)
   presents as one cell; until enhanced (`[data-enr-date-picker]` absent)
   it must not affect the JS-off grid layout at all (D11/D15).
   --------------------------------------------------------------------- */
[data-enr-date-mode="range"]:not([data-enr-date-picker]) { display: contents; }

/* Enhanced: the host stops being `display: contents` and becomes the field
   box itself, so it owns the label-over-control stack every other field has.
   Its children are, in DOM order, the generated picker (date.js inserts it as
   `firstChild`), then the start member's wrapper, then the end member's. Both
   natives are `[hidden]` by then, so each wrapper renders as nothing but its
   `<label>` — one duplicate heading under an unlabelled input, which is what
   the un-ordered stack looked like. So: the start wrapper's label is ordered
   ABOVE the picker, and the end wrapper is dropped (the picker carries the
   pair's accessible name via `data-enr-date-label`/`aria-label`, so nothing
   is left unnamed). Ordering, not reparenting — date.js owns the DOM. */
[data-enr-date-picker][data-enr-date-mode="range"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
[data-enr-date-picker][data-enr-date-mode="range"] > :first-child { order: 2; }
[data-enr-date-picker][data-enr-date-mode="range"] > :nth-child(2) { order: 1; }
[data-enr-date-picker][data-enr-date-mode="range"] > :nth-child(n + 3) { display: none; }
