body {
    font-family: var(--page-font-family);
    margin: 0;
    padding: 0;
    background-color: var(--page-background);
    color: var(--page-font-color);
}

/* One keyboard-focus contract for every shell. :focus-visible avoids painting a
   ring on ordinary pointer clicks while keeping navigation unambiguous. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 3px solid var(--focus-ring-color, var(--link-font-color));
    outline-offset: 2px;
}

/* Motion is enhancement, never a requirement. This also covers module sheets
   that use transitions without having to duplicate the preference guard. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        scroll-behavior: auto !important;
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* Local inline-SVG icon vocabulary (core/context/ui/icon.htp). Icons inherit
   currentColor and never establish meaning without a visible text label. */
.ui-icon {
    display: inline-block;
    width: 1.15em;
    height: 1.15em;
    flex: 0 0 auto;
    vertical-align: -0.18em;
}

.page.container {
    max-width: 1200px;
    height: 99vh;
/*    border: var(--main-border); */
    margin: 0 auto;
    display: grid;
    grid-template-areas:
        "banner banner"
        "header header"
        "menu main"
        "footer footer";
    grid-template-columns: 140px 1fr;
    grid-template-rows: auto auto 1fr auto;
    overflow: hidden;
    background-color: inherit;
    gap: var(--page-grid-gap);
}

.page.container > div {
    border-radius: var(--page-grid-border-radius);
}

.banner-logo { display: inline-block; padding-right: 4px; padding-left: 10px; top: 5px; position: relative; }
.banner-subtext { padding-left: 10px; color: var(--banner-subtext); font-size: 16px; font-weight: normal; }

.page > .banner {
    grid-area: banner;
    background-color: var(--banner-background);
    color: var(--banner-font-color);
    padding: 4px;
    text-align: left;
    font-size: 24px;
    font-weight: bold;
    box-shadow: var(--banner-shadow);
    border: var(--banner-border);
}

/* App selector in the banner ([Site Name] slot — crud_shell puts the popup
   there in place of the static site name): the target renders as the banner
   title text, not a button; the dropdown window resets to normal text metrics. */
.page > .banner .control.popup { vertical-align: baseline; }
.page > .banner .control.popup .target {
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0 4px;
    color: var(--banner-font-color);
    font-size: inherit;
    font-weight: inherit;
}
.page > .banner .control.popup .target:hover {
    background: var(--sidebar-menu-hover-background);
    border: none;
}
.page > .banner .popup > .window { font-size: 16px; font-weight: normal; }

.page > .header {
    grid-area: header;
    background-color: var(--header-background);
    border: var(--header-border);
    padding: 10px 15px;
    border-bottom: var(--header-border);
    color: var(--header-font-color);
    font-weight: bold;
    display: grid;
    grid-template-columns: auto auto auto auto 1fr auto 1fr auto;
    grid-template-areas: "site app company distributors . search . user";
    align-items: center;
    gap: 10px;
    box-shadow: var(--header-shadow);
}

/* Header selectors as separate grid areas */
.company { grid-area: companies; }
.distributor { grid-area: distributors; }

.search {
    grid-area: search;
    position: relative;
    justify-self: center;
}
.search input {
    padding: 6.5px 39px 6.5px 13px;
    border-radius: 26px;
    border: var(--input-border);
    width: 390px;
    font-size: 1em;
    background-color: var(--input-background);
    color: var(--input-font-color);
}
.search .close {
    position: absolute;
    top: 50%;
    right: 12px;
    transform: translateY(-50%);
    cursor: pointer;
    font-weight: bold;
    font-size: 16px;
    color: var(--border-font-color);
    z-index: 5;
}

.user.control.popup { grid-area: user; justify-self: end; }
.site.control.popup { grid-area: site; justify-self: start; }
.site.control.popup .target:after { content: " \25BC"; font-size: 10px; margin-left: 6px; }
.app.control.popup { grid-area: app; justify-self: start; }
.app.control.popup .target:after { content: " \25BC"; font-size: 10px; margin-left: 6px; }
/* Module header control (core_mod_header_controls): mfr's Company selector on an
   All Sites session. One entry per company, POSTed through the picker page. */
.company.control.popup { grid-area: company; justify-self: start; }
.company.control.popup .target:after { content: " \25BC"; font-size: 10px; margin-left: 6px; }
.company.control.popup .company-switch { list-style: none; margin: 0; padding: 4px 0; }
.company.control.popup .company-switch li { padding: 0; }
.company.control.popup .company-switch button {
    display: block; width: 100%; text-align: left; background: none; border: 0;
    padding: 6px 14px; font: inherit; color: inherit; cursor: pointer; white-space: nowrap;
}
.company.control.popup .company-switch button:hover { background: var(--popup-hover-background, rgba(127,127,127,.15)); }
.company.control.popup .company-switch li.current { padding: 6px 14px; font-weight: bold; }

.popup {
    position: relative;
    display: inline-block;
}

