/* ============================================================
   AR UI Framework — Module Form
   ------------------------------------------------------------
   Framework-wide entry/edit form shell: header, step rail,
   sections, field grid, toggles, footer. Rendered by
   public/shared/components/module-form.php (app_module_form())
   and driven by public/assets/js/components/module-form.js.

   Why this file exists
   --------------------
   Before it, entry forms were written three incompatible ways:
     1. .app-field/.app-label/.app-input  (components/forms.css)
     2. .form-field/.form-label/.form-control (framework showcase,
        never actually defined in CSS — the markup rendered unstyled)
     3. .form-group/.form-row/.form-select/.form-textarea
        (then components/collections-modals.css) — global, unprefixed
        names owned by a module-named file and reused by the
        clients-portal/collections/commission/contacts/financial modals.
   This layer is the single organized system all three converge on.
   Spelling (3) is now gone: once every one of those modals had moved
   onto this component the rules had nothing left rendering against
   them, and they were removed on 2026-09-14 with the file's rename to
   components/catrion-modal-shell.css, which kept only the .modal shell
   its one remaining consumer used. That consumer — the Catrion
   dashboard's Create PO / Receive Goods / Record Invoice modals, whose
   five endpoints all 404ed — was deleted on 2026-10-07 along with the
   stylesheet, when the module became Clients Portal. Nothing renders
   that shell any more.

   Framework rules this file follows
   ---------------------------------
   * No new palette. The source mockup shipped a parallel --sap-*
     token family duplicating values already in core/tokens.css.
     Duplicating the palette is how two blues drift apart, so every
     colour here resolves to an existing token in core/tokens.css
     (the --tbl- and --app- families).
   * Sizing rides --ui-* so the form honours the 100/90/80 UI-scale
     system in core/ui-scale.css. Fixed rems would not scale.
   * Buttons are NOT redefined. The footer uses the shared .btn
     family from components/buttons.css.
   * Every class is BEM-prefixed .app-module-form__*. The mockup's
     bare .form-row/.form-group/.btn would have collided head-on
     with the unprefixed selectors that file owned at the time.
   * RTL comes from logical properties (inline-start/end), matching
     the [dir] attribute set on <html> in shared/layouts/app.php.
   * Light-only, no prefers-color-scheme block. head.php declares
     <meta name="color-scheme" content="light"> app-wide; a dark
     block here would flip this component alone on a dark-OS
     machine while the page around it stayed light.

   Rollback: remove the @import from assets/css/app.css. Nothing
   else in the app references .app-module-form__*.
   ============================================================ */

/* The token block applies to a standalone __section too, not just a whole form.
   A page that already owns its <form> -- the contract wizard owns one, and HTML
   forbids nesting another inside it -- renders sections on their own through
   app_module_form_section(). Without this those sections would resolve every
   colour to its literal fallback and drift from the rest of the system. */
