/* Stage-form vocabulary — Shell-owned, split out of shared.css (Sprint 9.5 Story 22,
   architecture/SHARED-CSS-LAYER-SPLIT.md). Required-field marker, stage-form buttons/refusal message,
   and the stage-form layout vocabulary — moved here as ONE contiguous block, order unchanged, so
   .form-btn-primary still precedes .form-btn-danger (SharedCssDeclarationOrderTests). Linked once in
   App.razor's <head>, reaching every Blick's DOM the same way shared.css already did. */

/* ── Required-field marker (.form-required) ──────────────────────────────────────────────────────────────
   The red asterisk that follows a required field's label, e.g. <label>Quantity <span class="form-required">*</span></label>.
   Reused rather than newly coined: CCP.WorkManagementContext.Blick's S4 stage forms (CompleteProduction,
   PrepareJob, QualityControl, ShipOrder) already render this exact class on ~20 labels but never shipped a CSS
   rule for it (plain unstyled black text) or a "Fields marked * are required" legend — a half-built version of
   the same convention. Adopting the existing name and finishing it here, ONE rule, Shell-owned, so it reaches
   every Blick's DOM the same way .app-tabstrip above does — instead of a second, differently-named class
   competing with it in the same markup. */
.form-required {
    color: var(--brand-danger);
}

/* Never start a comment line with a .form-btn-* class name (it reads as a rule); each form-btn rule declares every property it keeps on :disabled. */
/* ── Stage-form buttons (.form-btn-primary / .form-btn-secondary) ───────────────────────────────────────────
   Used 53 times across CCP.WorkManagementContext.Blick's five stage-transition pages (Hold/Resume/Reassign/
   ConfirmDelivery/StartProduction Confirm) with zero matching CSS anywhere in the solution (Will's UX review,
   F1, 2026-08-14) — every button rendered as an unstyled browser default, including Confirm Delivery, an
   irreversible action. DESIGN-SYSTEM.md §4.32: the same visual object as the buttons WorkOrderDetails.razor renders (btn btn-primary /
   btn-outline-secondary; the Blick's own .wo-btn-* classes are gone) — mirrored here rather than reinvented, using only existing
   --brand-* tokens, so a primary/secondary button reads identically wherever it appears in this app. */
.form-btn-secondary,
.form-btn-primary {
    border-radius: var(--brand-radius-md);
    padding: var(--brand-space-2) var(--brand-space-3);
    font-size: var(--brand-font-size-sm);
    font-weight: var(--brand-font-weight-medium);
    cursor: pointer;
}

.form-btn-secondary {
    background: var(--brand-surface);
    color: var(--brand-text);
    border: 1px solid var(--brand-border-strong);
}

.form-btn-secondary:hover {
    background: var(--brand-neutral-bg);
}

/* Same solid-fill treatment as .btn-primary (theme.css): Primary-700 fill, Primary-800 hover
   (DESIGN-SYSTEM.md §4.1 groups .btn-primary/.form-btn-primary as the same "Solid" variant).
   2026-09-02, Will's measurement: hover and active computed to the identical #004670 fill (byte-identical
   screenshots) — a click gave no visual feedback — and focus-visible fell through to Chromium's default
   outline (box-shadow: none). :active now steps one further on the same Primary ramp (Primary-850,
   --brand-secondary, #002C56 — DESIGN-SYSTEM.md's own deep-navy end of the ramp, not an invented colour);
   :focus-visible gets the matching ring recipe .btn-primary already uses (theme.css). */
.form-btn-primary {
    background: var(--brand-primary-hover);
    color: var(--brand-surface);
    border: 1px solid var(--brand-primary-hover);
    transition: background var(--brand-transition-fast), border-color var(--brand-transition-fast), box-shadow var(--brand-transition-fast);
}

.form-btn-primary:hover {
    background: var(--brand-primary-active);
    border-color: var(--brand-primary-active);
}

.form-btn-primary:focus-visible {
    background: var(--brand-primary-active);
    border-color: var(--brand-primary-active);
    box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--brand-primary) 50%, transparent);
}

.form-btn-primary:active {
    background: var(--brand-secondary);
    border-color: var(--brand-secondary);
}