.popup > .window { z-index: 3000; }

.target {
    padding: 6px 12px;
    background-color: var(--button-background);
    color: var(--button-font-color);
    border-radius: 4px;
    cursor: pointer;
    display: flex;
    align-items: center;
    border: var(--button-border);
    box-shadow: var(--button-shadow);
    transition: background-color .2s ease, border-color .2s ease;
}
.target:hover {
    background-color: var(--button-hover-background);
    border: var(--button-hover-border);
}
.target:after { content: "\25BC"; font-size: 10px; margin-left: 8px; }

.window {
    position: absolute;
    top: 100%;
    right: 0;
    min-width: 200px;
    background-color: var(--popup-background);
    border: var(--popup-border);
    border-radius: 4px;
    box-shadow: 0 4px 8px var(--popup-window-shadow);
    display: none;
    z-index: 1001;
    padding: 0;
    max-height: 85vh;
    overflow-y: auto;
    color: var(--popup-font-color);
}
.window.right { left: 0; right: unset; }
.popup.active .window { display: block; }

.popup .window .header-wrapper {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: var(--header-background);
    color: var(--header-font-color);
    padding: 0;
    width: 100%;
}
.popup .window h4 {
    margin: 0;
    padding: 10px 15px;
    background-color: var(--header-background);
    color: var(--header-font-color);
    font-size: 14px;
    font-weight: 500;
    flex-grow: 1;
}
.popup .window .close {
    color: var(--header-font-color);
    font-size: 14px;
    font-weight: bold;
    cursor: pointer;
    padding: 10px 15px;
    background: none;
    border: none;
}
.popup .window .close:hover {
    background-color: var(--help-hover-background);
    color: var(--help-hover-font-color);
}

.selector .item {
    padding: 8px 12px;
    cursor: pointer;
    background: var(--main-background);
    color: var(--main-font-color);
}
.selector .item:hover { background-color: var(--table-even-row-hover); }
.selector .item.selected {
    background-color: var(--sidebar-menu-active-background);
    color: var(--sidebar-menu-active-font-color);
    font-weight: bold;
}
.selector .item:last-child { border-bottom: none; }

.sidebar-menu {
    grid-area: menu;
    background-color: var(--sidebar-background);
    border-right: var(--sidebar-border);
    padding: 10px;
    overflow: auto;
    color: var(--sidebar-menu-font-color);
}

.sidebar-menu > div {
    padding: 4px 10px;
    margin-bottom: 5px;
    background-color: transparent;
    border-radius: 4px;
    cursor: pointer;
    color: var(--sidebar-menu-font-color);
}

.sidebar-menu a {
    text-decoration: none;
    color: var(--sidebar-menu-font-color);
    width: 100%;
}

.sidebar-menu > div:hover { background-color: var(--sidebar-menu-hover-background); }

.main {
    grid-area: main;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    min-height: 0;
    background-color: var(--main-background);
    color: var(--main-font-color);
}

.main .area {
    overflow-y: auto;
    width: 100%;
    flex: 1;
    min-height: 0;
}

.fillup {
    flex: 1;
    overflow: auto;
    margin: 6px;
    min-height: 0;
    background: var(--fillup-background);
}

.fixed {
    overflow: auto;
    margin: 6px;
    background: var(--fillup-background);
}

.page > .footer {
    grid-area: footer;
    background-color: var(--footer-background);
    padding: 10px 15px;
    border-top: var(--footer-border);
    text-align: center;
    color: var(--footer-font-color);
    box-shadow: var(--footer-shadow);
}

.user.popup .initials {
    position: relative;
    display: inline-block;
    top: 0px;
    padding-left: 6px;
    font-weight: bold;
    color: var(--user-initials-font-color);
    background: var(--user-icon-background);
    border-radius: 999px;
    padding-right: 6px;
    margin-left: 6px;
}

.control.popup .target {
    background-color: var(--button-background);
    color: var(--button-font-color);
    border: var(--button-border);
    padding: 6px 12px;
    border-radius: 4px;
    display: flex;
    align-items: center;
    gap: 6px;
    transition: all 0.2s ease;
}

.control.popup .target:hover {
    background-color: var(--button-hover-background);
    border: var(--button-hover-border);
}

.control.popup .target:after { content: ''; margin-left: 0; }

.control .window {
    width: 280px;
    border-radius: 6px;
    box-shadow: 0 4px 12px var(--popup-window-shadow);
    overflow: auto;
    padding: 0;
    max-height: 85vh;
    z-index: 1002;
    position: absolute;
    top: 100%;
    right: 0;
    border: var(--popup-window-border);
    background: var(--popup-background);
    color: var(--popup-font-color);
}

.control .section {
    padding: 12px 15px;
    border-bottom: var(--main-border);
    background: var(--main-background);
    color: var(--main-font-color);
}

.control .label {
    display: block;
    margin-bottom: 5px;
    font-weight: normal;
    font-size: 13px;
    color: var(--border-font-color);
}