.app-module-form,
.app-module-form__section {
    /* Component-scoped aliases. Override these on a wrapper to
       re-skin one form without touching core/tokens.css. */
    --mf-surface: var(--tbl-surface, #fff);
    --mf-surface-muted: var(--tbl-control-bg, #f0f2f5);
    --mf-border: var(--tbl-border, #bcc3cd);
    --mf-border-subtle: var(--tbl-row-line, #d8dde4);
    --mf-text: var(--tbl-text, #1a2026);
    --mf-text-secondary: var(--tbl-text-secondary, #3d4a5a);
    --mf-text-muted: var(--tbl-text-muted, #6b7a8a);
    --mf-brand: var(--tbl-brand, #005c9e);
    --mf-brand-hover: var(--tbl-brand-hover, #004b82);
    --mf-brand-light: var(--tbl-brand-light, #e5f0fa);
    --mf-head-bg: var(--tbl-head-bg, #005c9e);
    --mf-head-text: var(--tbl-head-text, #fff);
    --mf-head-rule: var(--tbl-head-rule, #003f6e);
    --mf-success: var(--tbl-success, #107c41);
    --mf-danger: var(--tbl-danger, #b1302a);
    --mf-radius: var(--tbl-radius, 4px);
    --mf-radius-sm: var(--tbl-radius-sm, 2px);
    --mf-transition: .15s ease;

}

.app-module-form {
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: var(--mf-surface);
    border: 1px solid var(--mf-border);
    border-radius: var(--mf-radius);
    box-shadow: var(--shadow-xs, 0 1px 3px rgba(0, 0, 0, .05));
    color: var(--mf-text);
    font-size: var(--ui-font-size, 14px);
    line-height: var(--ui-line-height, 1.45);
    overflow: hidden;
}

/* Standalone page form: full width of its container. It used to cap at 60rem
   and centre, which on a wide monitor left the fields stacked in a narrow
   column with the page scrolling past them. Requirement is the opposite --
   use the width that is there, so the form stays short enough not to scroll. */
.app-module-form--page {
    width: 100%;
    max-width: none;
}

/* Inside app_modal()/app_drawer(): the host already draws the
   surface, border and radius. Drawing them twice produces the
   double-frame that made earlier embedded forms look boxed-in. */
.app-module-form--embedded {
    border: 0;
    border-radius: 0;
    box-shadow: none;
    background: transparent;
    height: 100%;
}

/* ---- Header ---- */
.app-module-form__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ui-space-md, 12px);
    flex-shrink: 0;
    padding: var(--ui-space-sm, 8px) var(--ui-space-lg, 16px);
    background: var(--mf-head-bg);
    border-bottom: 2px solid var(--mf-head-rule);
}

.app-module-form__title-group {
    display: flex;
    align-items: center;
    gap: var(--ui-space-sm, 8px);
    min-width: 0;
}

.app-module-form__icon {
    flex-shrink: 0;
    font-size: var(--ui-icon-size, 16px);
    line-height: 1;
    color: var(--mf-head-text);
}

.app-module-form__title {
    margin: 0;
    font-size: var(--ui-font-size, 14px);
    font-weight: 700;
    color: var(--mf-head-text);
    letter-spacing: .01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.app-module-form__badge {
    flex-shrink: 0;
    padding: 1px var(--ui-space-sm, 8px);
    border-radius: 100px;
    background: rgba(255, 255, 255, .14);
    color: rgba(255, 255, 255, .82);
    font-size: var(--ui-small-font-size, 12px);
    font-weight: 600;
    white-space: nowrap;
}

.app-module-form__header-actions {
    display: flex;
    align-items: center;
    gap: var(--ui-space-xs, 6px);
    flex-shrink: 0;
}

.app-module-form__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--ui-control-height-sm, 28px);
    height: var(--ui-control-height-sm, 28px);
    padding: 0;
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: var(--mf-radius-sm);
    background: rgba(255, 255, 255, .08);
    color: var(--mf-head-text);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    transition: background var(--mf-transition), border-color var(--mf-transition);
}

.app-module-form__close:hover {
    background: rgba(255, 255, 255, .2);
    border-color: rgba(255, 255, 255, .32);
}

.app-module-form__close:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 1px;
}

/* ---- Body ---- */
/* No overflow-y here on purpose. A scroll area inside the form produces a
   nested scrollbar -- the page scrolls, then the form scrolls again inside it,
   and neither shows the user where they are. Where a host genuinely needs to
   bound the height (a modal dialog), that host owns the scrolling. */
.app-module-form__body {
    flex: 1 1 auto;
    min-width: 0;
    padding: var(--ui-space-lg, 16px) var(--ui-space-lg, 16px) var(--ui-space-sm, 8px);
}

/* ---- Step rail ---- */
.app-module-form__steps {
    display: flex;
    align-items: center;
    gap: var(--ui-space-2xs, 4px);
    margin-bottom: var(--ui-space-lg, 16px);
    padding-bottom: var(--ui-space-md, 12px);
    border-bottom: 1px solid var(--mf-border-subtle);
}

.app-module-form__step {
    display: flex;
    align-items: center;
    gap: var(--ui-space-xs, 6px);
    padding: 2px var(--ui-space-sm, 8px);
    border-radius: var(--mf-radius-sm);
    color: var(--mf-text-muted);
    font-size: var(--ui-small-font-size, 12px);
    white-space: nowrap;
    transition: color var(--mf-transition);
}

.app-module-form__step-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--mf-surface-muted);
    color: var(--mf-text-muted);
    font-size: var(--ui-small-font-size, 12px);
    font-weight: 700;
    line-height: 1;
    transition: background var(--mf-transition), color var(--mf-transition);
}

.app-module-form__step.is-active {
    color: var(--mf-text);
    font-weight: 600;
}

.app-module-form__step.is-active .app-module-form__step-num {
    background: var(--mf-brand);
    color: #fff;
}

.app-module-form__step.is-done {
    color: var(--mf-success);
}

.app-module-form__step.is-done .app-module-form__step-num {
    background: var(--mf-success);
    color: #fff;
}

.app-module-form__step-line {
    flex: 1 1 auto;
    min-width: 16px;
    height: 1px;
    background: var(--mf-border-subtle);
}

/* Steps are a progress indicator by default. When the host page
   makes them clickable it swaps in <button> and this applies. */
button.app-module-form__step {
    border: 0;
    background: none;
    font-family: inherit;
    cursor: pointer;
}

/* ---- Section ----
   The section itself is the grid, and it fits as many columns as the width
   allows. Fields used to be locked to whatever their row declared (2 or 3),
   so a wide screen just made 2 columns wider and the form stayed tall enough
   to scroll. Flowing every field through one auto-fit grid spends the width
   horizontally instead, which is what keeps the form on one screen. */
.app-module-form__section {
    container: module-form / inline-size;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(var(--mf-col-min, 15rem), 100%), 1fr));
    gap: var(--ui-space-md, 12px) var(--ui-space-lg, 16px);
    align-items: start;
    margin-bottom: var(--ui-space-lg, 16px);
}

.app-module-form__section:last-child {
    margin-bottom: 0;
}

.app-module-form__section-title,
.app-module-form__section-desc {
    grid-column: 1 / -1;
}

/* Section-level content spans the whole grid rather than landing in the first free
   track. The section IS the field grid, so a `append` block -- a table of uploaded
   batches, a repeater, a review list, a build plan -- was being squeezed into one
   column the same width as a text input. Title and desc were each spelled out above
   and kept there for clarity; rows are display:contents, so excluding them is what
   keeps their fields as the real grid items. */
.app-module-form__section > :not(.app-module-form__row) {
    grid-column: 1 / -1;
}

.app-module-form__section-title {
    margin: 0 0 var(--ui-space-sm, 8px);
    padding-bottom: var(--ui-space-2xs, 4px);
    border-bottom: 1px solid var(--mf-border-subtle);
    color: var(--mf-text);
    font-size: var(--ui-font-size, 14px);
    font-weight: 700;
}

.app-module-form__section-desc {
    margin: 0 0 var(--ui-space-md, 12px);
    color: var(--mf-text-muted);
    font-size: var(--ui-small-font-size, 12px);
}

/* ---- Field grid ----
   Rows keep existing in the markup because they are how a caller groups
   related fields, but they are not layout boxes any more: display:contents
   drops the row box and hands its fields straight to the section grid, so
   fields flow across the full width instead of restarting on every row.

   Consequence, and it is intended: the --1/--2/--3/--4 counts are advisory.
   The width decides how many fit. `full` and `inline` are still honoured
   exactly, because those express intent the width cannot infer. */
.app-module-form__row {
    display: contents;
}

/* A caller asking for a narrower or wider rhythm sets the track floor rather
   than a column count -- that keeps working at every screen size. */
.app-module-form__row--1 { --mf-col-min: 100%; }
.app-module-form__row--2 { --mf-col-min: 22rem; }
.app-module-form__row--3 { --mf-col-min: 15rem; }
.app-module-form__row--4 { --mf-col-min: 11rem; }

/* ---- Field widths ----
   One field, one track, by default -- so every field in a section starts and
   ends on the same gridlines and the columns read straight down. This was first
   built the other way, with each field claiming space by type (dates narrow,
   names wide). It looked reasonable per field and ragged as a form: mixed spans
   stop dividing evenly into the row, and a group of five would leave the sixth
   field stranded alone on the next line. Uniform tracks are what ERP forms use,
   and the reason is alignment, not laziness.

   Only fields that genuinely cannot work in one track get more. The renderer
   gives a textarea the full row automatically; `width` overrides per field. */
.app-module-form__field { grid-column: span 1; }
.app-module-form__field--sm { grid-column: span 1; }
.app-module-form__field--md { grid-column: span 1; }
.app-module-form__field--lg { grid-column: span 2; }
.app-module-form__field--xl { grid-column: 1 / -1; }

/* A 2-track span cannot fit a 1-track grid, so it collapses with the rest. */
@container module-form (max-width: 32rem) {
    .app-module-form__field--lg { grid-column: 1 / -1; }
}

/* Start a fresh line: for the first field of a group that should not trail the
   previous one on the same row. */
.app-module-form__field--newline { grid-column-start: 1; }

/* Toggles and checkboxes sit next to each other rather than each claiming a
   grid column, so this row stays a real flex box and takes the full width. */
.app-module-form__row--inline {
    display: flex;
    grid-column: 1 / -1;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ui-space-lg, 16px);
}

.app-module-form__field {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

/* `full` beats every width keyword, whichever order they land in the class list. */
.app-module-form__field--full,
.app-module-form__field--full.app-module-form__field--sm,
.app-module-form__field--full.app-module-form__field--md,
.app-module-form__field--full.app-module-form__field--lg,
.app-module-form__field--full.app-module-form__field--xl {
    grid-column: 1 / -1;
}

.app-module-form__label {
    color: var(--mf-text-secondary);
    font-size: var(--ui-small-font-size, 12px);
    font-weight: 700;
    letter-spacing: .02em;
}

.app-module-form__required {
    margin-inline-start: 2px;
    color: var(--mf-danger);
}

.app-module-form__control {
    width: 100%;
    min-width: 0;
    height: var(--ui-control-height, 34px);
    padding: 0 var(--ui-control-padding-x, 12px);
    border: 1px solid var(--mf-border);
    border-radius: var(--mf-radius-sm);
    background: var(--mf-surface);
    color: var(--mf-text);
    font-family: inherit;
    font-size: var(--ui-small-font-size, 12px);
    line-height: normal;
    outline: none;
    transition: border-color var(--mf-transition), box-shadow var(--mf-transition);
}

/* Authors reach for a bare <input> inside a field far more often
   than they remember the control class. Style both so the two
   spellings cannot drift apart visually. */
.app-module-form__field > input:not([type="checkbox"]):not([type="radio"]),
.app-module-form__field > select,
.app-module-form__field > textarea {
    width: 100%;
    min-width: 0;
    height: var(--ui-control-height, 34px);
    padding: 0 var(--ui-control-padding-x, 12px);
    border: 1px solid var(--mf-border);
    border-radius: var(--mf-radius-sm);
    background: var(--mf-surface);
    color: var(--mf-text);
    font-family: inherit;
    font-size: var(--ui-small-font-size, 12px);
    outline: none;
    transition: border-color var(--mf-transition), box-shadow var(--mf-transition);
}

textarea.app-module-form__control,
.app-module-form__field > textarea {
    height: auto;
    min-height: calc(var(--ui-control-height, 34px) * 2);
    padding: var(--ui-space-xs, 6px) var(--ui-control-padding-x, 12px);
    line-height: var(--ui-line-height, 1.45);
    resize: vertical;
}

.app-module-form__control:focus,
.app-module-form__field > input:focus,
.app-module-form__field > select:focus,
.app-module-form__field > textarea:focus {
    border-color: var(--mf-brand);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--mf-brand) 16%, transparent);
}

.app-module-form__control:disabled,
.app-module-form__control[readonly],
.app-module-form__field > input:disabled,
.app-module-form__field > select:disabled,
.app-module-form__field > textarea:disabled {
    background: var(--mf-surface-muted);
    color: var(--mf-text-muted);
    cursor: not-allowed;
}

.app-module-form__control.is-invalid,
.app-module-form__field.is-invalid > input,
.app-module-form__field.is-invalid > select,
.app-module-form__field.is-invalid > textarea {
    border-color: var(--mf-danger);
}

.app-module-form__help {
    color: var(--mf-text-muted);
    font-size: var(--ui-small-font-size, 12px);
    line-height: 1.35;
}

.app-module-form__error {
    color: var(--mf-danger);
    font-size: var(--ui-small-font-size, 12px);
    line-height: 1.35;
}

/* The error node is rendered up front and always present, so showing a
   message is a textContent write rather than a DOM insertion — JS never
   has to know where in the field the message belongs. It collapses while
   empty; reserving a line under all 20-odd fields to avoid the shift on
   one would cost far more vertical space than it saves. */
.app-module-form__error:empty {
    display: none;
}

/* ---- Static / read-only value ---- */
.app-module-form__value {
    display: flex;
    align-items: center;
    min-height: var(--ui-control-height, 34px);
    padding: 0 var(--ui-control-padding-x, 12px);
    border: 1px solid transparent;
    border-radius: var(--mf-radius-sm);
    background: var(--mf-surface-muted);
    color: var(--mf-text);
    font-size: var(--ui-small-font-size, 12px);
    font-variant-numeric: tabular-nums;
}

/* ---- File control ---- */
.app-module-form__file {
    display: flex;
    align-items: center;
    gap: var(--ui-space-sm, 8px);
    min-height: var(--ui-control-height, 34px);
    padding: 0 var(--ui-space-xs, 6px);
    border: 1px solid var(--mf-border);
    border-radius: var(--mf-radius-sm);
    background: var(--mf-surface-muted);
}

.app-module-form__file input[type="file"] {
    width: auto;
    min-width: 0;
    height: auto;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--mf-text);
    font-family: inherit;
    font-size: var(--ui-small-font-size, 12px);
}

.app-module-form__file input[type="file"]::file-selector-button {
    height: var(--ui-control-height-sm, 28px);
    margin-inline-end: var(--ui-space-sm, 8px);
    padding: 0 var(--ui-space-md, 12px);
    border: 1px solid var(--mf-border);
    border-radius: var(--mf-radius-sm);
    background: var(--mf-surface);
    color: var(--mf-text-secondary);
    font-family: inherit;
    font-size: var(--ui-small-font-size, 12px);
    cursor: pointer;
    transition: background var(--mf-transition), border-color var(--mf-transition);
}

.app-module-form__file input[type="file"]::file-selector-button:hover {
    background: var(--mf-brand-light);
    border-color: var(--mf-brand);
}

/* ---- Actions field ----
   A field that holds buttons instead of a control. It has no label, and a field is
   a column with the label on top, so without bottom alignment the button sits a
   label's height too high -- measured at 17px above the inputs beside it on the
   aging workbook's filter row. align-self:end puts its baseline on the controls'. */
.app-module-form__field--actions {
    align-self: end;
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ui-space-xs, 6px);
}

.app-module-form__field--actions .app-module-form__error {
    display: none;
}

/* ---- Checkbox ---- */
.app-module-form__check {
    display: inline-flex;
    align-items: center;
    gap: var(--ui-space-sm, 8px);
    min-height: var(--ui-control-height, 34px);
    color: var(--mf-text-secondary);
    font-size: var(--ui-small-font-size, 12px);
    cursor: pointer;
}

.app-module-form__check input {
    margin: 0;
    flex-shrink: 0;
    accent-color: var(--mf-brand);
}

/* ---- Radio group ---- */
.app-module-form__radio-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ui-space-sm, 8px) var(--ui-space-md, 12px);
    min-height: var(--ui-control-height, 34px);
}

.app-module-form__radio {
    display: inline-flex;
    align-items: center;
    gap: var(--ui-space-xs, 6px);
    padding: var(--ui-space-2xs, 4px) var(--ui-space-sm, 8px);
    border: 1px solid var(--mf-border);
    border-radius: var(--mf-radius-sm);
    background: var(--mf-surface);
    color: var(--mf-text-secondary);
    font-size: var(--ui-small-font-size, 12px);
    cursor: pointer;
    transition: border-color var(--mf-transition), background var(--mf-transition);
}

.app-module-form__radio:hover {
    border-color: var(--mf-brand);
    background: var(--mf-brand-light);
}

/* :has() gives the checked option a visible state without a JS class. Browsers
   without it simply keep the native dot, which is still unambiguous. */
.app-module-form__radio:has(input:checked) {
    border-color: var(--mf-brand);
    background: var(--mf-brand-light);
    color: var(--mf-text);
    font-weight: 600;
}

.app-module-form__radio input {
    margin: 0;
    accent-color: var(--mf-brand);
}

/* ---- Input addon (unit suffix/prefix) ---- */
.app-module-form__addon {
    display: flex;
    align-items: stretch;
    width: 100%;
    min-width: 0;
    border: 1px solid var(--mf-border);
    border-radius: var(--mf-radius-sm);
    background: var(--mf-surface);
    transition: border-color var(--mf-transition), box-shadow var(--mf-transition);
}

/* The border moves to the wrapper so the unit sits inside one control box
   rather than beside a second bordered rectangle. */
.app-module-form__addon .app-module-form__control {
    border: 0;
    border-radius: 0;
    background: transparent;
    flex: 1 1 auto;
}

.app-module-form__addon .app-module-form__control:focus {
    box-shadow: none;
}

.app-module-form__addon:focus-within {
    border-color: var(--mf-brand);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--mf-brand) 16%, transparent);
}