/* Approvals card #44 (Brian ruled 2026-09-21, Option A): mirrors .btn-primary's disabled treatment
   (theme.css) — a disabled Submit rendered identically to an enabled one (seen on Ship Order; affects
   all five Work Management stage forms plus every Finance/Inventory dialog using these classes).
   The label is --brand-primary-hover on the tint, measured 5.09:1; a white label on the same fill
   measures 1.37:1 and is effectively invisible (DESIGN-SYSTEM.md §4.1).
   The danger button's own disabled rule (further down this file) was ADDED 2026-09-23 (Carrie's gate find,
   F1 loop 2) — "no disabled rule for the danger button, the design sheet documents no disabled state for
   it" was card #44's original position and
   is SUPERSEDED by Brian's 2026-09-22 btn-token ruling: once every form-btn-* button also carries
   Bootstrap's own "btn" class, an unstyled :disabled selector is no longer "inherits the enabled look" (the
   gap card #44 accepted) — it is "loses everything to Bootstrap's bare .btn:disabled" (no fill, inherited
   text colour, 65% opacity), the identical F1 defect .form-btn-secondary just had, on the one variant
   nobody had checked yet. Same tint-fill shape as primary, same --brand-danger-bg/--brand-danger-text pair
   .app-table__urgency already uses for a soft-danger fill (theme.css) — not an invented colour.
   ⛔ Do not start a comment line with a .form-btn-* class name: SharedCssDeclarationOrderTests reads a
   line-leading class name as a rule declaration, so a comment can flip its ordering check.
   Brian ruled 2026-09-22 that every form-btn-* button also carries Bootstrap's own "btn" class
   (class="btn form-btn-primary"). CORRECTED 2026-09-23 (Arthur's gate find, F2): "this file loads after
   bootstrap so source order wins" is only true PROPERTY BY PROPERTY, and only when the two rules are
   actually competing at EQUAL specificity — a :disabled selector against another :disabled selector,
   both one class + one pseudo-class, (0,2,0) each. It is NOT a blanket win for every property a
   form-btn-*:disabled rule leaves unset: an unset property falls through to whatever ELSE declares it,
   and the enabled .form-btn-secondary rule above is a bare class at (0,1,0) — lower specificity than
   Bootstrap's (0,2,0) .btn:disabled, so Bootstrap wins THAT property regardless of source order. This is
   exactly how .form-btn-secondary:disabled broke (F1): it declared only `color`, so background/border/
   opacity fell through to the lower-specificity enabled rule and lost to Bootstrap. The rule this
   stylesheet follows from now on: a form-btn-*:disabled selector must declare EVERY property it wants to
   keep — background, border-color and opacity at minimum — never lean on source order to inherit them
   from the enabled rule one specificity tier down.
   pointer-events (F3, 2026-09-23): Bootstrap's .btn:disabled also sets `pointer-events: none`, which
   suppresses the `cursor: not-allowed` card #44 ruled below — a pointer-events:none element never shows a
   custom cursor no matter what `cursor` says. Restored with `pointer-events: auto` on both rules below;
   this does NOT make a disabled button clickable again — the native `disabled` attribute already blocks
   pointer and keyboard activation on its own, pointer-events is only what decides whether a *cursor*
   renders on hover. Chosen over documenting the cursor as superseded because card #44 called the cursor
   part of the ruled recipe ("the non-visual half of the same signal" — SharedCssDisabledButtonStateTests),
   and restoring it costs nothing behaviourally. */
.form-btn-primary:disabled {
    background: var(--brand-primary-light);
    border-color: transparent;
    color: var(--brand-primary-hover);
    opacity: 1;
    cursor: not-allowed;
    pointer-events: auto;
}

.form-btn-secondary:disabled {
    background: var(--brand-surface);
    border-color: var(--brand-border-strong);
    color: var(--brand-text-subtle);
    opacity: 1;
    cursor: not-allowed;
    pointer-events: auto;
}

/* ── Stage-form refusal message (.form-error) ────────────────────────────────────────────────────────────
   Same F1 gap: WorkOrderStageFormSubmitError.MessageFor's domain-refusal sentence — the one seven red tests
   were spent getting right — rendered as bare unstyled text, less visible than the same page's Bootstrap
   `alert alert-danger`/`alert-warning` banners. Styled to read at the same weight as those banners, using only
   --brand-danger* tokens (no new colour). */