.control select,
.control input[type="date"],
.control input[type="number"],
.control input[type="text"] {
    width: 100%;
    padding: 6px 8px;
    border: var(--input-border);
    border-radius: 4px;
    font-size: 13px;
    background-color: var(--input-background);
    color: var(--input-font-color);
    box-sizing: border-box;
    transition: box-shadow .2s ease, outline .2s ease;
}
.control select:focus,
.control input[type="date"]:focus,
.control input[type="number"]:focus,
.control input[type="text"]:focus {
    outline: 2px solid color-mix(in oklab, currentColor 10%, transparent);
    box-shadow: 0 0 0 2px var(--popup-window-shadow);
}

.theme-selector { display: flex; gap: 10px; margin: 5px 0; }
.theme-option { display: flex; align-items: center; gap: 5px; cursor: pointer; }
.theme-option input { margin: 0; }
.theme-option label { color: var(--main-font-color); }

.button.section {
    gap: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-bottom: none;
    background: transparent;
}
/* Button look on ANY element via class="button" (<a>, <div>, <button>), plus a
   bare <button> inside a .button.section row. The .button.section CONTAINER is
   excluded (:not(.section)) — it only lays out a row of buttons. text-decoration
   + color reset so <a class="button"> never looks like a link. */
.button:not(.section),
.button.section button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 4px;
    font-size: 13px;
    line-height: 1.2;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: all 0.2s ease;
    border: var(--button-border);
    background-color: var(--button-background);
    color: var(--button-font-color);
}

.button:not(.section):hover,
.button.section button:hover {
    background-color: var(--button-hover-background);
    border: var(--button-hover-border);
    color: var(--button-font-color);
}

.popup .window ul.report-list,
.popup .window ul.site-switch,
.popup .window ul.app-switch,
ul.popup-selector,
ul.header-selector {
    display: block;
    list-style: none;
    margin: 0;
    padding: 0;
}

.popup .window ul.report-list li,
.popup .window ul.site-switch li,
.popup .window ul.app-switch li,
ul.popup-selector li,
ul.header-selector li {
    padding: 8px 12px;
    cursor: pointer;
    color: var(--main-font-color);
    background: var(--main-background);
}

.popup .window ul.report-list li:hover,
.popup .window ul.site-switch li:hover,
.popup .window ul.app-switch li:hover,
ul.popup-selector li:hover,
ul.header-selector li:hover {
    background-color: var(--table-even-row-hover);
}

.popup .window ul.report-list li.current,
.popup .window ul.site-switch li.current,
.popup .window ul.app-switch li.current,
ul.popup-selector li.current,
ul.header-selector li.current {
    background-color: var(--sidebar-menu-active-background);
    color: var(--sidebar-menu-active-font-color);
    font-weight: bold;
}

/* Site-switch entries are POST forms (CSRF-checked identity change) whose button
   looks and behaves like the link it replaced, filling the row. */
.popup .window ul.site-switch li:has(form) { padding: 0; }
.popup .window ul.site-switch form { margin: 0; }
.popup .window ul.site-switch button {
    display: block; width: 100%; padding: 8px 12px; margin: 0; border: 0;
    background: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
}

.popup .window ul.report-list a,
.popup .window ul.site-switch a,
.popup .window ul.app-switch a,
ul.popup-selector a,
ul.header-selector a {
    color: inherit;
    text-decoration: none;
}

ul.nav-menu { display: block; list-style-type: none; margin: 0px; padding: 0px;}
ul.nav-menu li { padding: 5px; cursor: pointer; }
ul.nav-menu li a { display: block;}
ul.nav-menu li:hover { background-color: var(--sidebar-menu-hover-background); border-radius: 4px; text-decoration: underline; }
ul.nav-menu li.current { background-color: var(--sidebar-menu-hover-background); border-radius: 4px; font-weight: bold; }
ul.nav-menu ul.nav-children { list-style-type: none; margin: 2px 0 0 0; padding-left: 14px; font-size: 13px; font-weight: normal; }
ul.nav-menu ul.nav-children li { padding: 2px 5px; }

/* CRUD edit/new form fields (crud_form / crud_render_field). A field whose write
   failed validation gets .field.error: the row is flagged and .field-error carries
   the message beside the input. Form-level errors render as standalone .field.error
   blocks atop the form. */
.field { display: block; margin: 6px 0; }
.field > label { display: inline-block; min-width: 160px; vertical-align: top; }
.field.error { border-left: 3px solid var(--status-failed-background); padding-left: 6px; }
.field.error > label { color: var(--status-failed-background); font-weight: bold; }
.field .field-error { color: var(--status-failed-background); font-size: 13px; }

/* Premade form layouts (crud_layout_grid). grid-template-areas / column sizing is
   set inline from the layout def; .crud-area is one named region; min-width:0 lets
   narrow columns shrink instead of overflowing. .crud-unplaced collects any field
   the entity's area map didn't place. */