.app-module-form__addon-text {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    padding-inline: var(--ui-space-sm, 8px);
    background: var(--mf-surface-muted);
    color: var(--mf-text-muted);
    font-size: var(--ui-small-font-size, 12px);
    font-weight: 600;
}

.app-module-form__field.is-invalid .app-module-form__addon {
    border-color: var(--mf-danger);
}

/* ---- Toggle ---- */
.app-module-form__toggle-group {
    display: inline-flex;
    align-items: center;
    gap: var(--ui-space-sm, 8px);
}

.app-module-form__toggle-label {
    color: var(--mf-text-secondary);
    font-size: var(--ui-small-font-size, 12px);
}

/* A real <button role="switch"> rather than the mockup's <div>:
   a div toggle is invisible to keyboard and screen readers, and
   this form ships framework-wide. The hidden input carries the
   value so the control posts with a normal form submit. */
.app-module-form__toggle {
    position: relative;
    flex-shrink: 0;
    width: 36px;
    height: 20px;
    padding: 0;
    border: 1px solid var(--mf-border);
    border-radius: 100px;
    background: var(--mf-surface-muted);
    cursor: pointer;
    transition: background var(--mf-transition), border-color var(--mf-transition);
}

.app-module-form__toggle[aria-checked="true"] {
    background: var(--mf-brand);
    border-color: var(--mf-brand);
}