.form-error {
    background: var(--brand-danger-bg);
    color: var(--brand-danger-text);
    border: 1px solid var(--brand-danger);
    border-radius: var(--brand-radius-md);
    padding: var(--brand-space-3) var(--brand-space-4);
    margin-bottom: var(--brand-space-4);
    font-weight: var(--brand-font-weight-medium);
}

/* ── Stage-form layout vocabulary (Arthur's 2026-08-14 sweep, §2-SEVERE) ────────────────────────────────────
   Will's F1 fix above covered form-btn-primary/-secondary/form-error — three of ~15 classes carried by the same
   nine WorkManagement action screens (PrepareJob, StartProductionConfirm, CompleteProduction, QualityControl,
   ShipOrder, HoldConfirm, ResumeConfirm, ReassignConfirm, ConfirmDeliveryConfirm). The remaining layout classes
   below — the page container, the field grid, the button bar, hint/summary/confirm text, the QA radio row, and
   the destructive fail/rework button — had zero matching CSS, so every one of these forms collapsed to
   unstyled, unaligned browser defaults. CSS-only: no markup changed, every class name was already correct.
   Deliberately LAYOUT/SPACING ONLY — no bare element selectors (input/select/textarea) added here: several
   fields nest Bootstrap-classed or EstimatorPicker-rendered controls (.form-select/.form-control), and an
   element selector in this file would out-specificity those class selectors as it loads after bootstrap.min.css
   in App.razor's head — safer to leave native-input chrome as its own, separate gap than risk an unverified
   visual regression on an already-styled control.
   .form-page__title's size/weight rule was retired 2026-09-02 (Brian: confirm forms converge on the app-wide
   <h1>). The class name stays in the eleven Pages/Actions/*.razor files as a harmless hook. */
.form-page {
    max-width: 640px;
}

.form-page__subtitle {
    color: var(--brand-text-muted);
    font-size: var(--brand-font-size-base);
    margin: 0 0 var(--brand-space-4);
}

.form-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--brand-space-4);
}

.form-field {
    display: flex;
    flex-direction: column;
    gap: var(--brand-space-1);
    margin-bottom: var(--brand-space-3);
}

.form-field label {
    font-weight: var(--brand-font-weight-medium);
    color: var(--brand-text);
}

/* Will's visual pass (fix round 1, ProcurementRequestForQuoteCreate.razor's Current Stock field): a bare <p>
   showing a read-only value carries the browser's own paragraph margin on top of .form-field's flex gap, which
   stacked to roughly 28px more spacing than every other field on the form. Zeroing it here (rather than only on
   that one page) keeps the fix reusable for the next static-value display a form adds. */
.form-field__static-value {
    margin: 0;
}

/* WF-4 (Service RFQ editor gate, 2026-09-17): a fieldset legend grouping several form-fields (e.g. the
   Specifications group) otherwise renders at the browser/Bootstrap default -- larger than the labels around
   it, at normal weight, a different type family from the rest of the page. Same treatment as
   CCP.QuoteContext.Blick's own .qw-address-group legend (that Blick's blick.css), reproduced here as a
   Shell-owned shared rule since a Blick-owned selector never reaches a Shell page. */
.form-field legend {
    font-size: inherit;
    font-weight: var(--brand-font-weight-semibold);
    color: var(--brand-text);
    padding: 0;
    margin-bottom: var(--brand-space-1);
}

.form-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--brand-space-2);
    margin-top: var(--brand-space-4);
}

.form-actions--between { justify-content: space-between; }

.form-actions--start { justify-content: flex-start; }

.form-actions--compact { margin-top: var(--brand-space-2); }

.option-subline {
    color: var(--brand-text-muted);
    font-size: var(--brand-font-size-sm);
}

/* Every blocked-submit line renders with this class, never on alert-warning; sweep by class, not by member name. */
.form-hint {
    color: var(--brand-text-muted);
    font-size: var(--brand-font-size-base);
    margin-bottom: var(--brand-space-3);
}