.crud-grid { display: grid; }
.crud-area { min-width: 0; }
.crud-unplaced { margin-top: 12px; }

/* Composite field (crud_render_group): subfields rendered as one labeled bubble,
   placeable in a layout region as a single unit. */
.field.group { background: var(--field-bubble-background); border: var(--field-bubble-border); border-radius: 4px; padding: 8px 10px; margin: 6px 0; }
.field.group .group-label { font-weight: bold; margin-bottom: 6px; }
/* Read-only field (crud_render_field _display): value shown as static text. */
.field.display .value { display: inline-block; }
/* Read-only rich-text (HTML) value in a display field — e.g. the ems Assignment
   course panel's description/prereqs. Render the markup but keep it contained:
   wrap long content, cap the height with a scroll, and normalize the block font to
   the page (inline styles in the pasted HTML still win, by design). */
.field.display .value.richtext-display {
    display: block;
    max-width: 100%;
    max-height: 320px;
    overflow: auto;
    font-family: var(--page-font-family);
    border: var(--field-bubble-border);
    border-radius: var(--page-grid-border-radius);
    background: var(--field-bubble-background);
    padding: 8px 10px;
}
.field.display .value.richtext-display img { max-width: 100%; height: auto; }

/* Required marker, inline help text, and the post-save banner. */
.field .required { color: var(--status-failed-background); font-weight: bold; }
.hint { color: var(--border-font-color); opacity: 0.7; font-size: 13px; font-style: italic; }
.banner.success { background: var(--field-bubble-background); border-left: 4px solid var(--status-success-background); padding: 8px 12px; margin: 0 0 12px; border-radius: 4px; }
/* Failure twin of .banner.success — same shape, so "saved" and "not saved" read
   as the same kind of statement about the same save. Was missing entirely: a
   failed save had no page-level statement at all, only per-field marks that a
   grid layout can push off screen. Colour comes from the same variable as
   .field.error, so the banner and the fields it refers to agree. */
.banner.error { background: var(--field-bubble-background); border-left: 4px solid var(--status-failed-background); padding: 8px 12px; margin: 0 0 12px; border-radius: 4px; }
.banner.error strong { color: var(--status-failed-background); }
.banner.error .banner-errors { margin: 6px 0 0; padding-left: 20px; }
.banner.error .banner-errors li { margin: 2px 0; }
/* PARTIAL success: the record saved, something related did not. Neither green
   nor red would be honest, so it is amber — the same signal the access-delta
   stale-edit warning uses for "look at this, nothing is broken". */
.banner.warn { background: var(--field-bubble-background); color: var(--status-warning-font-color); border-left: var(--status-warning-border); padding: 8px 12px; margin: 0 0 12px; border-radius: 4px; }
.banner.warn .banner-errors { margin: 6px 0 0; padding-left: 20px; }
.banner.warn .banner-errors li { margin: 2px 0; }
/* Neutral twin: a statement about how this entity is CONFIGURED, not a fault —
   "no row-level logging for this entity", "no exportable columns". These used to
   render as bare <p> with no styling at all. Painting them red instead would be
   worse than leaving them plain: a normal configuration answer would look like a
   failure, and a red that fires on non-failures is a red people learn to ignore. */
.banner.info { background: var(--field-bubble-background); border-left: 4px solid var(--banner-subtext); padding: 8px 12px; margin: 0 0 12px; border-radius: 4px; }

/* Compact state/category label. Neutral is the safe default; semantic variants
   use the same status tokens as banners, so colour never changes its meaning. */
.badge {
    display: inline-flex;
    align-items: center;
    min-height: 22px;
    box-sizing: border-box;
    padding: 2px 8px;
    border: var(--badge-border);
    border-radius: 999px;
    background: var(--badge-background);
    color: var(--badge-font-color);
    font-size: 12px;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
}
.badge--success { border-color: var(--status-success-background); color: var(--status-success-background); }
.badge--warning { border-color: var(--status-warning-font-color); color: var(--status-warning-font-color); }
.badge--error   { border-color: var(--status-failed-background); color: var(--status-failed-background); }
/* The "nothing here" row inside an otherwise empty grid. Muted and centred so it
   reads as an answer to the empty space rather than as a record in the list. */
/* One "nothing here" treatment for the places that had none — a table body, a card
   grid, an attachments box, a history page. The generic class="empty" carried no
   styling at all, so those statements rendered as bare text next to siblings that
   were styled. Muted and centred so it reads as an answer to the empty space rather
   than as content sitting in it.
   Deliberately NOT applied to .sg-empty or .asset-empty: those style themselves in
   their own inline <style> blocks, with spacing chosen for their context (a
   full-page search result wants more room than a table row), and adding this would
   only give one element two sources of truth. */