.app-module-form__toggle:disabled {
    opacity: .55;
    cursor: not-allowed;
}

.app-module-form__toggle:focus-visible {
    outline: 2px solid var(--mf-brand);
    outline-offset: 2px;
}

.app-module-form__toggle-thumb {
    position: absolute;
    top: 1px;
    inset-inline-start: 1px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
    transition: inset-inline-start var(--mf-transition);
}

.app-module-form__toggle[aria-checked="true"] .app-module-form__toggle-thumb {
    inset-inline-start: 17px;
}

/* ---- Footer ---- */
.app-module-form__footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--ui-space-sm, 8px);
    flex-shrink: 0;
    padding: var(--ui-space-md, 12px) var(--ui-space-lg, 16px);
    border-top: 1px solid var(--mf-border-subtle);
    background: var(--mf-surface-muted);
}

.app-module-form__footer-info {
    color: var(--mf-text-muted);
    font-size: var(--ui-small-font-size, 12px);
}

.app-module-form__footer-start,
.app-module-form__footer-end {
    display: flex;
    align-items: center;
    gap: var(--ui-space-xs, 6px);
    flex-wrap: wrap;
}

/* ---- Responsive ---- */
@media (max-width: 768px) {
    .app-module-form__body {
        padding: var(--ui-space-md, 12px) var(--ui-space-md, 12px) var(--ui-space-xs, 6px);
    }

    /* No column override needed any more -- minmax() already collapses the grid
       to one track once the width drops below the floor. Forcing it here would
       also stop two narrow fields sharing a line on a mid-size screen. */
    .app-module-form__section {
        gap: var(--ui-space-sm, 8px) var(--ui-space-md, 12px);
    }

    .app-module-form__steps {
        flex-wrap: wrap;
        gap: var(--ui-space-2xs, 4px);
    }

    .app-module-form__step-line {
        display: none;
    }

    .app-module-form__badge {
        display: none;
    }

    .app-module-form__header {
        padding: var(--ui-space-xs, 6px) var(--ui-space-md, 12px);
    }

    .app-module-form__footer {
        flex-direction: column;
        align-items: stretch;
        padding: var(--ui-space-sm, 8px) var(--ui-space-md, 12px);
    }

    .app-module-form__footer-start,
    .app-module-form__footer-end {
        justify-content: center;
    }
}

/* ---- Print ---- */
@media print {
    .app-module-form {
        border-color: #999;
        box-shadow: none;
    }

    .app-module-form__header-actions,
    .app-module-form__footer-end {
        display: none;
    }
}