/* QuickBooks Tester fix round (Will/Arthur, 2026-09-22): #qbt-blocked's own .form-hint margin-bottom already
   ties it to the action row beneath -- the defect was the TOP, flush against the field list above it with no
   margin-top set anywhere, so it read as a sixth app-field-list--inline row rather than the button's own
   reason. A small top margin only; plain .form-hint (the other twenty-two §4.27 Case B sites) is untouched. */
#qbt-blocked {
    margin-top: var(--brand-space-4);
}

.form-confirm {
    font-size: var(--brand-font-size-md);
    margin-bottom: var(--brand-space-4);
}

/* .form-summary is a pure list reset, meant to co-ride with whichever class supplies the box/colour half —
   class="form-error form-summary" on a validation-error list, and (card #30 fix round 2, 2026-09-21)
   class="form-hint form-summary" on ShipOrder.razor's blocked-submit list, since .form-hint sets only colour,
   font size and margin and is element-agnostic. Its former sibling .form-summary-list (ShipOrder's D-0129
   landed-shipments recap) converged onto .app-field-list--inline below (DESIGN-SYSTEM-DETAIL-SCREENS.md §3a)
   — deleted here, not aliased. */
.form-summary ul {
    margin: 0;
    padding-left: var(--brand-space-5);
}

/* Will's visual FAIL, card #30 fix round 3 (measured against ship-order-blocked-1920.png): plain .form-hint's
   own margin-bottom (--brand-space-3) collapses with .form-actions' margin-top (--brand-space-4) below it, and
   with nothing pulling the top away from the field above, the block sits roughly equidistant from both
   neighbours instead of reading as attached to the action row beneath it. .form-hint.form-summary widens the
   gap above (collapsing against the preceding field's own margin) and removes its own bottom margin so the
   gap below is set by .form-actions alone -- the same roughly-2:1 tighter-underneath rhythm
   create-quote-blocked-1920.png already has. Only the co-riding pair changes; plain .form-hint (the other
   twenty-one sites) is untouched. */
.form-hint.form-summary {
    margin-top: var(--brand-space-8);
    margin-bottom: 0;
}

/* Neutral emphasis for a blocked-submit LIST (the repeating-structure exception, DESIGN-SYSTEM.md §4.18e): a
   bordered panel on the page-background tint, text colour untouched. Stays in the "nothing has failed" channel
   (no danger/warning colour) while lifting the list out of the surrounding help text. Co-rides with
   .form-hint.form-summary, which supplies the colour, list reset and outer margins. */
.form-summary-panel {
    background: var(--brand-surface-page-bg);
    border: 1px solid var(--brand-border-strong);
    border-radius: var(--brand-radius-md);
    padding: var(--brand-space-3) var(--brand-space-4);
}

.form-radio-group {
    display: flex;
    gap: var(--brand-space-4);
    align-items: center;
}

/* QualityControl's destructive fail/rework action — form-btn-danger is named danger by the markup author
   (QualityControl.razor), so styling it from --brand-danger* tokens honours intent already present rather than
   inventing a new one. Mirrors .form-btn-primary's shape exactly, red instead of blue. Which SCREENS should use
   a danger/destructive treatment (e.g. Confirm Delivery) is Brian's open call — not decided here. */
.form-btn-danger {
    border-radius: var(--brand-radius-md);
    padding: var(--brand-space-2) var(--brand-space-3);
    font-size: var(--brand-font-size-sm);
    font-weight: var(--brand-font-weight-medium);
    cursor: pointer;
    background: var(--brand-danger);
    color: var(--brand-surface);
    border: 1px solid var(--brand-danger);
}

.form-btn-danger:hover {
    background: var(--brand-danger-text);
    border-color: var(--brand-danger-text);
}

/* Full rationale for WHY every property below is declared explicitly (never left to source order) lives on
   the primary button's own disabled-rule comment near the top of this file (F1/F2, 2026-09-23) — same
   tint-fill shape, --brand-danger-bg/--brand-danger-text instead of the primary ramp, same reason
   .app-table__urgency (theme.css) already pairs them for a soft-danger fill. */
.form-btn-danger:disabled {
    background: var(--brand-danger-bg);
    border-color: transparent;
    color: var(--brand-danger-text);
    opacity: 1;
    cursor: not-allowed;
    pointer-events: auto;
}