.empty-state,
.spreadsheet tr.crud-empty td,
.crud-cards > .crud-empty { text-align: center; padding: 18px 12px; color: var(--banner-subtext); font-style: italic; }
.crud-cards > .crud-empty { grid-column: 1 / -1; }
/* Mass-action progress: an operation with failed rows. */
#ma-results .ma-failed { color: var(--status-failed-background); }
#ma-results .ma-failed ul { color: var(--border-font-color); font-size: 13px; margin: 2px 0 0; }

/* Shared multicheckbox dropdown (explicit dropdown=true, or >8 options): native
   <details> panel overlays rather than pushing the form down. */
.field .multiselect { display: inline-block; position: relative; }
.field .multiselect > summary { cursor: pointer; padding: 3px 8px; border: var(--field-name-border); border-radius: 4px; background: var(--input-background); list-style: none; }
.field .multiselect > summary::-webkit-details-marker { display: none; }
.field .multiselect[open] > .checkboxes { position: absolute; z-index: 50; left: 0; min-width: 200px; max-height: 240px; overflow-y: auto; background: var(--input-background); border: var(--field-name-border); border-radius: 4px; padding: 6px 8px; box-shadow: 0 2px 6px rgba(0,0,0,0.2); }
.field .multiselect .checkbox { display: block; padding: 1px 0; }

/* =========================================================================
   App dashboards (core.context.ui.exec.dashboard) + the dashboard/SP-screen
   component classes. Tokens from theme.css; see docs/site-standards.md §5.1/§6.
   ========================================================================= */

/* Dashboard grid: 12 columns; a tile spans all 12 by default (vertical list),
   or sets --dash-span / --dash-col (the renderer emits them from a field's
   span/col). Collapses to one column on narrow screens. */
.dashboard      { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--dash-gap, 16px); align-items: start; }
.dash-field     { grid-column: var(--dash-col, auto) / span var(--dash-span, 12); min-width: 0; }
@media (max-width: 760px) { .dash-field { grid-column: 1 / -1; } }

/* Section/shortcut cards (core_dashboard_navcards). */
.dash-cards     { display: flex; flex-wrap: wrap; gap: var(--dash-gap, 16px); margin-top: 16px; }
.dash-card      { display: flex; align-items: center; gap: 14px; min-width: 200px; padding: 20px 24px; text-decoration: none; color: inherit;
                  border: var(--main-border); border-radius: var(--page-grid-border-radius); background: var(--main-background); }
.dash-card:hover{ background: var(--field-bubble-background); }
.dash-card h2   { margin: 0; }
.dash-card-icon { display: grid; width: 38px; height: 38px; place-items: center; border-radius: 10px;
                  background: var(--surface-subtle, var(--field-bubble-background)); color: var(--link-font-color); }
.dash-card-icon .ui-icon { width: 21px; height: 21px; }
.dash-card-copy { min-width: 0; }

/* Generic panel box (also defines the ems dashboard's box / box--rounded). */
.box            { background: var(--main-background); border: var(--main-border); padding: 18px 22px; margin-bottom: 24px; }
.box--rounded   { border-radius: var(--page-grid-border-radius); }

/* ems1 form look inside BOX-GROUPED crud edit/new forms (ems1 Content/main.css
   .edit-form): bold label ABOVE the input, one field per row with roomy spacing,
   comfortably padded inputs (text inputs cap at 250px, selects/textareas at 400px
   like ems1's custom-select). Scoped to .crud-form .box — the grouped-panels forms
   (loyalty Customer, ems Assignment) — so flat crud forms, dashboards, filters and
   index controls keep the shared inline-label style, in every page shell. */
.crud-form .box .field { margin: 0 0 1em; }
.crud-form .box .field:last-child { margin-bottom: 0; }
.crud-form .box .field > label { display: block; min-width: 0; padding: 0 0 3px; font-weight: bold; }
.crud-form .box .field input[type="text"],
.crud-form .box .field input[type="password"],
.crud-form .box .field input[type="number"],
.crud-form .box .field input[type="email"],
.crud-form .box .field input[type="date"] {
    width: 100%;
    max-width: 250px;
    padding: 7px;
    box-sizing: border-box;
}
.crud-form .box .field select,
.crud-form .box .field textarea {
    width: 100%;
    max-width: 400px;
    padding: 6px;
    box-sizing: border-box;
}

/* Declarative edit-page panels. crud_layout_cols() emits these only when an
   area's group names fields through {title,description,fields}; old anonymous
   groups retain their exact .box rendering. The baseline stays intentionally
   quiet so every shell remains usable, while Studio supplies the showcase skin. */
.form-panel { overflow: hidden; }
.form-panel-header { margin: -4px 0 18px; padding: 0 0 13px; border-bottom: var(--main-border); }
.form-panel-header h4 { margin: 0; color: var(--main-title-font-color); font-size: 16px; }
.form-panel-header p { margin: 5px 0 0; color: var(--banner-subtext); font-size: 13px; line-height: 1.45; }
.form-panel-body { min-width: 0; }
.form-panel--cols-2 .form-panel-body,
.form-panel--cols-3 .form-panel-body { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 18px; }
.form-panel--cols-3 .form-panel-body { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* A scalar select expressed as descriptive radio cards. The input remains a
   native radio for keyboard/screen-reader behavior and posts the same field. */
.choice-field { min-width: 0; margin: 0; padding: 0; border: 0; }
.choice-field > legend { display: block; width: 100%; margin: 0 0 4px; padding: 0; font-weight: bold; }
.choice-field > .hint { display: block; margin: 0 0 10px; }
.choice-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 9px; }
.choice-card { position: relative; display: flex; gap: 9px; min-width: 0; padding: 11px 12px;
               border: var(--input-border); border-radius: var(--page-grid-border-radius);
               background: var(--input-background); color: var(--input-font-color); cursor: pointer; }
.choice-card input { flex: 0 0 auto; margin: 3px 0 0; accent-color: var(--accent-background); }
.choice-card-copy { display: flex; min-width: 0; flex-direction: column; gap: 3px; }
.choice-card-copy strong { line-height: 1.25; }
.choice-card-copy small { color: var(--banner-subtext); font-size: 11px; line-height: 1.35; }
.choice-card:has(input:checked) { border-color: var(--accent-background); background: var(--accent-soft-background); }
.choice-card:focus-within { outline: 3px solid color-mix(in srgb, var(--focus-ring-color) 35%, transparent); outline-offset: 2px; }

/* Record-form controls take their COLOURS from the theme, like every other
   surface. They had none: the index/filter controls (.control input, above) read
   the tokens, but a crud form's own fields were left at the browser's defaults —
   white with black text, whatever the theme said. Invisible under the light theme,
   which is why it lasted; under a dark one the form stays a white rectangle, and a
   theme setting --input-font-color light would have written light text onto that
   white. Colours only: the border is left as the UA draws it, because switching it
   to var(--input-border) is a visible restyle rather than a theming fix. */
.crud-form .field input[type="text"],
.crud-form .field input[type="password"],
.crud-form .field input[type="number"],
.crud-form .field input[type="email"],
.crud-form .field input[type="date"],
.crud-form .field select,
.crud-form .field textarea {
    background-color: var(--input-background);
    color: var(--input-font-color);
}

/* KPI summary cards (ems dashboard). */
.kpi-row        { display: flex; flex-wrap: wrap; gap: var(--dash-gap, 16px); margin: 8px 0 24px; }

/* Single-line KPI summary (the app dashboards' status bar): the counts inline
   on one row. .kpi-alert tints a stat red when it demands attention (netops
   errors/open alerts). */
.kpi-line       { display: flex; flex-wrap: wrap; gap: 4px 32px; align-items: baseline; margin: 4px 0; }
.kpi-line a     { text-decoration: none; color: inherit; }
.kpi-line a:hover .kpi-label { text-decoration: underline; }
.kpi-line .kpi-num   { font-size: 20px; font-weight: 700; }
.kpi-line .kpi-label { color: var(--banner-subtext); margin-left: 6px; }
.kpi-line .kpi-alert .kpi-num, .kpi-line .kpi-alert .kpi-label { color: var(--status-failed-background); }
.kpi            { flex: 1; min-width: 160px; padding: 18px 22px; border: var(--main-border);
                  border-radius: var(--page-grid-border-radius); background: var(--main-background); }
.kpi-num        { font-size: 30px; font-weight: 700; line-height: 1; }
.kpi-label      { color: var(--banner-subtext); margin-top: 6px; }
.header--dashboard { font-size: var(--main-title-font-size, 20px); margin: 0 0 6px; }