/* ── File-upload dropzone + attachment chip (.app-dropzone*, .app-attachment-chip*) ─────────────────────────
   DESIGN-SYSTEM.md §4.14 (wave 2, F4): CCP.UI.Components/FileDropzone.razor + AttachmentChip.razor ship no
   CSS of their own — this is the host obligation, same split as every other CCP.UI.Components class. */
.app-dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--brand-space-2);
    padding: var(--brand-space-5);
    background: var(--brand-surface);
    border: 1px dashed var(--brand-border-strong);
    border-radius: var(--brand-radius-lg);
    transition: border-color var(--brand-transition-fast), background-color var(--brand-transition-fast);
}

.app-dropzone--drag-over {
    border-color: var(--brand-primary);
    background: var(--brand-primary-lighter);
}

.app-dropzone--drag-over .app-dropzone__icon {
    color: var(--brand-primary);
}

.app-dropzone--error {
    border-color: var(--brand-danger);
    border-style: solid;
}

.app-dropzone__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--brand-radius-md);
    background: var(--brand-primary-lighter);
    color: var(--brand-primary);
    font-size: var(--brand-font-size-lg);
}

.app-dropzone__title {
    margin: 0;
    color: var(--brand-text);
    font-weight: var(--brand-font-weight-medium);
}

/* DESIGN-SYSTEM.md §4.38 / WCAG 2.1 AA (Francie, 2026-09-18): --brand-text-subtle (#7D8A92) measures 3.54:1 against the
   dropzone's white/surface background -- well under the 4.5:1 floor (axe color-contrast, serious). This is a
   shared component (CCP.UI.Components/FileDropzone.razor) reachable from the customer/vendor portals, so it
   is built to the portal bar (DESIGN-SYSTEM.md §4.38). --brand-text-muted (#667178) is the next step down and passes (5.1:1
   against white). */
.app-dropzone__hint {
    margin: 0;
    color: var(--brand-text-muted);
    font-size: var(--brand-font-size-sm);
}

/* The "Choose file" trigger is a real <label for> wrapping the hidden <input> (§2.8 item 8: a labelled button
   is the path that always works, the drag surface is a convenience on top of it) -- .btn/.btn-outline-primary/
   .btn-sm already carry its visual weight; this rule is the spacing hook between it and the title/hint text
   above and below it. */
.app-dropzone__choose {
    margin-top: var(--brand-space-1);
}

/* The real focus target is the visually-hidden input, so its keyboard focus is painted on the label next to it
   with the same ring recipe .form-btn-primary uses. */
.app-dropzone input[type=file]:focus-visible + .app-dropzone__choose {
    box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--brand-primary) 50%, transparent);
}

.app-dropzone__choose--disabled {
    opacity: 0.65;
    cursor: not-allowed;
    pointer-events: none;
}

.app-dropzone__error {
    margin: 0;
}

.app-attachment-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--brand-space-2);
    padding: var(--brand-space-2) var(--brand-space-3);
    background: var(--brand-neutral-bg);
    border-radius: var(--brand-radius-md);
    transition: box-shadow var(--brand-transition-fast);
}

.app-attachment-chip:hover {
    box-shadow: var(--brand-shadow-sm);
}

.app-attachment-chip__icon {
    color: var(--brand-text-muted);
}

.app-attachment-chip__name {
    color: var(--brand-text);
    font-size: var(--brand-font-size-sm);
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-attachment-chip__size {
    color: var(--brand-text-muted);
    font-size: var(--brand-font-size-xs);
    flex-shrink: 0;
}

.app-attachment-chip__action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border: none;
    border-radius: var(--brand-radius-sm);
    background: transparent;
    color: var(--brand-primary);
    flex-shrink: 0;
}

.app-attachment-chip__action:hover {
    background: var(--brand-surface);
}

/* The Address Book row's inline address-type picker (Address Book, AB.2 row 4) -- a narrow select beside a
   full-width card, capped so it reads as a control on the row rather than a form field spanning the card.
   Lives here rather than inline on the element (L-233). */
.form-field--inline-select {
    max-width: 260px;
}