/* SP-screen chrome (mfr exec screens). */
.dash-form      { margin: 12px 0; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* Filter-bar controls: consistent 4/8 rhythm padding so SP screens don't carry
   per-input inline styles (site-standards §5.1). Colours/borders inherit the
   framework input styles; widths are opt-in via .input-sm / .input-wide. */
.dash-form input,
.dash-form select { padding: 6px 8px; }
.dash-form button { padding: 6px 14px; cursor: pointer; }
.dash-form label  { display: inline-flex; gap: 4px; align-items: center; }
.input-sm         { min-width: 120px; }
.input-wide       { min-width: 220px; }
/* SP-screen page wrapper + section spacing (replaces inline padding-top/margin-top). */
.screen           { padding-top: 16px; }
.screen h2        { margin-top: 16px; }
.export-link      { margin-left: 8px; font-size: 13px; }
.dash-table     { border-collapse: collapse; width: 100%; font-size: var(--table-cell-font-size, 14px); }
.dash-table th  { text-align: left; border-bottom: 2px solid var(--table-header-background); padding: 4px 8px; }
.dash-table td  { border-bottom: 1px solid var(--field-bubble-background); padding: 4px 8px; }
.dash-note      { color: var(--banner-subtext); margin: 8px 0; }
.dash-error     { color: var(--status-failed-background); padding: 12px; }
.no-results     { color: var(--banner-subtext); }

/* Detail key/value cards (order/customer detail). */
.dash-detail-cards { display: flex; flex-wrap: wrap; gap: 16px; margin: 12px 0; }
.dash-detail-card  { border: var(--main-border); border-radius: var(--page-grid-border-radius); padding: 12px 16px; min-width: 240px; }
.dash-detail-card h3 { margin: 0 0 6px; }
.dash-kv th     { text-align: left; padding: 2px 10px 2px 0; color: var(--banner-subtext); font-weight: normal; }
.dash-kv td     { padding: 2px 0; }

/* A self-contained document embedded in a page at a fixed 16:9 — the ERP
   presentation player (erp.Presentation.watch). Sized by the wrapper so the
   <iframe> needs no width/height attributes and reflows on a phone. */
.embed-frame        { width: 100%; max-width: 1280px; aspect-ratio: 16 / 9; margin: 8px 0 16px;
                      border: var(--main-border); border-radius: var(--page-grid-border-radius);
                      overflow: hidden; background: var(--surface-subtle); }
.embed-frame iframe { display: block; width: 100%; height: 100%; border: 0; }
/* Stored plain text whose line breaks are part of it (a summary, a note). */
.pre-wrap           { white-space: pre-wrap; }

/* Numeric table cells: quantities and money read as a column when they line up on
   the right, and every screen that wanted that was reaching for an inline
   style="text-align:right" (docs/style-guide.md §0 forbids exactly that). Applies
   to a cell, not to text generally, so it cannot leak into a layout. */
th.num, td.num { text-align: right; }
th.nowrap, td.nowrap { white-space: nowrap; }
th.vtop, td.vtop { vertical-align: top; }
/* a form that lives inline in a table cell (per-row action buttons) */
form.inline { display: inline; }

/* Token-based text utilities (status/muted) — use instead of raw color hex. */
.txt-ok    { color: var(--status-success-background); }
.txt-err   { color: var(--status-failed-background); }
.txt-muted { color: var(--banner-subtext); }
a.kpi { text-decoration: none; color: inherit; display: block; }
a.kpi:hover { background: var(--field-bubble-background); }

/* Status table rows (loyalty2's tr.success/failed/alert — the dashboard
   sales-upload board and any other load/deadline status list). Bold cells on
   the theme status tokens; "normal" rows intentionally unstyled. The tr-level
   background + the .spreadsheet-scoped selectors matter: table.css (loaded
   later) sets `.spreadsheet tbody td { background-color: inherit; color: ... }`
   which ties/wins against a bare `tr.X td` — the scoped selector out-ranks it
   and the tr background is what `inherit` then resolves to. */
tr.success, tr.success td, .spreadsheet tbody tr.success td {
    font-weight: bold;
    color: var(--status-success-font-color);
    background-color: var(--status-success-background);
}
tr.failed, tr.failed td, .spreadsheet tbody tr.failed td {
    font-weight: bold;
    color: var(--status-failed-font-color);
    background-color: var(--status-failed-background);
}
tr.alert, tr.alert td, .spreadsheet tbody tr.alert td {
    font-weight: bold;
    color: var(--status-warning-font-color, inherit);
    background-color: var(--status-warning-background);
}

/* Shared CRUD headers also appear in embedded indexes on show/edit pages,
   whose shells do not load the spreadsheet-specific table.css. */
.table > .header {
    padding: 10px;
    background-color: var(--main-title-background);
    border-bottom: var(--main-border);
    color: var(--main-font-color);
    display: grid;
    grid-template-columns: auto 1fr auto auto auto auto;
    grid-template-areas: "title . buttons record-count pagination filter";
    align-items: center;
    gap: 10px;
}

/* An <h2>, not a <div>: a list page had no heading element anywhere, so a screen
   reader had nothing to navigate by while the sighted reader saw a title. The
   selector is by class and the tag carries no styling of its own here — margin and
   weight are reset so the swap is invisible to everyone who was already fine. h2
   rather than h1 because a page can carry several embedded tables. */
.table > .header > .title {
    grid-area: title;
    font-size: var(--main-title-font-size);
    color: var(--main-title-font-color);
    margin: 0;
    font-weight: normal;
}

.table > .header > .buttons { grid-area: buttons; }
.table > .header > .record-count {
    grid-area: record-count;
    padding: 6px 12px;
    background-color: var(--surface-raised, var(--main-background));
    border: var(--main-border);
    border-radius: 4px;
    font-size: 14px;
    color: var(--main-font-color);
}
.table > .header > .pagination { grid-area: pagination; }
.table > .header > .filter { grid-area: filter; }

.pagination .directions {
    display: flex;
    align-items: center;
}

.pagination .directions span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 3px;
    cursor: pointer;
    transition: background-color .2s ease;
}

.pagination .directions span:hover {
    background-color: var(--table-even-row-hover);
}

/* Card list view (crud_cards_html / crud_index "view"=>"cards", and direct
   callers like the search page). Stylable via the theme tokens; empty optional
   slots collapse. The standard card markup lives in template/card-template.html. */
.crud-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 1rem; }
.crud-cards-head { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; margin: 0 0 .75rem; }
.crud-cards-head h3 { margin: 0; }
.crud-cards-count { color: var(--banner-subtext); font-size: .85rem; }
.crud-card { border: var(--field-bubble-border); border-radius: var(--page-grid-border-radius);
             overflow: hidden; background: var(--main-background); display: flex; flex-direction: column; }
.crud-card-img { height: 150px; background: var(--field-bubble-background) center/contain no-repeat; }
.crud-card-body { padding: .6rem .7rem; display: flex; flex-direction: column; gap: .25rem; flex: 1 1 auto; }
.crud-card-eyebrow { font-size: .72rem; text-transform: uppercase; letter-spacing: .03em; color: var(--banner-subtext); }
.crud-card-title { font-size: .92rem; font-weight: 600; line-height: 1.25; }
.crud-card-title a { text-decoration: none; color: inherit; }
.crud-card-title a:hover { text-decoration: underline; }
.crud-card-accent { font-weight: 600; }
.crud-card-accent .sale { color: var(--status-success-background); }
.crud-card-accent .was { color: var(--banner-subtext); text-decoration: line-through; font-weight: 400; margin-left: .4rem; }
.crud-card-text { font-size: .78rem; color: var(--page-font-color); max-height: 3.2em; overflow: hidden; margin: 0; }
.crud-card-meta { margin-top: auto; font-size: .7rem; color: var(--banner-subtext);
                  display: flex; justify-content: space-between; gap: .5rem; flex-wrap: wrap; }
.crud-card-eyebrow:empty, .crud-card-title:empty, .crud-card-accent:empty,
.crud-card-text:empty, .crud-card-meta:empty { display: none; }
.crud-badge { display: inline-block; font-size: .62rem; padding: .05rem .35rem; border-radius: 4px;
              background: var(--status-success-background); color: var(--status-success-font-color); }

/* Edit page title + header buttons (ems1 request.edit: h1 + View) */
.page-header { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 0 0 16px; }
.page-header h3 { margin: 0; }
/* Which record this page is editing (crud_record_ident), adjacent to the
   heading and weighted as secondary. It cannot be nested in the localized h3:
   the client language pass replaces that element's text after page load. */
.page-header .record-ident { font-weight: normal; opacity: .7; }
.record-header { align-items: flex-start; }
.record-header-copy { min-width: 0; flex: 1 1 360px; }
.record-header-copy h3 { line-height: 1.2; }
.record-lede { max-width: 720px; margin: 7px 0 0; color: var(--banner-subtext); line-height: 1.45; }
.record-header-meta { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.status-pill { display: inline-flex; align-items: center; min-height: 26px; padding: 2px 10px;
               border: var(--badge-border); border-radius: 999px; background: var(--badge-background);
               color: var(--badge-font-color); font-size: 12px; font-weight: 700; }
.status-pill::before { width: 7px; height: 7px; margin-right: 7px; border-radius: 50%;
                       background: currentColor; content: ""; }
.status-pill--success { background: var(--status-success-background); color: var(--status-success-font-color); border-color: transparent; }
.status-pill--warning { background: var(--status-warning-background); color: var(--status-warning-font-color); border-color: transparent; }
.status-pill--danger { background: var(--status-failed-background); color: var(--status-failed-font-color); border-color: transparent; }

@media (max-width: 700px) {
    .form-panel--cols-2 .form-panel-body,
    .form-panel--cols-3 .form-panel-body { grid-template-columns: 1fr; }
}

/* Keep standalone POST actions alongside the record navigation buttons. */
.edit-actions > form {display:inline-flex;width:auto;margin:0;padding:0;vertical-align:middle}

/* Selection controls shared by standard and custom CRUD cards. */
.crud-card-selection { display:flex; align-items:center; gap:8px; padding:8px; }
.crud-card-select-all { display:inline-flex; align-items:center; gap:6px; }

/* Shared forkable actions: button/run summary and record progress slots. */
.process-dialog { color:var(--main-font-color); background:var(--main-background); border:var(--main-border); border-radius:var(--page-grid-border-radius); max-width:650px; width:calc(100% - 48px); max-height:85vh; padding:24px; }
.process-dialog::backdrop { background:color-mix(in srgb,var(--page-font-color) 45%,transparent); }
.process-dialog [hidden] { display:none; }
.process-dialog .button.section { display:flex; gap:8px; margin-top:16px; }
.process-runs { display:block; padding:0 8px; }
.process-runs > .process-status { border-bottom:var(--main-border); }
.process-runs .process-summary { flex-basis:auto; max-width:500px; }
.process-status { display:flex; flex-wrap:wrap; align-items:center; gap:8px; padding:8px 0; }
.process-summary { display:block; flex-basis:100%; }
.process-status progress { width:120px; height:12px; }
.process-record-status { font-size:13px; }
.process-runs details { margin:8px 0; }
