/* App shell: the only scroll container is .content (MainLayout), which sits in a 100vh flex column.
   The page itself must never scroll — FluentDesignTheme and the toast/tooltip providers render as
   extra elements after the layout in <body>, and their line boxes push the document past 100vh,
   which shows up as a second scrollbar next to .content's. */
html, body {
    height: 100%;
    overflow: hidden;
}

/* Breadcrumb spacing on "bare" pages (crumb sits directly in .content, no flex-gap
   wrapper). Gap-host pages nest the crumb inside .set-page/.sd-page/.bua and get
   spacing from that container's `gap`, so they are intentionally not matched here. */
.content > .pg-crumbs {
    margin-bottom: var(--space-md);
}

/* ==========================================================================
   Site Detail (and shared detail-tab) styles.
   Global (NOT scoped) on purpose: SiteDetail + SiteAssetsTab + SiteEmployeesTab
   all consume the same table / pill / card classes, and Blazor scoped CSS does
   not cross component boundaries. Prefix: .sd-
   ========================================================================== */

/* White container card that wraps the whole detail page (gray canvas shows as margin). */
.sd-shell {
    background: var(--color-primary-surface);
    border: 1px solid var(--color-text-base-border);
    border-radius: var(--radius-card);
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.05);
    padding: 24px 28px;
}

.sd-page { display: flex; flex-direction: column; gap: 20px; }

/* ---- Breadcrumb ---- */
.sd-crumbs {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    font-size: var(--font-size-caption);
    color: var(--color-text-base-placeholder-text);
}

.sd-crumbs a { color: var(--color-text-base-description-icon-form); text-decoration: none; }
.sd-crumbs a:hover { color: var(--color-text-base-link); text-decoration: underline; }
.sd-crumbs .sd-crumb-sep { color: var(--color-text-base-button-cancel); }
.sd-crumbs .sd-crumb-current { color: var(--color-neutral-description-icon-form-divider); font-weight: var(--font-weight-semibold); }

/* ---- Title row ---- */
.sd-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
}

.sd-title { margin: var(--space-0); font-size: var(--font-size-heading); font-weight: var(--font-weight-bold); color: var(--color-neutral-title-content); }

.sd-head__meta { display: inline-flex; align-items: center; gap: 12px; }

.sd-last-activity {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: var(--radius-pill);
    background: var(--color-primary-surface);
    border: 1px solid var(--color-text-base-border);
    font-size: var(--font-size-caption);
    color: var(--color-neutral-description-icon-form-divider);
    font-weight: var(--font-weight-semibold);
}
.sd-last-activity .sd-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--color-text-base-placeholder-text); }

/* ---- Info strip (code / province / people) ---- */
.sd-info-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 36px;
}

.sd-field__label {
    font-size: var(--font-size-label);
    color: var(--color-text-base-placeholder-text);
    font-weight: var(--font-weight-semibold);
    margin-bottom: var(--space-xs);
}
.sd-field__value { font-size: var(--font-size-body); color: var(--color-neutral-title-content); font-weight: var(--font-weight-semibold); }
.sd-field__label--required::after { content: ' *'; color: var(--color-status-error); }

/* ---- SiteForm: two <select>s composing "HH:mm-HH:mm" ---- */
.sd-hours { display: flex; align-items: center; gap: var(--space-sm); min-width: 0; }
.sd-hours .sd-input { width: auto; min-width: 0; flex: 1 1 0; }
/* The two time pickers are PecSearchableSelect now, not bare <select class="sd-input">, so the
   rule above no longer reaches them — its selector matched a class the migration removed. Their
   flex item is _FieldFrame's wrapper (PecSearchableSelect renders INSIDE it), so target every
   direct child except the "-" separator rather than a component-specific class. Without this each
   picker falls back to `flex: 0 1 auto` and shrinks to its content (~42px, measured, vs the 190px
   its grid neighbours get). */
.sd-hours > *:not(.sd-hours__sep) { min-width: 0; flex: 1 1 0; }
.sd-hours__sep { color: var(--color-text-base-placeholder-text); flex: 0 0 auto; }

.sd-people-pill {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 10px 16px;
    border-radius: var(--radius-input);
    background: var(--color-text-base-background-soft);
    border: 1px solid var(--color-blue-200);
    color: var(--color-primary-primary);
    font-weight: var(--font-weight-semibold);
    font-size: var(--font-size-tag);
}

/* ---- Overview: site photo + stat cards + responsible card ---- */
.sd-overview {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    gap: var(--space-md);
}
@media (max-width: 900px) { .sd-overview { grid-template-columns: 1fr; } }

/* Site photo — sits beside the project-info fields. */
.sd-photo-panel { display: flex; flex-direction: column; gap: var(--space-sm); }
.sd-photo-panel .sd-btn { justify-content: center; cursor: pointer; }

.sd-photo-box {
    /* Fixed 16:9 frame: the box never reflows to the image, so a portrait upload and a
       landscape one occupy the same slot (the image itself is cover-cropped). */
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius-button);
    border: 1px solid var(--color-text-base-border);
    /* Light fill so a transparent PNG stays visible instead of blending into a dark box. */
    background: var(--color-primary-surface);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.sd-photo-img { width: 100%; height: 100%; object-fit: cover; }

/* Project-info card: photo column beside the field grid (roughly the 46/54 split of the design).
   min-width:0 on the grid so long values wrap instead of pushing the photo out. */
.sd-project { display: grid; grid-template-columns: minmax(0, 46fr) minmax(0, 54fr); gap: var(--space-lg); align-items: start; }
@media (max-width: 900px) { .sd-project { grid-template-columns: 1fr; } }

/* The map row and the operations note sit full-width UNDER that split. */
.sd-maprow { display: flex; flex-direction: column; gap: var(--space-xs); margin-top: 18px; }
.sd-maprow__label { font-size: var(--font-size-label); color: var(--color-text-base-placeholder-text); }
.sd-maprow__control { display: flex; gap: var(--space-sm); align-items: center; }
.sd-maprow__input { flex: 1; min-width: 0; }
/* 42px, not the sd-btn default 40px, so the button lines up with the input it sits next to. */
.sd-maprow__copy { height: 42px; flex: 0 0 auto; white-space: nowrap; }

.sd-map-link { display: inline-flex; align-items: center; gap: var(--space-xs); }

/* SiteForm has no photo panel, so its card body is a single column. */
.sd-form-col { display: flex; flex-direction: column; gap: var(--space-md); }

.sd-overview__right { display: flex; flex-direction: column; gap: var(--space-md); }

.sd-stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 12px;
}
@media (max-width: 560px) { .sd-stats { grid-template-columns: repeat(2, 1fr); } }

.sd-stat-card {
    background: var(--color-blue-100);
    border: 1px solid transparent;
    border-radius: var(--radius-button);
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04);
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    position: relative;
}
.sd-stat-card__num { font-size: var(--font-size-summary); font-weight: var(--font-weight-extrabold); color: var(--color-neutral-title-content); line-height: 1; }
.sd-stat-card__label { font-size: var(--font-size-label); color: var(--color-text-base-placeholder-text); font-weight: var(--font-weight-semibold); }
.sd-stat-card__icon {
    position: absolute;
    top: 12px;
    right: 12px;
    color: var(--color-text-base-placeholder-text);
}

.sd-contact-card {
    background: var(--color-component-card-bg);
    border: 1px solid var(--color-text-base-border);
    border-radius: var(--radius-button);
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04);
    padding: 14px 16px;
}
.sd-contact-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}
.sd-contact-card__title { font-size: var(--font-size-label); font-weight: var(--font-weight-bold); color: var(--color-neutral-title-content); }
.sd-contact-card__line { font-size: var(--font-size-body); color: var(--color-text-base-description-icon-form); margin-top: 2px; }

.sd-person {
    border: 1px solid var(--color-text-base-border);
    border-radius: var(--radius-input);
    padding: 10px 12px;
}
.sd-person + .sd-person { margin-top: var(--space-sm); }
.sd-person--primary { background: var(--color-text-base-background-soft); border-color: var(--color-navy-blue-100); }
.sd-person__name { font-size: var(--font-size-body); font-weight: var(--font-weight-bold); color: var(--color-neutral-title-content); }
.sd-person__line { font-size: var(--font-size-body); color: var(--color-text-base-description-icon-form); margin-top: 2px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sd-person__contact { margin-left: var(--space-sm); color: var(--color-primary-primary); font-weight: var(--font-weight-semibold); }

/* ---- Card (white panel) ---- */
.sd-card {
    background: var(--color-component-card-bg);
    border: 1px solid var(--color-text-base-border);
    border-radius: var(--radius-button);
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04);
}
.sd-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px;
}
.sd-card__title { margin: var(--space-0); font-size: var(--font-size-header-card); font-weight: var(--font-weight-bold); color: var(--color-neutral-title-content); }
.sd-card__body { padding: 0 20px 20px; }
/* Bare cards (no __head/__body) that need their own inner padding + vertical rhythm — sections 1 &
   3 on the detail page. Flex column with gap restores the spacing the old .sd-page wrapper gave. */
.sd-card--pad { padding: 20px 24px; display: flex; flex-direction: column; gap: 20px; }

/* ---- Project info grid ---- */
.sd-infogrid {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 18px 24px;
}
.sd-infogrid--form {
    grid-template-columns: repeat(2, minmax(0, 1fr)) minmax(0, 2fr) minmax(0, 1fr);
}
/* Detail page: three columns beside the photo (the form variant keeps its own four). */
.sd-infogrid--detail { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.sd-field--span2 { grid-column: span 2; }
.sd-field--span3 { grid-column: span 3; }
@media (max-width: 900px) {
    .sd-infogrid--detail { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .sd-field--span2, .sd-field--span3 { grid-column: span 2; }
}
@media (max-width: 900px) { .sd-infogrid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 900px) { .sd-infogrid--form { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.sd-remark {
    margin-top: 18px;
    padding: 14px 16px;
    background: var(--color-text-base-background);
    border: 1px solid var(--color-status-pending-vbright);
    border-radius: var(--radius-input);
}
.sd-remark__label { font-size: var(--font-size-label); color: var(--color-text-base-placeholder-text); font-weight: var(--font-weight-semibold); margin-bottom: var(--space-xs); }
/* Free text typed by site staff: keep their line breaks, and break mid-word when a single token
   (a pasted URL, a run of Thai without spaces) is wider than the box — otherwise it runs off the card. */
.sd-remark__text { font-size: var(--font-size-body); color: var(--color-neutral-description-icon-form-divider); line-height: 1.5;
    white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; }

/* ---- Buttons ---- */
.sd-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 40px;
    padding: 0 18px;
    font-size: var(--font-size-button);
    font-weight: var(--font-weight-semibold);
    border-radius: var(--radius-lg);
    border: 1px solid transparent;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
}
.sd-btn--ghost { background: var(--color-text-base-background-soft); color: var(--color-primary-primary); border-color: var(--color-navy-blue-100); }
.sd-btn--ghost:hover:not(:disabled) { background: var(--color-primary-primary-very-bright); }
/* Filled pale-blue action, borderless — the card-header "add" affordance in the site design. */
.sd-btn--soft { background: var(--color-navy-blue-100); color: var(--color-primary-primary); }
.sd-btn--soft:hover:not(:disabled) { background: var(--color-navy-blue-200); }
.sd-btn--navy { background: var(--color-navy-blue-900); color: var(--color-text-base-white-text); }
.sd-btn--navy:hover:not(:disabled) { background: var(--color-neutral-title-content); }
.sd-btn--link {
    height: auto;
    padding: 6px 12px;
    background: var(--color-semantic-extra-highlight-bg);
    color: var(--color-semantic-extra-highlight-text);
    border-color: var(--color-orange-200);
}
.sd-btn:disabled { opacity: 0.6; cursor: not-allowed; }

/* ---- Tabs ---- */
.sd-tabs {
    display: flex;
    align-items: center;
    gap: 0;
    border-bottom: 1px solid var(--color-text-base-border);
}
.sd-tab {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 13px 24px;
    font-size: var(--font-size-base);
    color: var(--color-text-base-placeholder-text);
    background: none;
    border: none;
    border-bottom: 3px solid transparent;
    cursor: pointer;
    margin-bottom: -1px;
}
.sd-tab:hover { color: var(--color-neutral-description-icon-form-divider); }
/* Selected tab (Figma): soft-blue fill + navy bold text + 3px red underline. */
.sd-tab--active {
    background: var(--color-text-base-background-soft);
    color: var(--color-primary-navigation-bg);
    font-weight: var(--font-weight-bold);
    border-bottom-color: var(--color-red-700);
}
/* Mobile-only: a tab row with several icon+label tabs (InstanceCreate.razor: up to 5) doesn't fit
   a 375px viewport. Scroll it horizontally instead of clipping — additive, mobile-scoped only, so
   desktop's tab strip (SiteDetail.razor / MaterialLotDetail.razor / InstanceCreate.razor) is
   byte-identical above this breakpoint. */
@media (max-width: 768px) {
    .sd-tabs { overflow-x: auto; flex-wrap: nowrap; }
    .sd-tab { flex: 0 0 auto; white-space: nowrap; }
}

/* ---- Toolbar above tab content ---- */
.sd-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}
.sd-toolbar__title { margin: var(--space-0); font-size: var(--font-size-summary); font-weight: var(--font-weight-bold); color: var(--color-neutral-title-content); }

.sd-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
}
.sd-filter { display: flex; flex-direction: column; gap: var(--space-xs); }
.sd-filter--grow { flex: 1 1 320px; min-width: 220px; }
.sd-filter--status { flex: 0 0 220px; }
.sd-filter__label { font-size: var(--font-size-label); color: var(--color-text-base-placeholder-text); font-weight: var(--font-weight-semibold); }
.sd-input {
    height: 42px;
    padding: 0 14px;
    font-size: var(--font-size-input);
    color: var(--color-neutral-title-content);
    background: var(--color-primary-surface);
    border: 1px solid var(--color-text-base-button-cancel);
    border-radius: var(--radius-lg);
    outline: none;
    box-sizing: border-box;
    width: 100%;
}
/* Multi-line inputs: .sd-input's single-line 42px height + zero vertical padding would crush a
   textarea to one line with its text pinned against the top edge. Height follows `rows` instead. */
textarea.sd-input {
    height: auto;
    padding: 10px 14px;
    line-height: 1.5;
    resize: vertical;
}
.sd-input::placeholder { color: var(--color-text-base-placeholder-text); }
/* readonly inputs read as non-editable (subtle grey), mirroring the vendor .vd-input[readonly] pattern */
.sd-input[readonly], .sd-input:disabled { background: var(--color-text-base-disabled-bg); color: var(--color-text-base-description-icon-form); cursor: default; }
.sd-input--preview { color: var(--color-text-base-placeholder-text); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .02em; }
.sd-input:focus { border-color: var(--color-primary-primary); box-shadow: var(--shadow-active-state); }
.sd-input--invalid, .sd-input--invalid:focus { border-color: var(--color-status-error); box-shadow: none; }
.cust-field__error { margin-top: var(--space-xs); font-size: var(--font-size-label); color: var(--color-status-error); }
/* Required marker — the asterisk is decoration, so it comes from CSS (red) and not from the label text. */
.cust-field__label--required::after { content: ' *'; color: var(--color-status-error); }
.sd-select {
    cursor: pointer;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748B' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    padding-right: var(--space-xl);
}

/* DateInput renders a Fluent text field.  Keep the Fluent shadow-root box as the single visible
   input; otherwise .sd-input styles the host as a second box around it. */
fluent-text-field.sd-input {
    display: block;
    width: 100%;
    height: 42px;
    min-height: 0;
    box-sizing: border-box;
    padding: 0;
    background: transparent;
    border: none;
    --accent-fill-rest: transparent;
    --accent-fill-hover: transparent;
    --accent-fill-active: transparent;
    --accent-fill-focus: transparent;
    color: var(--color-text-base-description-icon-form);
}
fluent-text-field.sd-input::part(root) {
    width: 100%;
    height: 42px;
    box-sizing: border-box;
    background: var(--color-primary-surface);
    border: 1px solid var(--color-text-base-button-cancel);
    border-radius: var(--radius-lg);
    font-size: var(--font-size-input);
    color: var(--color-neutral-title-content);
}
fluent-text-field.sd-input:focus-within::part(root) {
    border-color: var(--color-primary-primary);
}
fluent-text-field.sd-input::part(control) {
    flex: 1 1 auto;
    width: 100%;
    min-width: 0;
    font-size: inherit;
    color: inherit;
    /* Match .sd-input's 14px gutter — Fluent's default control padding is narrower, which left the
       date text out of line with every sibling input in the same grid. */
    padding: 0 14px;
}

/* ---- Detail table (navy header, red left accent) ---- */
.sd-table-card {
    background: var(--color-component-card-bg);
    border: 1px solid var(--color-text-base-border);
    border-radius: var(--radius-button);
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04);
    overflow: hidden;
}
.sd-table-card__head { padding: 18px 20px 12px; }
.sd-table-card__head--split { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm); }
.sd-table-card__title { margin: var(--space-0); font-size: var(--font-size-header-card); font-weight: var(--font-weight-bold); color: var(--color-neutral-title-content); }
.sd-table-card__count { margin-top: 2px; font-size: var(--font-size-caption); color: var(--color-text-base-placeholder-text); }
/* The card itself has no padding (the table runs edge to edge), so a filter row inside it carries
   its own gutters. */
.sd-table-card__filters { padding: 0 20px 16px; }
/* Nested in a padded card (the site-detail tab panels), the table is no longer its own card: drop
   the chrome and the gutters so it sits flush inside the surrounding card's padding. */
.sd-card .sd-table-card { border: none; box-shadow: none; background: transparent; border-radius: 0; overflow: visible; }
.sd-card .sd-table-card__head { padding: 0 0 12px; }
.sd-card .sd-table-card__filters { padding: 0 0 16px; }
/* Without the card clipping it, the table rounds its own corners (the dark header reads as a bar). */
.sd-card .sd-table__scroll { border: 1px solid var(--color-text-base-border); border-radius: var(--radius-button); }
/* The empty panel carries side margins for the edge-to-edge card; flush inside one, they read as a
   double gutter. */
.sd-card .sd-doc-empty { margin-left: var(--space-0); margin-right: var(--space-0); }

.sd-table__scroll { overflow-x: auto; }

.sd-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--font-size-table-line);
}
.sd-table__empty { text-align: center; padding: 28px 16px; color: var(--color-text-base-placeholder-text); }
.sd-doc-empty { display: flex; flex-direction: column; align-items: center; gap: 12px;
    padding: 40px 16px; margin: 16px 20px; border: 1px dashed var(--color-text-base-border); border-radius: var(--radius-button);
    background: var(--color-neutral-background); }
.sd-doc-empty__icon { width: 56px; height: 56px; border-radius: 50%; background: var(--color-text-base-disabled-bg);
    display: flex; align-items: center; justify-content: center; }
.sd-doc-empty__text { font-size: var(--font-size-body); color: var(--color-text-base-description-icon-form); }.sd-table thead th {
    background: var(--color-navy-blue-900);
    color: var(--color-text-base-white-text);
    font-weight: var(--font-weight-semibold);
    text-align: left;
    padding: 13px 16px;
    white-space: nowrap;
}
.sd-table thead th:first-child {
    border-left: 3px solid var(--color-status-error);
}
.sd-table tbody td {
    padding: 14px 16px;
    border-bottom: 1px solid var(--color-text-base-disabled-bg);
    color: var(--color-neutral-description-icon-form-divider);
    vertical-align: middle;
}
.sd-table tbody tr:last-child td { border-bottom: none; }
.sd-table tbody tr:nth-child(even) { background: var(--color-neutral-background); }   /* zebra striping */
.sd-table tbody tr:hover { background: var(--color-text-base-disabled-bg); }             /* hover wins (declared after zebra) */

/* Asset-note search: one full-width field with a leading magnifier, above the note table. */
.sd-asset-search { position: relative; padding: 0 20px 14px; }
.sd-asset-search__icon {
    position: absolute;
    left: 32px;
    top: 12px;
    color: var(--color-text-base-placeholder-text);
    pointer-events: none;
}
.sd-asset-search__input { width: 100%; padding-left: 36px; }

/* Site photo gallery: a tinted panel inset inside the asset-notes card, below the note table.
   Square thumbnails followed by a dashed upload tile of the same size. */
.sd-gallery-block {
    margin: 8px 20px 20px;
    padding: 16px;
    background: var(--color-navy-blue-50);
    border-radius: var(--radius-button);
}
.sd-gallery-block__head { padding-bottom: 12px; }
.sd-gallery-block__title { margin: var(--space-0); font-size: var(--font-size-header-card); font-weight: var(--font-weight-bold); color: var(--color-neutral-title-content); }
.sd-gallery-block__count { margin-left: var(--space-sm); font-size: var(--font-size-caption);
    font-weight: var(--font-weight-regular); color: var(--color-text-base-placeholder-text); }
.sd-gallery-block__hint { margin-top: 2px; font-size: var(--font-size-caption); color: var(--color-text-base-placeholder-text); }
.sd-gallery { padding: 0; position: relative; }
/* One scrolling row, not a wrapping grid: the card keeps a fixed height however many photos exist. */
.sd-gallery__grid { display: flex; flex-wrap: nowrap; gap: 12px; overflow-x: auto; scroll-behavior: smooth;
    scrollbar-width: thin; padding-bottom: 4px; }
.sd-gallery__thumb, .sd-gallery__drop { flex: 0 0 auto; }
.sd-gallery__arrow {
    position: absolute; top: 46px; transform: translateY(-50%); z-index: 2;
    width: 32px; height: 32px;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--color-text-base-border); border-radius: 50%;
    background: var(--color-primary-surface); color: var(--color-primary-primary);
    font-size: 20px; line-height: 1; cursor: pointer;
    box-shadow: 0 2px 8px rgba(15, 23, 42, .12);
}
.sd-gallery__arrow:disabled { opacity: .35; cursor: default; }
.sd-gallery__arrow--prev { left: -12px; }
.sd-gallery__arrow--next { right: -12px; }
.sd-gallery__thumb {
    position: relative;
    width: 104px; height: 104px;
    border: 1px solid var(--color-text-base-border);
    border-radius: var(--radius-button);
    overflow: hidden;
    background: var(--color-primary-surface);
}
.sd-gallery__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sd-gallery__remove {
    position: absolute; top: 4px; right: 4px;
    width: 22px; height: 22px;
    display: flex; align-items: center; justify-content: center;
    border: none; border-radius: 50%;
    background: rgba(15, 23, 42, 0.6);
    color: var(--color-text-base-white-text);
    cursor: pointer;
}
.sd-gallery__remove:disabled { opacity: 0.5; cursor: default; }
/* The native control is replaced by the label tile, but must stay focusable for keyboard users —
   so it is transparent and stretched over the tile rather than parked off-layout. */
.sd-gallery__input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.sd-gallery__drop {
    position: relative;
    width: 104px; height: 104px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
    border: 1px dashed var(--color-navy-blue-200);
    border-radius: var(--radius-button);
    background: var(--color-primary-surface);
    font-size: var(--font-size-caption);
    color: var(--color-primary-primary);
    cursor: pointer;
    text-align: center;
}

.sd-col-action { width: 96px; text-align: right; white-space: nowrap; }
.sd-col-check { width: 44px; text-align: center; }
.sd-col-check input { width: 16px; height: 16px; accent-color: var(--color-primary-primary); cursor: default; }

.sd-asset-name { font-weight: var(--font-weight-semibold); color: var(--color-neutral-title-content); }
.sd-asset-sub {
    margin-top: 2px;
    font-size: var(--font-size-label);
    font-weight: var(--font-weight-semibold);
    color: var(--color-status-error);
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}
.ab-branch-badge {
    font-size: 0.75rem;
    color: var(--color-status-error);
    margin-top: 2px;
}
/* Chip picker — a short, flat set of options laid out as tap targets instead of a <select>. */
.sd-chips { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.sd-chip {
    padding: 7px 16px;
    border: 1px solid var(--color-text-base-border);
    border-radius: 999px;
    background: var(--color-primary-surface);
    color: var(--color-neutral-title-content);
    font-size: var(--font-size-button);
    cursor: pointer;
}
.sd-chip:hover { border-color: var(--color-primary-primary); }
.sd-chip--on {
    background: var(--color-navy-blue-100);
    border-color: var(--color-primary-primary);
    color: var(--color-primary-primary);
    font-weight: var(--font-weight-semibold);
}

/* Table chips are labels, not controls: smaller, no pointer, no hover affordance. */
.sd-chip--static { padding: 3px 10px; font-size: var(--font-size-caption); cursor: default; }
.sd-chip--static:hover { border-color: var(--color-text-base-border); }
.sd-chip--static.sd-chip--on:hover { border-color: var(--color-primary-primary); }
/* Source BU, shown after the source chip as a quieter neutral one. */
.sd-asset-srcbu { margin-left: var(--space-sm); background: var(--color-text-base-disabled-bg);
    color: var(--color-text-base-description-icon-form); }
.sd-cell-muted { color: var(--color-text-base-description-icon-form); }
.sd-cell-empty { color: var(--color-text-base-button-cancel); }
.sd-cell-mono { font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; color: var(--color-neutral-description-icon-form-divider); }

.sd-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-text-base-border);
    background: var(--color-primary-surface);
    cursor: pointer;
}
.sd-icon-btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* ---- Status pill ---- */
.sd-status {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 5px 12px;
    border-radius: var(--radius-pill);
    font-size: var(--font-size-status);
    font-weight: var(--font-weight-semibold);
    line-height: 1;
    white-space: nowrap;
}
.sd-status .sd-status-dot { width: 7px; height: 7px; border-radius: 50%; }

.sd-status--green  { background: var(--color-green-50); color: var(--color-status-success); }
.sd-status--green  .sd-status-dot { background: var(--color-status-success); }
.sd-status--amber  { background: var(--color-semantic-extra-warning-bg); color: var(--color-semantic-extra-highlight-text); }
.sd-status--amber  .sd-status-dot { background: var(--color-status-waiting); }
.sd-status--red    { background: var(--color-component-feedback-card-bg); color: var(--color-status-error); }
.sd-status--red    .sd-status-dot { background: var(--color-component-button-danger-bg); }
.sd-status--purple { background: var(--color-navy-blue-50); color: var(--color-status-pending); }
.sd-status--purple .sd-status-dot { background: var(--color-status-pending); }
.sd-status--blue   { background: var(--color-component-reward-card-bg); color: var(--color-primary-primary); }
.sd-status--blue   .sd-status-dot { background: var(--color-component-button-primary-bg); }
.sd-status--grey   { background: var(--color-text-base-disabled-bg); color: var(--color-text-base-description-icon-form); }
.sd-status--grey   .sd-status-dot { background: var(--color-text-base-placeholder-text); }

/* ---- Pager ---- */
.sd-pager {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    flex-wrap: wrap;
    padding: 16px 20px;
}
.sd-page-btn {
    min-width: 34px;
    height: 34px;
    padding: 0 var(--space-sm);
    font-size: var(--font-size-caption);
    font-weight: var(--font-weight-semibold);
    color: var(--color-neutral-description-icon-form-divider);
    background: var(--color-primary-surface);
    border: 1px solid var(--color-text-base-border);
    border-radius: var(--radius-lg);
    cursor: pointer;
}
.sd-page-btn--active { background: var(--color-component-button-primary-bg); border-color: var(--color-primary-primary); color: var(--color-text-base-white-text); cursor: default; }
.sd-page-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.sd-page-ellipsis { padding: 0 var(--space-xs); color: var(--color-text-base-placeholder-text); }
.sd-pager__size {
    position: absolute;
    right: 20px;
    top: 50%;
    transform: translateY(-50%);
    font-size: var(--font-size-caption);
    color: var(--color-text-base-description-icon-form);
}
/* The size picker sits inside the size slot, so it must not stretch to the slot's full width. */
.sd-pager__size .sd-select { width: auto; min-width: 150px; padding-top: 6px; padding-bottom: 6px; }
@media (max-width: 720px) { .sd-pager__size { position: static; transform: none; width: 100%; text-align: center; } }

/* Sortable column header — a button that inherits the header cell's type so it reads as the label,
   not as a control sitting inside it. */
.sd-th-sort {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    background: none;
    border: none;
    padding: var(--space-0);
    cursor: pointer;
    font: inherit;
    color: inherit;
}
.sd-th-sort__arrows { font-size: var(--font-size-caption); opacity: 0.75; }

/* ---- Empty / loading state ---- */
.sd-state {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: var(--space-2xl) 0;
    color: var(--color-text-base-placeholder-text);
    font-size: var(--font-size-body);
}

/* ===== Employee list + status badge ===== */
.page-title { font-size: var(--font-size-title); font-weight: var(--font-weight-semibold); margin: 0 0 var(--space-md); color: var(--color-neutral-title-content); }

.filter-input { flex: 1 1 180px; min-width: 160px; height: 38px; padding: 0 .75rem;
    border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg); font-size: var(--font-size-body); background: var(--color-primary-surface); }
.filter-select { flex: 0 0 160px; }
.btn { display: inline-flex; align-items: center; gap: .4rem; height: 38px; padding: 0 var(--space-md);
    border: none; border-radius: var(--radius-lg); font-size: var(--font-size-button); font-weight: var(--font-weight-medium); cursor: pointer; text-decoration: none; }
.btn-primary { background: var(--color-navy-blue-900); color: var(--color-text-base-white-text); }
.btn-create { background: var(--color-blue-100); color: var(--color-navy-blue-900); }
.btn-create:hover, .btn-create:focus, .btn-create:visited { color: var(--color-navy-blue-900); }
.btn-create:disabled { opacity: .55; cursor: default; }
.btn--danger { background: var(--color-component-button-danger-bg); color: var(--color-text-base-white-text); }
.btn--danger:hover { background: var(--color-component-button-danger-hover); }
.btn--danger:disabled { opacity: .55; cursor: default; }

.emp-allbus { display: inline-flex; align-items: center; gap: .4rem; font-size: var(--font-size-caption); color: var(--color-neutral-description-icon-form-divider); cursor: pointer; }

.col-check { width: 36px; }
.col-actions { width: 110px; text-align: center; }
.list-table tbody td.col-actions { text-align: center; }
/* Hover target wrapping a disabled action — a disabled button gets no mouse events itself. */
.action-group > span, .btn-hover-wrap { display: inline-flex; }
.cell-mono { font-family: ui-monospace, monospace; color: var(--color-neutral-description-icon-form-divider); }
.cell-muted { color: var(--color-text-base-description-icon-form); }

.action-group { display: flex; gap: .35rem; justify-content: center; align-items: center; }
.icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: var(--radius-pill);
    border: 1px solid var(--color-text-base-border); background: var(--color-blue-100); cursor: pointer; }
.icon-btn:disabled { opacity: .5; cursor: default; }

.emp-status { display: inline-flex; align-items: center; gap: .4rem; padding: 4px 12px;
    border-radius: var(--radius-pill); font-size: var(--font-size-status); font-weight: var(--font-weight-medium); width: 75px;}
.emp-status--active { background: var(--color-status-success-vbright); color: var(--color-green-700); }
.emp-status--inactive { background: var(--color-text-base-disabled-bg); color: var(--color-text-base-description-icon-form); }
.emp-status--suspended { background: var(--color-semantic-extra-warning-bg); color: var(--color-semantic-extra-highlight-text); }
.emp-status--leavewithoutpay { background: var(--color-blue-100); color: var(--color-blue-700); }
.emp-status--other { background: var(--color-status-pending-vbright); color: var(--color-semantic-extra-purple-accent-text); }
.emp-status-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

.page-btn { min-width: 32px; height: 32px; border: 1px solid var(--color-text-base-border); border-radius: var(--radius-md);
    background: var(--color-primary-surface); cursor: pointer; font-size: var(--font-size-caption); color: var(--color-neutral-description-icon-form-divider); }
.page-btn--active { background: var(--color-component-button-primary-bg); color: var(--color-text-base-white-text); border-color: var(--color-primary-primary); }
.page-btn:disabled { opacity: .5; cursor: default; }
.page-ellipsis { padding: 0 var(--space-xs); color: var(--color-text-base-placeholder-text); }

.th-sortable { display: inline-flex; align-items: center; gap: .4rem; }
.th-sort-btn { background: none; border: none; padding: 0; cursor: pointer; color: inherit; font: inherit; }
.th-caret { opacity: .7; font-size: .85em; } /* TODO: no matching font-size token — em is relative to the parent (th) font-size, not statically resolvable to a token */
.col-num { text-align: left; width: 110px; }
.cell-empty { color: var(--color-text-base-button-cancel); }
.site-code { margin-top: 2px; font-size: var(--font-size-label); color: var(--color-red-700); font-family: ui-monospace, monospace; }

.status-pill { display: inline-flex; align-items: center; gap: .4rem; padding: .2rem .6rem;
    border-radius: var(--radius-pill); font-size: var(--font-size-status); font-weight: var(--font-weight-medium); white-space: nowrap; }
.status-pill--active { background: var(--color-status-success-vbright); color: var(--color-green-700); }
.status-pill--closed { background: var(--color-text-base-disabled-bg); color: var(--color-text-base-description-icon-form); }
.status-pill--inactive { background: var(--color-text-base-disabled-bg); color: var(--color-text-base-description-icon-form); }
/* customer workflow-status variants (deal lifecycle pills) */
.status-pill--green { background: var(--color-status-success-vbright); color: var(--color-green-700); }
.status-pill--orange { background: var(--color-semantic-extra-highlight-bg); color: var(--color-semantic-extra-highlight-text); }
.status-pill--yellow { background: var(--color-status-alert-vbright); color: var(--color-semantic-extra-warning-text); }
.status-pill--red { background: var(--color-status-error-vbright); color: var(--color-red-700); }
.status-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

/* shared list chrome (PagedListTable + ListFilterBar) */
.list-filters { display: flex; gap: var(--space-sm); flex-wrap: wrap; margin-bottom: var(--space-md); align-items: flex-end; }

/* labelled filter fields (label stacked above input) */
.filter-field { display: flex; flex-direction: column; gap: .35rem; flex: 1 1 180px; min-width: 160px; }
.filter-field .filter-input { flex: 1 1 auto; width: 100%; min-width: 0; }
.filter-label { font-size: var(--font-size-label); font-weight: var(--font-weight-medium); color: var(--color-text-base-description-icon-form); }

/* A Pec* field (PecDatePicker/PecTextField/...) dropped straight into the filter bar: the Pec field
   frame already renders its own label row, so it replaces .filter-field rather than nesting inside
   it — this rule just re-applies .filter-field's flex sizing so the bar lays out identically. Lives
   here (not in _FieldFrame.razor.css) because it is filter-bar layout, not field styling; app.css
   loads after the scoped bundle, so it wins the min-width tie against .pec-field's own `min-width: 0`. */
.list-filters .pec-field { flex: 1 1 130px; min-width: 160px; }

/* Match the search button's height to the filter inputs beside it (48px). PecButton's own Size
   parameter cannot do this: Small/Medium/Large only change padding and font-size in components.css
   — the height comes from FluentButton's shadow DOM, so all three measure the same 60px (verified
   live by swapping the size class on a rendered button). Setting it here rather than in
   components.css keeps every other PecButton in the app at its designed 60px; this is filter-bar
   layout, not a change to the button variant. Both selectors are needed for the same reason the
   PecButton variant rules carry an `a.` companion: OnClick renders <fluent-button> (styled through
   ::part(control)), Href renders a plain <a> with no shadow DOM.

   The `:not(a)` rule sizes the HOST too, for the same reason .pec-btn--icon needs one in
   components.css: ::part(control) only reaches the box INSIDE the shadow root, while the host is
   what the flex row lays out — set only the control and the host stays 60px with a 48px control
   inside it (measured live). */
.list-filters .pec-btn::part(control),
.list-filters a.pec-btn { height: 48px; }
.list-filters .pec-btn:not(a) { height: 48px; }

/* QR batch quantity row (QrBatchCreate) — page-specific, but it has to live here rather than in
   QrBatchCreate.razor.css: .pec-choice/.pec-choice__btn are rendered by PecChoiceGroup, so a
   page-scoped [b-xxxxx] rule would never match them. PecChoiceGroup's default .pec-choice__btn is
   flex:1 1 0 (Figma's 2-button row), which squeezes a 7-preset group until a label breaks onto a
   second line ("1 ชิ้น"). Content-size the buttons instead, keep each label on one line, and use
   the tighter gap the old hand-rolled .qrc-seg row had. min-width matches .qrc-seg's old 60px. */
.qrc-qty-row .pec-choice { gap: var(--space-sm); flex-wrap: wrap; }
.qrc-qty-row .pec-choice__btn { flex: 0 0 auto; min-width: 60px; white-space: nowrap; }

/* Same reason, same file: QrBatchCreate's จัดการ cell holds up to 3 IconOnly PecButtons, so it
   cannot use .pec-table__action — that rule adds margin:0 auto per button, which in a flex row
   absorbs the free space and pulls the group apart. Everything ELSE in that rule is still needed:
   FluentButton's host is display:grid and stretches to the cell, leaving its 36px ::part(control)
   circle at the start while the icon centers against the wide host — so the icon ends up outside
   its own circle. Pin the host to the circle's size and let .qrc-actions' justify-content do the
   centering. Sizes mirror components.css .pec-table__action (36 / 30 / 44 for md/sm/lg). */
.qrc-actions .pec-btn--icon {
    display: inline-flex !important;
    width: 36px !important;
    min-width: 0 !important;
    justify-content: center !important;
    align-items: center !important;
}
.qrc-actions .pec-btn--icon.pec-btn--sm { width: 30px !important; }
.qrc-actions .pec-btn--icon.pec-btn--lg { width: 44px !important; }

/* too-short filter: the bar refuses to search and the field says why */
.filter-input--invalid { border-color: var(--color-red-500); }
.filter-error { font-size: var(--font-size-label); color: var(--color-red-700); }

/* non-sticky page footer actions (กลับ / บันทึก) */
.list-footer { display: flex; justify-content: center; gap: var(--space-md); padding: var(--space-xl) 0 var(--space-md); }
.list-footer .btn { min-width: 160px; justify-content: center; text-decoration: none; align-items: center; }
.list-footer__back { background: var(--color-text-base-border); color: var(--color-neutral-description-icon-form-divider); }
.list-footer__save { background: var(--color-navy-blue-900); color: var(--color-text-base-white-text); border: none; cursor: pointer; }
.list-footer__save:disabled { opacity: .6; cursor: not-allowed; }

/* customer detail — information card */
.cust-info { display: flex; gap: var(--space-lg); align-items: flex-start; }
.cust-info__photo { flex: 0 0 136px; display: flex; flex-direction: column; gap: var(--space-sm); align-items: stretch; }
.cust-photo-box { width: 136px; height: 153px; border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg);
    background: var(--color-neutral-background); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.cust-photo-img { width: 100%; height: 100%; object-fit: cover; }
.cust-info__photo .sd-btn { justify-content: center; cursor: pointer; }
/* Busy state for any in-flight submit (save / add / upload): dim + inert while the spinner runs.
   Applies to both button families; the spinner sits inline beside the label. */
.sd-btn--busy, .btn--busy { pointer-events: none; opacity: .6; }
.sd-btn--busy, .btn--busy { display: inline-flex; align-items: center; gap: var(--space-sm); }
.cust-info__fields { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: var(--space-md); }
.cust-grid { display: grid; grid-template-columns: repeat(3, 1fr) auto; gap: var(--space-md); align-items: end; }
/* create mode: the id field carries an absolute hint below it — reserve clearance for that one row */
.cust-grid:has(.cust-field__hint) { margin-bottom: var(--space-md); }
.cust-grid--3 { grid-template-columns: repeat(3, 1fr); }
.cust-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; position: relative; }
.cust-field__label { font-size: var(--font-size-label); color: var(--color-text-base-placeholder-text); font-weight: var(--font-weight-semibold); }
.cust-field__hint { position: absolute; top: 100%; left: 0; margin-top: 3px; font-size: var(--font-size-texthelp); color: var(--color-text-base-placeholder-text); white-space: nowrap; }
.cust-field--status { justify-content: flex-end; padding-bottom: var(--space-sm); }
.cust-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

/* BU detail — the sites table carries a labelled action, so it needs more room than the 110px default. */
.bu-site-actions-cell { width: 120px; }
.bu-site-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }

@media (max-width: 900px) {
    .cust-info { flex-direction: column; }
    .cust-grid, .cust-grid--3 { grid-template-columns: 1fr; }
}

/* ---- Modal (sd namespace) ---- */
/* ---- Image preview (ImagePreviewModal) ---- */
/* Darker than sd-overlay and above it: a photo opened from inside a modal must still sit on top. */
.img-preview { position: fixed; inset: 0; z-index: 1100; background: rgba(2, 6, 23, 0.88);
    display: flex; align-items: center; justify-content: center; padding: 56px 16px; outline: none; }
.img-preview__img { max-width: 92vw; max-height: 84vh; object-fit: contain;
    border-radius: var(--radius-button); box-shadow: 0 24px 60px rgba(0, 0, 0, .5); }
.img-preview__bar { position: absolute; top: 0; left: 0; right: 0; height: 56px;
    display: flex; align-items: center; gap: var(--space-md); padding: 0 16px;
    color: var(--color-text-base-white-text); }
.img-preview__caption { flex: 1; font-size: var(--font-size-body); overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; }
.img-preview__count { font-size: var(--font-size-caption); opacity: .75; }
.img-preview__close { background: none; border: none; cursor: pointer; display: flex; padding: 4px; }
.img-preview__nav { position: absolute; top: 50%; transform: translateY(-50%);
    width: 44px; height: 44px; border: none; border-radius: 50%;
    background: rgba(255, 255, 255, .15); color: var(--color-text-base-white-text);
    font-size: 28px; line-height: 1; cursor: pointer; }
.img-preview__nav:hover { background: rgba(255, 255, 255, .28); }
.img-preview__nav--prev { left: 16px; }
.img-preview__nav--next { right: 16px; }
/* The thumbnail itself is the trigger, so it must read as clickable. */
.sd-gallery__img, .sd-photo-img--zoomable { cursor: zoom-in; }

.sd-overlay { position: fixed; inset: 0; background: rgba(15, 23, 42, 0.45);
    display: flex; align-items: center; justify-content: center; z-index: 1000; padding: var(--space-lg); }
.sd-modal.sd-modal--wide { width: min(1280px, 96vw); }
.sd-modal--wide .sd-table th, .sd-modal--wide .sd-table td { white-space: nowrap; }
.sd-modal { background: var(--color-primary-surface); border-radius: 14px; width: 640px; max-width: 100%;
    max-height: 90vh; display: flex; flex-direction: column; box-shadow: 0 20px 50px rgba(15, 23, 42, 0.25); }
.sd-modal__head { display: flex; align-items: center; justify-content: space-between;
    padding: 18px 22px; border-bottom: 1px solid var(--color-text-base-border); }
.sd-modal__title { margin: var(--space-0); font-size: var(--font-size-title); font-weight: var(--font-weight-bold); color: var(--color-neutral-title-content); }
.sd-modal__close { background: none; border: none; cursor: pointer; padding: var(--space-xs); line-height: 0; }
.sd-modal__body { padding: 22px; overflow-y: auto; display: flex; flex-direction: column; gap: var(--space-md); }
.sd-modal__foot { display: flex; justify-content: center; gap: var(--space-md);
    padding: 20px 22px 24px; }
.sd-modal__error { margin: var(--space-0); color: var(--color-red-700); font-size: var(--font-size-body); }
.sd-modal__btn { min-width: 200px; height: 52px; justify-content: center;
    border-radius: var(--radius-button); font-size: var(--font-size-button); font-weight: var(--font-weight-bold); }
.sd-modal__btn--grey { background: var(--color-text-base-border); color: var(--color-neutral-description-icon-form-divider); }
.sd-modal__btn--grey:hover:not(:disabled) { background: var(--color-text-base-button-cancel); }
.list-card { background: var(--color-component-card-bg); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-button); overflow: hidden; }
.list-card__head { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.25rem; border-bottom: 1px solid var(--color-text-base-disabled-bg); }
.list-card__heading { font-size: var(--font-size-base); font-weight: var(--font-weight-semibold); margin: var(--space-0); color: var(--color-neutral-title-content); }
.list-card__count { color: var(--color-text-base-placeholder-text); font-weight: var(--font-weight-regular); margin-left: var(--space-xs); }
.list-card__head-actions { display: flex; align-items: center; gap: var(--space-md); }
.list-card__state { padding: 2.5rem; text-align: center; color: var(--color-text-base-placeholder-text); }
.list-table__scroll { overflow-x: auto; }
.list-table { width: 100%; border-collapse: collapse; font-size: var(--font-size-table-line); }
.list-table thead th { text-align: left; height: 68px; padding: 0 var(--space-md); background: var(--color-navy-blue-900); color: var(--color-text-base-border); font-weight: var(--font-weight-medium); white-space: nowrap; }
/* Red accent bar on the header's left edge (design mockup). */
.list-table thead th:first-child { border-left: 3px solid var(--color-status-error); }
.list-table tbody td { height: 60px; padding: 0 var(--space-md); border-bottom: 1px solid var(--color-text-base-disabled-bg); color: var(--color-neutral-description-icon-form-divider); vertical-align: middle; }
/* Zebra-striped rows: white / slate-200 (design). Declared BEFORE .row--busy so the
   delete-in-flight gray still wins on even rows. */
.list-table tbody tr:nth-child(even) td { background: var(--color-text-base-border); }
.list-table td.list-table__empty { text-align: center; color: var(--color-text-base-placeholder-text); padding: var(--space-xl); }
/* Empty-state row is not a data row: no zebra, no hover highlight. */
.list-table tbody tr.list-table__emptyrow td,
.list-table tbody tr.list-table__emptyrow:hover td { background: transparent; }
.list-table tbody tr:hover td { background: var(--color-text-base-disabled-bg); }
/* Row with an operation (delete) in flight: dim it and block all clicks (links, buttons, checkbox). */
.list-table tbody tr.row--busy { opacity: .45; pointer-events: none; background: var(--color-neutral-background); }
.list-name { color: var(--color-primary-primary); text-decoration: none; font-weight: var(--font-weight-medium); }
.list-name:hover { text-decoration: underline; }
.list-pager { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding: .75rem 1.25rem; }
.list-pager__size { justify-self: end; }
.list-pager__size .filter-input { width: auto; min-width: 130px; }
.list-pager__pages { grid-column: 2; display: flex; gap: var(--space-xs); }
.list-pager__size { grid-column: 3; justify-self: end; }
.list-pager__size .filter-input { min-width: 130px; }

/* ===== Employee detail + certificates tab ===== */
.ed-page { display: flex; flex-direction: column; gap: var(--space-md); }
.ed-state { padding: var(--space-2xl); text-align: center; color: var(--color-text-base-placeholder-text); }

.ed-crumbs { display: flex; align-items: center; gap: var(--space-sm); font-size: var(--font-size-caption); color: var(--color-text-base-placeholder-text); }
.ed-crumbs a { color: var(--color-text-base-link); text-decoration: none; }
.ed-crumb-sep { color: var(--color-text-base-button-cancel); }
.ed-crumb-current { color: var(--color-neutral-description-icon-form-divider); }

.ed-title { font-size: var(--font-size-title); font-weight: var(--font-weight-semibold); margin: var(--space-0); color: var(--color-neutral-title-content); }
.ed-emptype { align-self: center; font-size: var(--font-size-tiny); font-weight: var(--font-weight-bold); letter-spacing: .04em;
    color: var(--color-text-base-white-text); background: var(--color-component-button-primary-bg); padding: .35rem .75rem; border-radius: var(--radius-pill); white-space: nowrap; }

.ed-btn { display: inline-flex; align-items: center; gap: .4rem; height: 36px; padding: 0 var(--space-md);
    border: none; border-radius: var(--radius-lg); cursor: pointer;}
.ed-btn:disabled { opacity: .55; cursor: default; }

.ed-card { background: var(--color-component-card-bg); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-button); overflow: hidden; margin-top: 1rem;}
.ed-card + .ed-card { margin-top: 1.25rem; }
.ed-card__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-md);
    border-bottom: 1px solid var(--color-text-base-disabled-bg); padding: 0.5rem 1.25rem; }
/* Flush variant: no head separator (drops the top/bottom rules inside the card). */
.ed-card--flush .ed-card__head { border-bottom: none; }
/* Card heads can carry a title plus a cluster of action controls (status badge, buttons, icon
   links — e.g. InstanceCreate.razor's edit-mode head). At narrow widths that row has nowhere to
   shrink to, so let it wrap to a second line instead of overflowing/clipping. No-op wherever the
   head's content already fits (every other .ed-card__head caller at this breakpoint today). */
@media (max-width: 560px) { .ed-card__head { flex-wrap: wrap; row-gap: var(--space-sm); } }
.ed-card__title { display: flex; align-items: center; gap: var(--space-sm);
    font-size: var(--font-size-base); font-weight: var(--font-weight-semibold); margin: var(--space-0); color: var(--color-neutral-title-content); }
/* Save row shown only when the viewer has edit permission (EmployeeDetail.razor _canEdit) —
   the card head no longer carries an Edit button, editability is permission-driven not toggle-driven. */
.ed-card__foot { display: flex; justify-content: flex-end; padding: 1.25rem 1.25rem; }

/* Personal information card — profile strip atop the field grid */
.ed-profile {display: flex; flex-direction: column;}
.ed-profile__strip { display: flex; align-items: stretch; gap: var(--space-md); background-color: var(--color-text-base-disabled-bg);
    padding: 0.75rem 1.25rem; border: 1px solid var(--color-text-base-disabled-bg); border-radius: 14px; margin-top: 10px; margin:1.25rem}
.ed-profile__avatar { width: 72px; height: 72px; border-radius: 10%; background: var(--color-text-base-disabled-bg); border: 1.37px solid var(--color-navy-blue-100);
    display: flex; align-items: center; justify-content: center; flex: 0 0 auto; position: relative; box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);}
.ed-profile__avatar-img { width: 100%; height: 100%; object-fit: cover; border-radius: 10%; }
.ed-profile__upload { width: 23px; height: 23px; border-radius: 50%; background: var(--color-component-button-danger-bg); border: 1.3px solid var(--color-primary-surface);
    position: absolute; bottom: -6px; right: -6px; display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
    box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); cursor: pointer;}
.ed-profile__id { flex: 1 1 auto; display: flex; flex-direction: column; gap: .35rem; min-width: 0;}
.ed-profile__name-row { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
.ed-profile__empid { font-family: ui-monospace, monospace; font-size: var(--font-size-label);
    letter-spacing: .04em; color: var(--color-text-base-placeholder-text); }
.ed-profile__meta { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap;
    font-size: var(--font-size-caption); color: var(--color-neutral-description-icon-form-divider); }
.ed-profile__sep { color: var(--color-text-base-button-cancel); }
.ed-profile__contact { display: flex; gap: 1.25rem; flex-wrap: wrap;
    font-size: var(--font-size-caption); color: var(--color-text-base-description-icon-form); }
.ed-profile__contact-item { display: inline-flex; align-items: center; gap: .35rem; }

/* Field grid (EmployeeDetail/EmployeeCreate "profile" fields). Design intent: column 4 holds ONLY
   Birthdate, pinned to row 1 — every other field is confined to columns 1-3 (col 4 rows 2/3 render
   empty). A plain 4-column CSS grid can't express "col 4 is off-limits to auto-placed items except
   one" (implicit auto-placement wraps based on the explicit column-track count, so normal fields
   would spill into column 4 on wrap). Instead .ed-infogrid is a 2-region flex row: `__main` (a
   3-column grid holding every field except Birthdate, free to wrap to as many rows as it needs)
   sits beside `__birthdate` (Birthdate alone, one column's width, `align-self: flex-start` pins it
   to the top regardless of how tall `__main` grows). */
.ed-infogrid { display: flex; align-items: flex-start; gap: 1.25rem; padding: 1.25rem; }
.ed-infogrid__main { display: grid; grid-template-columns: repeat(3, 1fr);
    gap: 1rem 1.25rem; flex: 3 1 0; min-width: 0; }
.ed-infogrid__birthdate { flex: 1 1 0; align-self: flex-start; min-width: 0; }
@media (max-width: 900px) { .ed-infogrid__main { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) {
    .ed-infogrid { flex-direction: column; }
    .ed-infogrid__main { grid-template-columns: 1fr; width: 100%; }
    .ed-infogrid__birthdate { width: 100%; }
}
/* Contact grid has 4 fields (Email, Phone, Last Update, Create Date) — plain 3-column
   grid (matches the design mockup, splits 3+1, no reserved column). Position was removed from here
   (employee-self-edit slice — Position/Department are no longer editable from this page; the fields
   stay on the model/DB, just not rendered here) and the grid still auto-flows fine with one fewer cell. */
.ed-infogrid--contact { display: grid; grid-template-columns: repeat(3, 1fr);
    gap: 1rem 1.25rem; padding: 1.25rem; }
@media (max-width: 900px) { .ed-infogrid--contact { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .ed-infogrid--contact { grid-template-columns: 1fr; } }
.ed-field__label { font-size: var(--font-size-label); color: var(--color-text-base-description-icon-form); font-weight: var(--font-weight-semibold);
    letter-spacing: .01em; margin-bottom: .35rem; }
.ed-field__label--required::after { content: ' *'; color: var(--color-status-error); }
.ed-field__value { font-size: var(--font-size-body); color: var(--color-navy-blue-900); }
.ed-field__input { background: var(--color-primary-surface); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg);
    padding: .5rem .75rem; min-height: 40px; font-size: var(--font-size-body); color: var(--color-navy-blue-900);
    display: flex; align-items: center; }
/* Editable variants (<input>/<select>) reuse .ed-field__input's box styling but need an
   explicit full width + border-box — unlike the read-only <div>, form controls don't fill
   their grid cell by default and would otherwise shrink to intrinsic width. */
input.ed-field__input, select.ed-field__input {
    width: 100%; box-sizing: border-box; }
.ed-field__input--readonly { background: var(--color-text-base-disabled-bg); color: var(--color-text-base-description-icon-form); }
/* DateInput.razor's <FluentDatePicker> — despite the tag name, FluentDatePicker's rendered root
   element is its INNER <fluent-text-field> (confirmed live: Class="ed-field__input" lands on a
   <fluent-text-field class="fluent-datepicker ed-field__input outline"> — there is no wrapping
   <fluent-date-picker> host element in the DOM at all). fluent-text-field is a FluentUI web
   component with an OPEN shadow root; it renders its OWN bordered box (shadow part "root") plus a
   FAST/Fluent focus "underline" (a :host(...)::after pseudo-element, not a stable exposed part).
   Previously `.ed-field__input`'s plain-class rule (line ~690) matched this element directly and
   painted a border/padding/bg on the *light-DOM host*, on top of the shadow "root" part's own box
   underneath — double box, plus the underline showing through on focus. Fix: this more specific
   selector strips the host back to an unstyled passthrough (no border/bg/padding of its own); the
   shadow "root" part becomes the ONE visible field box, styled to match .ed-field__input exactly.
   The underline can't be targeted via ::part (FAST doesn't expose it as a part), so it's neutralized
   by overriding the design-token CSS custom property it reads (--accent-fill-rest) to transparent —
   these tokens are real inherited CSS custom properties, not shadow-DOM-opaque, confirmed via the
   shipped Microsoft.FluentUI.AspNetCore.Components.lib.module.js FAST style-recipe source, and via
   live devtools computed-style/shadowRoot inspection against the running app. */
fluent-text-field.ed-field__input {
    /* width contract, stated explicitly at every layer (host + both shadow parts below) rather
       than relying on the shadow parts implicitly inheriting/auto-filling — the host itself
       defaults to `display: flex` (FAST's own custom-element default, confirmed live via
       getComputedStyle), and its "root" part is an inner flex/block box that doesn't reliably
       stretch to 100% on its own once other rules are added to this file later. */
    display: block;
    width: 100%;
    box-sizing: border-box;
    /* host: no box of its own — the shadow "root" part below is the field box */
    background: transparent;
    border: none;
    border-radius: var(--radius-none);
    padding: var(--space-0);
    min-height: 0;
    height: 40px;
    /* kills the FAST focus/active underline (:host::after reads --accent-fill-rest for its color) */
    --accent-fill-rest: transparent;
    --accent-fill-hover: transparent;
    --accent-fill-active: transparent;
    --accent-fill-focus: transparent;
    /* calendar icon (light-DOM <FluentIcon>, fill: currentcolor) tinted to match other muted icons */
    color: var(--color-text-base-description-icon-form);
}
fluent-text-field.ed-field__input::part(root) {
    width: 100%;
    background: var(--color-primary-surface);
    border: 1px solid var(--color-text-base-border);
    border-radius: var(--radius-lg);
    padding: .5rem .75rem;
    height: 40px;
    box-sizing: border-box;
    font-size: var(--font-size-body);
    color: var(--color-navy-blue-900);
}
fluent-text-field.ed-field__input:focus-within::part(root) {
    border-color: var(--color-primary-primary);
    box-shadow: var(--shadow-active-state);
}
fluent-text-field.ed-field__input::part(control) {
    /* the raw <input> inside "root" — stretch it to fill whatever horizontal space "root" isn't
       using for its start/end icon slots (flex child, so 100% here means "take remaining space",
       not "match root's own 100%" — confirmed live: control's rendered width is narrower than
       root's by exactly root's padding + the end-slot calendar-icon width, as expected). */
    width: 100%;
    flex: 1 1 auto;
    min-width: 0;
    font-size: inherit;
    color: inherit;
}

/* Styled file picker (native input hidden; label acts as the button) */
.cust-file { display: flex; align-items: center; gap: .75rem; }
.cust-file .sd-btn { cursor: pointer; flex: 0 0 auto; }
.cust-file__name { font-size: var(--font-size-caption); color: var(--color-text-base-description-icon-form); overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; }

/* Vendor detail — stacked form matching Figma (ID, Name, [Contact|Phone|Email], Address) */
.vd-form { display: flex; flex-direction: column; gap: var(--space-md); padding: 0.25rem; box-sizing: border-box; width: 100%; min-width: 0; }
.vd-row3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.25rem; width: 100%; min-width: 0; box-sizing: border-box; }
/* Grid items must be allowed to shrink below their content's intrinsic width, or a wide child
   (e.g. a PecSelect whose <fluent-select> sizes to its longest option) blows the 1fr track out
   past the row edge. */
.vd-row3 > * { min-width: 0; }
/* ProductCategoryModal — the 3 classification selects stack one-per-line (the 3-up row3 was too
   tight for the label + placeholder in this narrow dialog). */
.pcm-selects { display: flex; flex-direction: column; gap: var(--space-md); }
.pcm-selects > * { min-width: 0; }
/* Footer buttons centered with a small gap (← Close / Confirm →). */
.pcm-footer { display: flex; justify-content: center; align-items: center; gap: var(--space-md); width: 100%; }
@media (max-width: 768px) { .vd-row3 { grid-template-columns: 1fr; } }
.vd-field { display: flex; flex-direction: column;}
/* AssetDetail.razor / MaterialLotDetail.razor's status-toggle field — was an inline
   `style="width: 50%;"` on both call sites (grepped, exactly 2). Ported to a class purely so a
   mobile media query can override it (inline styles beat any stylesheet rule targeting the same
   class regardless of specificity — same reason InstanceCreate.razor's `.vd-fields-grid` inline
   styles had to move out). Value is byte-identical to what was inline; desktop unaffected. */
.vd-field--half { width: 50%; }
@media (max-width: 560px) { .vd-field--half { width: 100%; } }
.vd-input { width: 100%; background: var(--color-primary-surface); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg);
    padding: .5rem .75rem; min-height: 40px; font-size: var(--font-size-body); color: var(--color-navy-blue-900); box-sizing: border-box; }
.vd-input:focus { outline: none; border-color: var(--color-primary-primary); box-shadow: var(--shadow-active-state); }
.vd-input[readonly] { background: var(--color-neutral-background); color: var(--color-neutral-description-icon-form-divider); }
.vd-input--preview { color: var(--color-text-base-placeholder-text); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .02em; }
/* Auto-growing remark box: height tracks content (field-sizing where supported), no manual resize. */
.vd-textarea { resize: none; field-sizing: content; min-height: 64px; line-height: 1.4; font-family: inherit; }
.vd-charcount { margin-top: var(--space-xs); text-align: right; font-size: var(--font-size-label); color: var(--color-text-base-placeholder-text); }
.vd-error { background: var(--color-component-feedback-card-bg); border: 1px solid var(--color-red-200); color: var(--color-red-700);
    border-radius: var(--radius-lg); padding: .625rem .875rem; font-size: var(--font-size-body); }
.vd-input--invalid, .vd-input--invalid:focus { border-color: var(--color-red-700); box-shadow: none; }
.vd-field-error { margin-top: var(--space-xs); font-size: var(--font-size-label); color: var(--color-red-700); }

/* SkuDetail.razor (create + detail state) — page-scoped layout primitives matching
   design/product/sku_detail.css's photo-left/fields-right split (Frame 1410069376) and its 3
   asymmetric field-row shapes (Frame 1410069245/1410069244/1410069246), which the shared
   .vd-row3 (always-3-equal-columns) grid cannot express. Deliberately NOT folded into .vd-row3
   itself — that class is used by other pages with its original fixed-3-col shape; these are new,
   additive classes, see research/2026-07-22-sku-detail-layout-css-diff.md §1/§2. */
.sku-layout { display: flex; flex-direction: row; gap: var(--space-md); align-items: flex-start; }
.sku-layout__upload { flex: 0 0 auto; }
.sku-layout__fields { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: var(--space-md); }
@media (max-width: 768px) { .sku-layout { flex-direction: column; } }
.sku-row-code { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-md); align-items: start; }
.sku-row-category { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-md); }
.sku-row-full { display: grid; grid-template-columns: 1fr; }
@media (max-width: 768px) { .sku-row-code { grid-template-columns: 1fr; } }

/* InstanceCreate.razor top card (design/product/instance create.png, design/product/instance
   create.css) — form (left) + printable QR sticker card (right, edit mode only). All colors below
   are exact matches to the Figma export's hex values via existing tokens (no new tokens needed):
   #060D1D header -> --color-text-base-title-content, #F8FAFC QR tile -> --color-neutral-background,
   #13284F Print button -> pec-btn--primary's own navy (unchanged, no override needed). */
.ic-layout { display: flex; flex-direction: row; gap: var(--space-lg); align-items: flex-start; width: 100%; }
/* InstanceCreate's top card head sits tighter than the Figma design wants — add breathing room
   above the title. Scoped to .ic-layout so shared .ed-card heads on other pages are unaffected. */
.ic-layout .ed-card__head { padding-top: var(--space-md); padding-bottom: var(--space-md); }
.ic-layout__form { flex: 1 1 auto; min-width: 0; padding: var(--space-md);}
/* Edit-mode card-head action cluster (rental-offerings link + status badge + history icon button)
   — was an inline `style="display:flex; align-items:center; gap: var(--space-sm);"` on the wrapper
   div; ported to a class with the exact same 3 declarations (no value changed) purely so a
   mobile-only media query can add wrapping below, which an inline style can't be overridden by. */
.ic-head-actions { display: flex; align-items: center; gap: var(--space-sm); }
/* Mobile-only: this cluster can hold 3 controls (button + badge + icon button) that don't fit next
   to the card title in a 375px row. Let it wrap instead of overflowing. Desktop (unscoped rule
   above) is untouched. */
@media (max-width: 560px) { .ic-head-actions { flex-wrap: wrap; row-gap: var(--space-sm); } }
@media (max-width: 900px) { .ic-layout { flex-direction: column; } }
/* QR sticker card is a fixed-percentage FLEX-BASIS column while .ic-layout is a row; once the row
   flips to a column at <=900px above, flex-basis governs height instead of width and the card gets
   squashed. Let it take the container's full width in the stacked layout instead. */
@media (max-width: 900px) { .ic-qr-card { flex-basis: auto; width: 100%; } }

/* InstanceCreate.razor's 4 metadata-tab bodies (VehicleInfo/ToolMachineInfo/Driver/Inspection) —
   was previously an inline `style="display:grid; grid-template-columns: repeat(3, 1fr); ..."` on
   each tab's wrapper div; moved into this class so a media query can actually override it (inline
   styles beat stylesheet rules regardless of specificity, so a @media rule targeting the class had
   no effect while the grid columns lived inline). Values below are the exact ones that were inline. */
.vd-fields-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-md); padding: 1.25rem 1.25rem; }
@media (max-width: 900px) { .vd-fields-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .vd-fields-grid { grid-template-columns: 1fr; } }

.ic-qr-card { flex: 0 0 20%; display: flex; flex-direction: column; align-items: stretch; gap: var(--space-sm); padding: var(--space-md); }
/* .ic-qr-card__box, __header, __canvas, __code, __meta, __bu retired — the sticker chrome itself
   (box/header/canvas/code/category strip/BU footer) now comes from the shared QrSticker component
   (Components/Shared/Ui/QrSticker.razor + its own scoped .razor.css), the same component
   QrAssetBindModal/QrBatchCreate use. Only .ic-qr-card (this card's own column layout),
   .ic-qr-card__empty (the dashed unbound placeholder, rendered into QrSticker's Empty fragment) and
   .ic-qr-card__register-btn (a PecButton variant override) still belong to this page.
   Unbound state (no sticker bound yet — sticker-only issuance, 2026-07-31). The card renders WITHOUT
   the __header and __bu bars here: those black strips are the printed sticker's chrome, and there is
   no sticker to print yet. The unbound card is therefore deliberately shorter than the bound one —
   binding grows it, which is the correct signal that something now exists.
   200px is the bound QR stack measured against the tokens above (canvas 128 + margin-top --space-md
   16, then __code ≈28 + --space-sm 8, then __meta ≈17 + --space-xs 4), minus the frame's own top and
   bottom margin so the dashed box occupies the same slot the QR will. */
.ic-qr-card__empty { min-height: calc(200px - 2 * var(--space-md)); align-self: stretch;
    display: flex; align-items: center; justify-content: center;
    /* Dashed placeholder frame rather than bare text: the empty state occupies the slot the QR will
       fill, so it should read as "a sticker goes here", not as a caption. */
    margin: var(--space-md); padding: var(--space-md); box-sizing: border-box;
    border: 1px dashed var(--color-text-base-border); border-radius: var(--radius-md);
    text-align: center; font-size: var(--font-size-tiny);
    font-weight: var(--font-weight-semibold); color: var(--color-text-base-placeholder-text); }
/* Gap: Figma's register-QR fill (#FEF3C7 / navy text) matches neither pec-btn--primary-light
   (pale BLUE) nor pec-btn--warning (solid amber) exactly — reusing the existing
   --color-semantic-extra-warning-bg/-text pair here (same tokens ProductCategory's group tag
   already uses for this precise pale-amber look) via a scoped override, same dual ::part(control)
   + a.pec-btn selector shape every other PecButton variant override in this file uses. */
.ic-qr-card__register-btn::part(control),
a.ic-qr-card__register-btn {
    background: var(--color-semantic-extra-warning-bg);
    color: var(--color-semantic-extra-warning-text);
}

/* ── print — single element ─────────────────────────────────────────────────────────────────
   Paired with js/print-element.js: window.printElement(selector) stamps .is-printing-element on
   <body> and .is-print-target on the element, prints, then removes both on afterprint. Nothing
   here applies to an ordinary Ctrl+P or to the pages that deliberately print whole (DeliveryPrep,
   DeliveryReceipt) — the body class only exists during a printElement() call.
   visibility (not display) is what hides the rest: display:none on ancestors would take the target
   down with them, whereas visibility is re-assertable on a descendant subtree. The target is then
   position:fixed so no ancestor's overflow/clip can crop it, and print-color-adjust:exact keeps the
   sticker's black header/footer bars from being dropped as "background graphics". */
@media print {
    body.is-printing-element * { visibility: hidden !important; }
    body.is-printing-element .is-print-target,
    body.is-printing-element .is-print-target * {
        visibility: visible !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
    body.is-printing-element .is-print-target {
        position: fixed;
        top: 0;
        left: 0;
        margin: 0;
        box-shadow: none;
    }

    /* The target is the SHEET — one page of label stock. It covers the page box exactly and the
       labels on it are placed absolutely, so a sheet carrying two labels needs no flow layout at
       print time (its on-screen flex row would have to be re-derived in page coordinates anyway). */
    body.is-printing-element .ic-qr-card__sheet.is-print-target {
        width: 100%; height: 100%; display: block; gap: 0;
    }
    body.is-printing-element .ic-qr-card__sheet.is-print-target .qr-sticker {
        position: absolute;
        top: 50%;
        left: 50%;
        /* The quarter turn. The tag is authored portrait (40x60 / 25x50) and the stock is landscape,
           so it is rotated rather than re-flowed - preview and print stay the identical artwork, one
           just lies on its side on the roll. Rotation happens about the label's own centre (the
           default transform-origin) AFTER the translate has moved that centre onto the target point;
           written the other way round the translate would run along the rotated axes and throw the
           tag off the page. */
        transform: translate(-50%, -50%) rotate(90deg);
        border: none; border-radius: 0;
        /* Fill the page across the label's SHORT axis, and ONLY that one. Prints leave a ~3mm white
           band at one edge: the label is authored 25mm/40mm across, but the page the driver hands
           over is a little deeper than that (the die-cut gap appears to sit inside the form), so a
           fixed mm can never quite reach the edge. 100vh is 100% of the page box height, and the tag
           is rotated a quarter turn, so its WIDTH is what lands on that height.
           The long axis stays in authored mm deliberately — that is the axis the 2-across seam runs
           along, and an earlier pass that stretched BOTH (100vw + 100vh) made one label's artwork
           straddle both die-cuts. Short axis only. */
        width: 100vh;
    }

    /* Label stock, one named @page per preset - @page takes no selector, so a body-level `page:`
       property is the only way to pick a size per print, and printElement()'s second argument adds
       the matching body class. A plain Ctrl+P and the whole-page prints (DeliveryPrep,
       DeliveryReceipt) carry no such class and keep the browser's own defaults.
       Sizes are the stock as the driver holds it - landscape - because the artwork above is the
       thing being rotated. Letting the printer's default stock stand instead (no `size`) was tried
       on 2026-08-03 and reverted: it removed the need for driver setup but fed a full 101.6mm page
       per label, leaving ~3cm of blank liner every print.
       The 2-across page is the whole 100mm ROW of two labels, not one 50mm label - that is the
       operator's Godex form, the only one the printer accepts for this roll. Asking for 50x25 made
       Chrome fall back to its default paper; omitting `size` handed orientation to the print
       dialog's layout radio. An explicit size matching a real driver form is what makes the
       orientation deterministic and the radio irrelevant. */
    @page sticker-60x40 { size: 60mm 40mm; margin: 0; }
    @page sticker-50x25 { size: 100mm 25mm; margin: 0; }
    body.is-printing-element.print-60x40 { page: sticker-60x40; }
    body.is-printing-element.print-50x25 { page: sticker-50x25; }

    /* Single-across roll: one label, page centre. */
    body.is-printing-element.print-60x40 .ic-qr-card__sheet.is-print-target .qr-sticker { left: 50%; }

    /* 2026-08-05: the print-50x25 :first-child/:last-child split that used to sit here (25%/75% along
       the row, one per die-cut label) is REMOVED, not just unused — it targeted `.qr-sticker`, which
       InstanceCreate.razor's sheet only ever renders in the CSS-drawn (unbound) state, and the browser
       fallback print (BrowserPrintAsync, this block's only caller — see js/print-element.js) is
       reachable only once a token is bound, i.e. only once the sheet has already switched to
       `<img class="qr-sticker-image">`. So this rule never matched anything, in EITHER preset, from the
       moment image mode landed (Task 6) — confirmed, not assumed, before deleting it. Its old comment
       explained the SEAM logic for splitting one page into two die-cut labels, which no longer applies
       now that the preview/print sheet only ever contains ONE sticker element (2026-08-05 duplicate-
       preview fix) — leaving a rule that split children of an element with only one child would have
       invited the next reader to "fix" it by adding a second element back, the exact bug just removed.
       The EZPL direct-print path (LabelJobBuilder/LabelSheetComposer) is unaffected — it always tiled
       the rendered bitmap itself and never depended on this CSS. */
}
/* ── label layout — screen preview AND print, ONE rule set ───────────────────────────────────
   The preview on the instance page is the label at 1:1: same mm, so what the operator sees on
   screen is what comes out of the label printer. CSS mm is an absolute unit on screen too
   (96px/25.4mm), so a single declaration serves both. These rules key off .ic-qr-card, NOT
   .is-print-target — the print target is a descendant of that card, so it inherits the preview's
   own geometry by construction and the two can never drift. Only what is genuinely print-only
   (@page, the visibility mask, the die-cut edge) lives in @media print above.
   Why an mm re-layout instead of transform:scale on the 240px screen sticker (~63.5×90mm, fits
   neither preset): a uniform scale shrinks the asset code to unreadable along with the box.
   QrAssetBindModal/QrBatchCreate are untouched — they keep the original 240px screen sticker. */

/* ── preset A: 60×40 mm stock, tag PRINTED SIDEWAYS ──────────────────────────────────────────
   The tag design is portrait (bar / QR / code / bar stacked vertically) and the stock is landscape.
   Squeezing the stack into a 60-wide × 40-tall box was WRONG (2026-08-03, rejected on sight): it
   flattens the design — the bars go thin, the QR shrinks to 17mm — instead of using the label.
   What the label actually wants is the paper TURNED: the tag keeps its own portrait proportions at
   40mm wide × 60mm tall, and the PRINT step rotates it 90° onto the 60×40 page (see
   body.is-printing-element.print-60x40 in @media print). 40×60 rotated is exactly 60×40, so nothing
   is scaled or cropped, and the QR gets 30mm instead of 17 — roughly 3× the scan area.
   The preview therefore stays PORTRAIT and upright: it shows the tag as it reads in the hand, which
   is the orientation the operator sticks it on in. */
.ic-qr-card .qr-sticker {
    width: 40mm; height: 60mm; box-sizing: border-box;
    display: flex; flex-direction: column; overflow: hidden;
}
.ic-qr-card .qr-sticker .qr-sticker-head,
.ic-qr-card .qr-sticker .qr-sticker-foot {
    flex: 0 0 auto; padding: 1.5mm; font-size: 3mm; line-height: 1.2;
}
.ic-qr-card .qr-sticker .qr-sticker-body {
    flex: 1 1 auto; min-height: 0; justify-content: center; padding: 2mm; gap: 1.5mm;
}
/* 30mm off a ~160px canvas prints at ~135dpi — coarse for text, irrelevant for a QR: what matters
   is module size, and 30mm makes every module ~1mm, far above any phone camera's floor. */
.ic-qr-card .qr-sticker .qr-sticker-canvas { width: 30mm; height: 30mm; }
.ic-qr-card .qr-sticker .qr-sticker-code {
    font-size: 3mm; line-height: 1.2; padding: .8mm 2mm; border-width: .4mm; border-radius: 1.5mm;
}
.ic-qr-card .qr-sticker .qr-sticker-sku { font-size: 2.2mm; line-height: 1.2; }
/* Unbound: the dashed placeholder was sized (min-height ~168px) to occupy the OLD 240px card's QR
   stack. Inside a fixed-height label box that overflows, so it fills the box instead — the empty
   state now previews the label's footprint, which is the point of showing it at all. */
.ic-qr-card .qr-sticker .ic-qr-card__empty {
    min-height: 0; flex: 1 1 auto; align-self: stretch;
    margin: 1.5mm; padding: 1mm; font-size: 2.4mm; line-height: 1.3;
}

/* ── preset B: 50×25 mm stock — THE SAME TAG, smaller ────────────────────────────────────────
   One design across both presets (user decision, 2026-08-03): an earlier pass gave this size its
   own landscape composition (QR left, text stacked right) and that was rejected — two labels off
   the same system must not read as two different products. So this preset only re-sizes: same
   portrait tag, 25mm wide × 50mm tall, same 90°-at-print rotation onto the 50×25 stock.
   Only the type and the QR scale down; nothing moves, nothing is dropped. */
.ic-qr-card.is-50x25 .qr-sticker { width: 25mm; height: 50mm; }
.ic-qr-card.is-50x25 .qr-sticker .qr-sticker-head,
.ic-qr-card.is-50x25 .qr-sticker .qr-sticker-foot { padding: 1mm; font-size: 2.4mm; }
.ic-qr-card.is-50x25 .qr-sticker .qr-sticker-body { padding: 1.5mm; gap: 1mm; }
.ic-qr-card.is-50x25 .qr-sticker .qr-sticker-canvas { width: 21mm; height: 21mm; }
.ic-qr-card.is-50x25 .qr-sticker .qr-sticker-code {
    font-size: 2.4mm; padding: .5mm 1.2mm; border-width: .3mm; border-radius: 1mm;
}
.ic-qr-card.is-50x25 .qr-sticker .qr-sticker-sku { font-size: 1.9mm; }

/* The sheet is one page of stock. On screen it lays its labels out left-to-right; at print time this
   flow layout is replaced outright by absolute placement in page coordinates (see the print block
   above). */
.ic-qr-card__sheet { display: flex; justify-content: center; align-self: center; }

@media screen {
    /* 2026-08-05: the `.ic-qr-card__sheet .qr-sticker + .qr-sticker { display: none }` rule that used
       to sit here is REMOVED — it dates from a JS-drawn-<canvas> era when InstanceCreate.razor rendered
       one `.qr-sticker` PER die-cut label on the 2-across preset (two canvases, one hidden by this
       rule, both needing a live 2D context for renderQrCode ahead of print). That markup is gone (Task
       6 moved the preview to image mode; the leftover render-twice loop itself was removed 2026-08-05),
       so the sheet only ever contains ONE sticker element now and `X + X` can never match. Deleted the
       rule WITH its comment, not just the rule: the comment described how CSS hides a duplicate, and
       leaving that claim in place next to markup that no longer produces a duplicate would read as
       standing permission to add one back "because CSS will hide it" — which is the exact bug this was
       written to fix. The duplication that legitimately still exists — the printed 2-across SHEET
       carrying the SAME tag on both die-cut labels — is real stock, not a rendering artifact, and lives
       entirely in LabelJobBuilder/LabelSheetComposer on the print path; nothing on the preview side
       needs to hide anything from it. */

    /* Preview a shade larger than the physical label. The mm geometry is what the print depends on,
       so it must not change — `zoom` scales the rendered result instead of the authored sizes, which
       keeps the single source of truth intact and cannot leak into the print (this block is
       @media screen). 1.25 is a legibility nudge, not a rescale: the operator still reads the code
       and the lot line on a 40mm-wide tag. */
    .ic-qr-card__sheet { zoom: 1.25; }
}

/* Preset picker sits directly above the print button, both full-width in the card column. */
.ic-qr-card__preset { width: 100%; }

.ed-table-card { background: var(--color-component-card-bg); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-button); overflow: hidden; }
/* ===========================================================================================
   InstanceCreate.razor — mobile design pass (<=560px only).
   Everything in this block is additive and gated behind the media query: desktop's already-
   correct ~1440px layout (every unscoped rule above/elsewhere in this file) renders byte-for-byte
   unchanged. The goal here isn't just "doesn't overflow" — it's a page that reads as built for a
   phone: tighter card chrome so content isn't fighting desktop padding, clearer section rhythm,
   and each of the dense desktop widgets (tab strip, sticky action bar, segmented inspection
   controls) restyled to its own native-mobile shape. All values are existing tokens already used
   elsewhere in this file — no new hex/px literals invented. =========================================== */
@media (max-width: 560px) {
    /* Section title sits flush left with the tab/field content below it once the head's own
       horizontal padding is reduced — keeps a consistent left edge down the whole page.
       `:ed-card__head` is a SIBLING of `.ic-layout` (both direct children of the same top-level
       `.ed-card`), not an ancestor/descendant, so `:has(.ic-layout)` on the card itself is what
       actually scopes this to InstanceCreate.razor's card without a new wrapper class or touching
       any other `.ed-card` on the 6 other pages that share this chrome. */
    .ed-card:has(.ic-layout) > .ed-card__head { padding: var(--space-sm) var(--space-md); }
    .ed-card:has(.ic-layout) > .ed-card__head .ed-card__title { font-size: var(--font-size-base); }

    /* Form padding: .vd-form's desktop 0.25rem is already tight, but .ic-layout__form ALSO adds
       --space-md (16px) on top of it — doubled up with the card's own edge, the fields sit further
       from the screen edge than the card head above them. Drop the form wrapper's own padding and
       let .vd-form's smaller padding be the only inset, so field left-edges line up with the title. */
    .ic-layout__form { padding: var(--space-sm); }
    .vd-form { gap: var(--space-sm); }

    /* Metadata tab-body grids already collapse to 1 column (rule above) — tighten the outer
       padding to match the tightened card padding above instead of the desktop 1.25rem inset. */
    .vd-fields-grid { padding: var(--space-md); gap: var(--space-md); }

    /* Field label breathing room — a touch more space between stacked single-column fields than
       desktop's 3-up grid needs, so the page reads as distinct rows rather than a dense list. */
    .vd-field { gap: var(--space-xs); }

    /* Tab strip: beyond just scrolling (rule above), give it a native-mobile density — smaller
       side padding per tab (Figma's 24px desktop padding is generous because tabs share a wide
       card; 5 tabs at that padding is what forces the scroll in the first place) and a slightly
       smaller icon/label so more of the strip is visible per swipe without shrinking the 44px+
       tap height (13px top/bottom padding + line height already clears that). */
    .sd-tabs { gap: 2px; }
    .sd-tab { padding: 13px 14px; font-size: var(--font-size-caption); gap: 6px; }

    /* Sticky action bar: sits full-bleed against the screen edge already (rule above adds side
       padding); add a top border + background always-on (not just while .is-stuck) so the bar
       reads as a fixed mobile footer bar from the moment the page loads, the same way native app
       bottom bars look, rather than only gaining chrome once you scroll past the fold. */
    .ed-actions {
        background: var(--color-primary-surface);
        border-top-color: var(--color-text-base-border);
        box-shadow: 0 -2px 10px rgba(15, 23, 42, .06);
    }
}

.ed-table-card__head { display: flex; align-items: center; justify-content: space-between;
    padding: 1rem 1.25rem; border-bottom: 1px solid var(--color-text-base-disabled-bg); }
.ed-table-card__title { display: flex; align-items: center; gap: var(--space-sm);
    font-size: var(--font-size-base); font-weight: var(--font-weight-semibold); margin: var(--space-0); color: var(--color-neutral-title-content); }
.ed-table-card__actions { display: flex; align-items: center; gap: .85rem; }
.ed-table-card__count { font-size: var(--font-size-caption); color: var(--color-text-base-placeholder-text); }
.ed-btn--cert-add { height: 34px; background: var(--color-blue-100); color: var(--color-blue-700); font-weight: var(--font-weight-semibold); }
.ed-table__scroll { overflow-x: auto; }
.ed-table { width: 100%; border-collapse: collapse; font-size: var(--font-size-table-line); table-layout: fixed; }
.ed-table thead th { text-align: left; height: 68px; padding: 0 var(--space-md); background: var(--color-navy-blue-900); color: var(--color-text-base-border); font-weight: var(--font-weight-medium); white-space: nowrap; }
/* Red accent bar on the header's left edge (design mockup). */
.ed-table thead th:first-child { border-left: 3px solid var(--color-status-error); }
.ed-table tbody td { height: 60px; padding: 0 var(--space-md); border-bottom: 1px solid var(--color-text-base-disabled-bg); color: var(--color-neutral-description-icon-form-divider); overflow: hidden; text-overflow: ellipsis; }
/* Zebra-striped rows: white / slate-200 (design). */
.ed-table tbody tr:nth-child(even) td { background: var(--color-text-base-border); }
/* Two-line header: Thai label + English gloss in parentheses, stacked (design: Employeedetail.png).
   Empty in the English locale (redundant there) — :empty collapses it so the English header stays one line. */
.ed-table thead th .ed-th-sub { display: block; font-weight: var(--font-weight-regular); font-size: var(--font-size-label); color: var(--color-text-base-placeholder-text); white-space: nowrap; }
.ed-table thead th .ed-th-sub:empty { display: none; }
.ed-table .col-cert-no { width: 13%; }
.ed-table td.col-cert-no { white-space: nowrap; }
.ed-table .col-cert-issue,
.ed-table .col-cert-expiry { width: 15%; }
.ed-table .col-cert-attachment { width: 11%; }
.ed-table .col-cert-status { width: 10%; }
.ed-table .col-cert-action { width: 9%; text-align: right; }
.ed-table tbody td.col-cert-action { text-align: right; }
.ed-cell-mono { font-family: ui-monospace, monospace; color: var(--color-neutral-description-icon-form-divider); }
.ed-cell-muted { color: var(--color-text-base-placeholder-text); }
.ed-cell-danger { color: var(--color-status-error); font-weight: var(--font-weight-medium); }
.ed-link { color: var(--color-text-base-link); text-decoration: none; }
.ed-link--btn { background: none; border: none; padding: var(--space-0); font: inherit; cursor: pointer; }
/* Sticky action bar: pins to the bottom of the scroll container (.content) when the form
   overflows. Negative margins cancel .content's 24px/32px padding so the white fill is full-bleed;
   padding restores inner spacing. The white fill/border/shadow are applied ONLY while the bar
   floats over overflowing content — sticky-actions.js toggles .is-stuck (see that file). When the
   form fits or is scrolled to the bottom, the bar is transparent and sits inline. */
/* .content is a flex column (MainLayout) so .ed-actions can bottom-align; keep page blocks at their
   natural height (no shrink) so tall pages overflow + scroll instead of squashing. */
.content > * { flex-shrink: 0; }
.ed-actions { position: sticky; bottom: -24px; z-index: 5;
    display: flex; justify-content: center; align-items: center; gap: var(--space-md);
    background: transparent; border-top: 1px solid transparent;
    transition: background .15s ease, border-color .15s ease, box-shadow .15s ease; 
    padding: 0.75rem 0;}
.ed-actions.is-stuck { background: var(--color-primary-surface); border-top-color: var(--color-text-base-border);
    box-shadow: 0 -2px 10px rgba(15, 23, 42, .06); }
/* Inline variant (Employee pages): sits at its natural position, never pinned to the viewport. */
.ed-actions--inline { position: static; margin: var(--space-0); padding: var(--space-lg) 0; }
.ed-actions .btn { min-width: 200px; height: 48px; justify-content: center; font-size: var(--font-size-base); }
.ed-actions .btn--back { background: var(--color-text-base-button-cancel); color: var(--color-navy-blue-900); text-decoration: none; outline: none; }
.ed-actions .btn--back:hover { background: var(--color-text-base-button-cancel); }
/* Two 200px-min-width buttons + gap (~416px) don't fit a 375px viewport and force the whole page to
   scroll horizontally, since this bar is sticky at the page's own width, not clipped by anything.
   Below 560px, drop the fixed min-width and let each button share the row equally instead. */
@media (max-width: 560px) {
    .ed-actions { padding-left: var(--space-md); padding-right: var(--space-md); box-sizing: border-box; }
    .ed-actions .btn { min-width: 0; flex: 1 1 0; }
}
.ed-icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px;
    border: none; border-radius: 50%; background: var(--color-text-base-disabled-bg); cursor: pointer; }
.ed-icon-btn--edit { background: var(--color-semantic-extra-warning-bg); }
.ed-icon-btn--delete { background: var(--color-red-100); }
.ed-icon-btn:disabled { opacity: .65; cursor: default; }

.ed-badge { font-size: var(--font-size-tiny); font-weight: var(--font-weight-semibold); letter-spacing: .03em; padding: var(--space-xs) var(--space-sm); border-radius: var(--radius-md); }
.ed-badge--valid { background: var(--color-status-success-vbright); color: var(--color-green-700); }
.ed-badge--expiring { background: var(--color-status-alert-vbright); color: var(--color-semantic-extra-warning-text); }
.ed-badge--expired { background: var(--color-status-error-vbright); color: var(--color-red-700); }

/* Profile strip — right-aligned status/employment-type/date-range stack (design: badge is clickable
   to open the status-change modal; date range is a backend-gap placeholder). */
.ed-profile__badges { display: flex; flex-direction: column; justify-content: space-between; align-items: flex-end; gap: .75rem; flex: 0 0 auto;}
.ed-status-trigger { background: none; border: none; padding: var(--space-0); margin: var(--space-0); cursor: pointer; }
.ed-profile__daterange { font-size: var(--font-size-tiny); color: var(--color-text-base-placeholder-text); white-space: nowrap; }

/* Sub-section header inside the profile card (e.g. "ข้อมูลติดต่อ" ahead of the contact grid) */
.ed-card__head--sub { padding: .25rem 1.25rem; }

/* ===== Employee modals (status change / reset password / upload license / delete license) =====
   Follows the AssetPickerDialog overlay/modal shape (Components/Shared/Order/AssetPickerDialog.razor.css)
   with its own emx- prefix since these are simpler single-column forms, not a picker table. */
.emx-overlay { position: fixed; inset: 0; background: rgba(15, 23, 42, .45);
    display: flex; align-items: center; justify-content: center; z-index: 9999; padding: var(--space-lg); }
.emx-modal { background: var(--color-primary-surface); border-radius: var(--radius-button); width: 100%; max-width: 420px; max-height: 92vh;
    overflow-y: auto; box-shadow: 0 12px 40px rgba(0, 0, 0, .25); display: flex; flex-direction: column; }
.emx-modal--narrow { max-width: 380px; }
.emx-modal--wide { max-width: 480px; }

.emx-modal__head { padding: var(--space-lg) var(--space-lg) 0; }
.emx-modal__title { font-size: var(--font-size-title); font-weight: var(--font-weight-bold); margin: var(--space-0); color: var(--color-neutral-title-content); }
.emx-modal__subtitle { margin: .35rem 0 0; font-size: var(--font-size-caption); color: var(--color-text-base-description-icon-form); }

.emx-modal__body { padding: 1.25rem 1.5rem; display: flex; flex-direction: column; gap: var(--space-md); }

.emx-field { display: flex; flex-direction: column; gap: var(--space-sm); }
.emx-field__label { font-size: var(--font-size-label); font-weight: var(--font-weight-semibold); color: var(--color-neutral-description-icon-form-divider); }
.emx-field__label--required::after { content: ' *'; color: var(--color-status-error); }
.emx-field__hint { font-size: var(--font-size-texthelp); color: var(--color-text-base-placeholder-text); }
.emx-field__error { font-size: var(--font-size-caption); color: var(--color-status-error); }

.emx-input { height: 40px; padding: 0 .75rem; border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg);
    font-size: var(--font-size-body); background: var(--color-primary-surface); color: var(--color-navy-blue-900); }
.emx-input:disabled { background: var(--color-neutral-background); color: var(--color-text-base-placeholder-text); }

.emx-textarea { min-height: 72px; padding: .6rem .75rem; border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg);
    font-size: var(--font-size-body); color: var(--color-navy-blue-900); resize: vertical; background: var(--color-primary-surface); }
.emx-textarea--tall { min-height: 100px; }
.emx-textarea:disabled { background: var(--color-neutral-background); color: var(--color-text-base-placeholder-text); }
.emx-charcount { align-self: flex-end; font-size: var(--font-size-tiny); color: var(--color-text-base-placeholder-text); }

.emx-radio-group { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.emx-radio-group--two .emx-radio-pill { flex: 1 1 0; justify-content: center; }
/* Status modal: 4 option pills stretch to fill the row equally (per design). */
.emx-radio-group--fill { flex-wrap: nowrap; }
.emx-radio-group--fill .emx-radio-pill { flex: 1 1 0; justify-content: center; }
.emx-radio-pill { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-xs);
    height: 38px; padding: 0 var(--space-md); border-radius: 4px; border: 1px solid var(--color-text-base-border); background: var(--color-primary-surface);
    color: var(--color-neutral-description-icon-form-divider); font-size: var(--font-size-button); font-weight: var(--font-weight-semibold); cursor: pointer; white-space: nowrap; }
.emx-radio-group--fill .emx-radio-pill { padding: 0 var(--space-sm); }
.emx-radio-pill:has(input:disabled) { cursor: not-allowed; }
.emx-radio-pill input { position: absolute; opacity: 0; pointer-events: none; }
.emx-radio-pill--active { background: var(--color-navy-blue-900); color: var(--color-text-base-white-text); border-color: var(--color-neutral-disable); font-weight: var(--font-weight-semibold);}

.emx-date-range { display: flex; align-items: center; gap: var(--space-sm); }
.emx-date-range input[type="date"] { flex: 1 1 0; height: 40px; padding: 0 .6rem; border: 1px solid var(--color-text-base-border);
    border-radius: var(--radius-lg); font-size: var(--font-size-input); color: var(--color-neutral-description-icon-form-divider); background: var(--color-primary-surface); }
.emx-date-range input[type="date"]:disabled { background: var(--color-neutral-background); color: var(--color-text-base-placeholder-text); }
.emx-date-range__sep { color: var(--color-text-base-placeholder-text); }

.emx-dropzone { display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: var(--space-sm); padding: var(--space-lg); border: 1px dashed var(--color-text-base-button-cancel); border-radius: var(--radius-input); color: var(--color-text-base-placeholder-text);
    font-size: var(--font-size-caption); cursor: pointer; }
.emx-dropzone:has(input:disabled) { cursor: not-allowed; }
/* Icon-only variant (InstanceCreate.razor's document tab) — the base class is sized as a real drop
   zone, so with its label text removed the icon floats inside a large dashed box. This shrinks it to
   an icon-sized square hit target; the dashed border stays so it still reads as an upload affordance.
   Kept as a modifier because the base class is shared with UploadLicenseModal / MaterialLotDetail,
   which both still render icon + text and must not move. */
.emx-dropzone--icon { padding: var(--space-sm); gap: 0; }

.emx-modal__footer { display: flex; justify-content: center; gap: .75rem; padding: var(--space-md) var(--space-lg) var(--space-lg); width: 100%; }
.emx-btn { display: inline-flex; align-items: center; justify-content: center; gap: .4rem; height: 42px;
    padding: 0 var(--space-lg); border: none; border-radius: var(--radius-lg); font-size: var(--font-size-button); font-weight: var(--font-weight-semibold); cursor: pointer;
    flex: 1 1 0; }
.emx-btn--ghost { background: var(--color-text-base-disabled-bg); color: var(--color-neutral-description-icon-form-divider); }
.emx-btn--primary { background: var(--color-navy-blue-900); color: var(--color-text-base-white-text); }
.emx-btn--primary:disabled { opacity: .55; cursor: default; }
.emx-btn--danger { background: var(--color-component-button-danger-bg); color: var(--color-text-base-white-text); }
.emx-btn--danger:disabled { opacity: .55; cursor: default; }

/* ===== Order type selector ===== */
.selector-card { background: var(--color-neutral-background); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-button); padding: 2rem 2.5rem; }
.selector-card__header { display: flex; align-items: center; gap: .75rem; margin-bottom: var(--space-lg); }
.selector-card__header h1 { font-size: var(--font-size-title); font-weight: var(--font-weight-bold); margin: var(--space-0); color: var(--color-neutral-title-content); }
.selector-card__subtitle { margin: .15rem 0 0; font-size: var(--font-size-body); color: var(--color-text-base-description-icon-form); }

.selector-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-md); margin-bottom: var(--space-xl); }
.selector-grid .selector-option:nth-child(n+3) { /* bottom row: switch to 3-col */ }
.selector-grid--bottom { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-md); margin-bottom: var(--space-xl); }

.selector-option { display: flex; flex-direction: column; gap: var(--space-sm); padding: 1.25rem 1.5rem;
    border: 1px solid var(--color-text-base-button-cancel); border-radius: var(--radius-button); background: var(--color-text-base-background-soft); cursor: pointer;
    text-align: left; transition: border-color .15s, box-shadow .15s; min-height: 100px; }
.selector-option:hover:not(:disabled) { border-color: var(--color-blue-300); box-shadow: 0 2px 8px rgba(37,99,235,.1); }
.selector-option strong { font-size: var(--font-size-base); color: var(--color-neutral-title-content); }
.selector-option span { font-size: var(--font-size-caption); color: var(--color-text-base-description-icon-form); }

.selector-option--active { background: var(--color-navy-blue-900); border-color: var(--color-navy-blue-900); cursor: pointer; }
.selector-option--active strong { color: var(--color-text-base-white-text); }
.selector-option--active span { color: var(--color-text-base-placeholder-text); }
.selector-option--active:hover { border-color: var(--color-neutral-description-icon-form-divider); }

.selector-option--selected { outline: 3px solid var(--color-primary-primary); outline-offset: -3px; }

.selector-option--disabled { background: var(--color-text-base-disabled-bg); border-color: var(--color-text-base-border); opacity: .65; cursor: not-allowed; }
.selector-option--disabled strong { color: var(--color-neutral-description-icon-form-divider); }
.selector-option--disabled span { color: var(--color-text-base-placeholder-text); }

.selector-actions { display: flex; justify-content: center; gap: .75rem; padding-top: var(--space-sm); }

/* ===== Order status badges ===== */
.status-badge { display: inline-flex; align-items: center; gap: .4rem; font-size: var(--font-size-status);
    font-weight: var(--font-weight-medium); white-space: nowrap; }
.status-badge::before { content: ''; width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }

.badge--draft { color: var(--color-text-base-description-icon-form); }
.badge--draft::before { background: var(--color-text-base-placeholder-text); }
.badge--pending { color: var(--color-semantic-extra-warning-text); }
.badge--pending::before { background: var(--color-status-waiting); }
.badge--warning { color: var(--color-semantic-extra-highlight-text); }
.badge--warning::before { background: var(--color-orange-500); }
.badge--danger { color: var(--color-status-error); }
.badge--danger::before { background: var(--color-red-500); }
.badge--info { color: var(--color-primary-primary); }
.badge--info::before { background: var(--color-blue-500); }
.badge--primary { color: var(--color-status-pending); }
.badge--primary::before { background: var(--color-purple-500); }
.badge--success { color: var(--color-green-700); }
.badge--success::before { background: var(--color-status-success); }
.badge--muted { color: var(--color-text-base-placeholder-text); }
.badge--muted::before { background: var(--color-text-base-button-cancel); }

/* ===== Order customer header (oh-*) ===== */
.oh-card { background: var(--color-component-card-bg); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-button); overflow: hidden; margin-bottom: var(--space-md); }
.oh-card__head { display: flex; align-items: center; justify-content: space-between;
    padding: var(--space-md) var(--space-lg); background: var(--color-neutral-background); cursor: pointer; }
.oh-card__head-left { display: flex; align-items: center; gap: .6rem; }
.oh-card__title { font-size: var(--font-size-title); font-weight: var(--font-weight-bold); margin: var(--space-0); color: var(--color-neutral-title-content); }
.oh-card__accent { height: 3px; background: var(--color-component-button-danger-bg); }
.oh-card__body { padding: 1.25rem 1.5rem; display: flex; flex-direction: column; gap: var(--space-md); }

.oh-sub-head { display: flex; align-items: center; gap: var(--space-sm); margin-top: var(--space-sm); }
.oh-sub-head h3 { font-size: var(--font-size-body); font-weight: var(--font-weight-bold); margin: var(--space-0); color: var(--color-neutral-title-content); }

.oh-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: .75rem 1rem; }
@media (max-width: 900px) { .oh-grid-3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .oh-grid-3 { grid-template-columns: 1fr; } }

.oh-field { display: flex; flex-direction: column; gap: var(--space-xs); }
.oh-field--full { grid-column: 1 / -1; }
.oh-field__label { font-size: var(--font-size-label); color: var(--color-text-base-description-icon-form); font-weight: var(--font-weight-semibold); letter-spacing: .01em; }
.oh-field__input { background: var(--color-primary-surface); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg);
    padding: .55rem .75rem; font-size: var(--font-size-input); color: var(--color-navy-blue-900); min-height: 40px;
    display: flex; align-items: center; }
.oh-field__input--ro { background: var(--color-neutral-background); color: var(--color-neutral-description-icon-form-divider); }
.oh-field__input::placeholder { color: var(--color-text-base-placeholder-text); }
.oh-field__select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M3 5l3 3 3-3' fill='none' stroke='%2364748b' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right .75rem center; padding-right: var(--space-xl); }

.oh-divider { border: none; border-top: 1px solid var(--color-text-base-border); margin: var(--space-xs) 0; height: 0; }

.oh-checkbox { display: flex; align-items: center; gap: var(--space-sm); font-size: var(--font-size-body); color: var(--color-neutral-description-icon-form-divider); cursor: pointer; }
.oh-checkbox input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--color-primary-primary); }

.oh-tabs { display: flex; gap: 0; border-bottom: 2px solid var(--color-text-base-border); }
.oh-tab { display: flex; align-items: center; gap: var(--space-xs); padding: var(--space-sm) var(--space-lg);
    font-size: var(--font-size-body); font-weight: var(--font-weight-semibold); color: var(--color-text-base-placeholder-text);
    cursor: pointer; border: none; border-bottom: 2px solid transparent; margin-bottom: -2px;
    background: none; transition: color .15s, border-color .15s; }
.oh-tab:hover { color: var(--color-neutral-title-content); }
.oh-tab--active { color: var(--color-neutral-title-content); border-bottom-color: var(--color-primary-primary); }
.oh-tab:disabled { opacity: .5; cursor: not-allowed; }

.oh-search { position: relative; }
.oh-search__input { width: 100%; background: var(--color-primary-surface); border: 1px solid var(--color-text-base-border);
    border-radius: var(--radius-lg); padding: .55rem .75rem; font-size: var(--font-size-input);
    color: var(--color-navy-blue-900); min-height: 40px; }
.oh-search__input::placeholder { color: var(--color-text-base-placeholder-text); }
.oh-search__dropdown { position: absolute; top: 100%; left: 0; right: 0; z-index: 10;
    background: var(--color-primary-surface); border: 1px solid var(--color-text-base-border);
    border-top: none; border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    max-height: 200px; overflow-y: auto; }
.oh-search__item { padding: .55rem .75rem; cursor: pointer; font-size: var(--font-size-input); }
.oh-search__item:hover { background: var(--color-neutral-background); }

/* ===== Order form sections ===== */
.order-section { background: var(--color-primary-surface); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-button);
    overflow: hidden; margin-bottom: var(--space-md); }
.order-section__head { display: flex; align-items: center; justify-content: space-between;
    padding: 1rem 1.25rem; border-bottom: 1px solid var(--color-text-base-disabled-bg); cursor: pointer; }
.order-section__title { display: flex; align-items: center; gap: var(--space-sm);
    font-size: var(--font-size-base); font-weight: var(--font-weight-semibold); margin: var(--space-0); color: var(--color-neutral-title-content); }
.order-section__body { padding: 1rem 1.25rem; }

.order-bu-group { margin-bottom: var(--space-md); }
.order-bu-group__head { display: flex; align-items: center; justify-content: space-between;
    margin-bottom: var(--space-sm); }
.order-bu-group__name { font-weight: var(--font-weight-semibold); color: var(--color-neutral-title-content); }
.order-bu-group__count { color: var(--color-text-base-placeholder-text); font-size: var(--font-size-caption); margin-left: var(--space-sm); }

/* ===== BU Allowance / Permissions pages (Figma node 956:43752) ===== */
.bua { display: flex; flex-direction: column; gap: var(--space-md);
    font-family: var(--font-family-help), 'Segoe UI', sans-serif; color: var(--color-neutral-title-content); }

.bua-head { display: flex; flex-direction: column; gap: var(--space-sm); }
.bua-title { margin: var(--space-0); font-size: var(--font-size-heading); font-weight: var(--font-weight-bold); line-height: var(--line-height-heading); color: var(--color-text-base-title-content); }
.bua-crumbs { display: flex; align-items: center; gap: var(--space-sm); font-size: var(--font-size-nav); color: var(--color-text-base-description-icon-form); }
.bua-crumbs a { color: var(--color-text-base-description-icon-form); text-decoration: none; }
.bua-crumb-home { display: inline-flex; align-items: center; gap: 6px; }
.bua-crumbs .sep { color: var(--color-text-base-button-cancel); }
.bua-crumbs .crumb { color: var(--color-primary-navigation-bg); }
.bua-crumbs .crumb.current { color: var(--color-primary-primary-bright); font-weight: var(--font-weight-semibold); }

/* Folder-style tabs: sit flush on top of the card below (active tab merges into the card,
   red accent bar marks the join). The negative margin cancels the .bua column gap so there is
   no visible seam between the tab row and the card. */
.bua-tabs { display: flex; gap: 6px; padding: var(--space-0); background: none; border-radius: var(--radius-none);
    align-items: flex-end; position: relative; z-index: 2; }
.bua-tab { display: inline-flex; align-items: center; gap: var(--space-sm); padding: 14px 28px;
    font-size: var(--font-size-base); font-weight: var(--font-weight-semibold); color: var(--color-text-base-description-icon-form); text-decoration: none;
    background: var(--color-text-base-disabled-bg); border: 1px solid var(--color-text-base-border); border-bottom: none;
    border-radius: var(--radius-button) var(--radius-button) 0 0; }
.bua-tab:hover { color: var(--color-neutral-title-content); background: var(--color-text-base-border); }
.bua-tab.active { color: var(--color-text-base-white-text); background: var(--color-navy-blue-900); border-color: var(--color-navy-blue-900);
    box-shadow: inset 0 -3px 0 var(--color-status-error); }
.bua-tab.active:hover { background: var(--color-navy-blue-900); }

/* overflow: clip (not hidden) clips the rounded corners WITHOUT becoming a scroll container — so the
   sticky module-nav and sticky table header stick to the page scroll instead of being trapped. */
.bua-card { background: var(--color-component-card-bg); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-card);
    box-shadow: 0 1px 5px rgba(33, 33, 33, 0.1); overflow: clip; }
/* Loading state: centre the spinner inside the card with generous padding. */
.bua-loading { display: flex; align-items: center; justify-content: center; padding: var(--space-3xl); }
/* Split cards are fully square + overflow:visible so the sticky module-nav and sticky table header
   can pin to the PAGE scroll (overflow:clip/hidden would trap them). The table is full-bleed, so there
   are no rounded corners to clip anyway. */
.bua-card.bua-split { border-radius: var(--radius-none); overflow: visible; }
/* Top folder tabs connect to whatever block follows (card, or the BU bar): pull it up to meet the
   tabs (cancel the .bua gap + 1px overlap to hide the seam) and square its top-LEFT corner. Top-right
   stays rounded since the folder tabs don't span the full width. */
.bua-tabs + .bua-card,
.bua-tabs + .bua-subtabs { margin-top: -17px; border-top-left-radius: var(--radius-none); }
/* The flat BU bar spans the full width and IS the card's top band: the body just below touches it
   (cancel the gap, keep the 1px border as the divider) and squares BOTH top corners. */
.bua-subtabs + .bua-card { margin-top: -16px; border-top-left-radius: var(--radius-none); border-top-right-radius: var(--radius-none); }

/* BU selector: a flat tab bar that forms the top band of the card itself — no rounded folder tabs,
   just an underline on the active BU. The bar carries the card's top border + rounding; the card
   body below squares its top so the two read as one continuous card. */
.bua-subtabs { display: flex; flex-wrap: nowrap; gap: var(--space-0); padding: var(--space-sm) 0 0;
    background: var(--color-primary-surface); border: 1px solid var(--color-text-base-border); border-bottom: none;
    border-radius: var(--radius-card) var(--radius-card) 0 0; position: relative; z-index: 1; overflow-x: auto; }
.bua-subtab { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px; padding: 12px 14px;
    background: none; border: none; border-bottom: 2px solid transparent; border-radius: var(--radius-none);
    font-family: inherit; font-size: var(--font-size-tab); font-weight: var(--font-weight-semibold); color: var(--color-text-base-description-icon-form); cursor: pointer;
    white-space: nowrap; }
.bua-subtab:hover { color: var(--color-neutral-title-content); }
.bua-subtab.active { color: var(--color-status-error); border-bottom-color: var(--color-status-error); }

/* Toolbar between the BU sub-tabs and the stacked feature sections (Groups per BU design). */
.bua-toolbar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-md);
    padding: var(--space-md) var(--space-xs); }
.bua-toolbar__info { font-size: var(--font-size-body); color: var(--color-text-base-description-icon-form); }
/* Stacked feature sections need breathing room between them. */
.bua-card + .bua-toolbar, .bua-toolbar + .bua-card, .bua-card + .bua-card { margin-top: var(--space-md); }
.bua-empty { text-align: center; color: var(--color-text-base-placeholder-text); padding: var(--space-lg); }
/* BU picker on the right of the section head (replaces the top BU tabs). */
.bua-butabs-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-md);
    flex-wrap: wrap; }
.bua-headactions { display: inline-flex; align-items: center; gap: 12px; }
.bua-buselect { display: inline-flex; align-items: center; gap: var(--space-sm); }
.bua-buselect--block { display: flex; flex-direction: column; align-items: stretch; gap: var(--space-xs); }
.bua-buselect--block .filter-input { flex: none; width: 100%; min-width: 0; height: 38px; }
.bua-buselect__label { font-size: var(--font-size-label); font-weight: var(--font-weight-semibold); color: var(--color-text-base-description-icon-form); }
.bua-buselect .filter-input { width: auto; min-width: 160px; }
/* Group picker: custom navy dropdown + an inline add button to its right. */
.bua-groupbar { display: flex; align-items: center; gap: var(--space-sm); min-width: 0; }
.bua-modnav__head { min-width: 0; border-right: 1px solid var(--color-text-base-border); }
.bua-groupdd__trigger { min-width: 0; overflow: hidden; }
/* flex-basis 0 → the dropdown fills the remaining head width at a fixed size regardless of the
   selected group's name length (the name truncates instead of stretching the trigger). */
.bua-groupdd { position: relative; flex: 1 1 0; min-width: 0; }
.bua-groupdd__trigger { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm);
    width: 100%; height: 44px; padding: 0 14px; border: none; border-radius: var(--radius-input);
    background: var(--color-navy-blue-900); color: var(--color-text-base-white-text); font-family: inherit; font-size: var(--font-size-button); font-weight: var(--font-weight-semibold);
    cursor: pointer; }
.bua-groupdd__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bua-groupdd__chev { transition: transform .15s ease; flex: none; }
.bua-groupdd.open .bua-groupdd__chev { transform: rotate(180deg); }
.bua-groupdd__backdrop { position: fixed; inset: 0; z-index: 15; border: none; background: transparent;
    padding: var(--space-0); cursor: default; }
.bua-groupdd__menu { position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 16;
    background: var(--color-primary-surface); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-button);
    box-shadow: var(--shadow-card-soft); padding: 6px; display: flex; flex-direction: column;
    gap: 2px; max-height: 280px; overflow-y: auto; }
.bua-groupdd__item { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-sm);
    text-align: left; padding: 10px 12px; border: none; border-radius: var(--radius-lg); background: none;
    font-family: inherit; font-size: var(--font-size-body); font-weight: var(--font-weight-semibold); color: var(--color-blue-700); cursor: pointer; }
.bua-groupdd__item > span:first-child { min-width: 0; overflow-wrap: anywhere; word-break: break-word; }
.bua-groupdd__item:hover { background: var(--color-text-base-disabled-bg); }
.bua-groupdd__item.active { background: var(--color-component-reward-card-bg); color: var(--color-status-error); }
.bua-groupdd__lock { flex: none; }
.bua-addbtn { display: inline-flex; align-items: center; justify-content: center; flex: none;
    width: 44px; height: 44px; border: none; border-radius: var(--radius-input); background: var(--color-navy-blue-900); color: var(--color-text-base-white-text);
    cursor: pointer; }
.bua-addbtn:hover { background: var(--color-navy-blue-800); }
/* Split card: feature areas as left vertical tabs, the selected area's table on the right. */
.bua-split { display: flex; align-items: stretch; }
/* min-width:0 defeats the flex auto-minimum so the nav is EXACTLY 240px regardless of content
   (long group names / labels truncate) — no width shift when switching BU. The right divider is drawn
   per-item (not on the nav) so the active item can simply drop it and read as connected to the panel. */
/* top: -24px cancels .content's 24px padding-top so the pinned nav sits flush under the app header
   (sticky offsets are measured from the scroll container's padding edge). */
.bua-modnav { flex: 0 0 240px; min-width: 0; display: flex; flex-direction: column;
    background: var(--color-neutral-background); position: sticky; top: -24px; align-self: flex-start; }
.bua-modnav__info { padding: 12px 16px 4px; font-size: var(--font-size-label); color: var(--color-text-base-description-icon-form); text-align: left; }
/* Group-count badge on each BU tab. */
.bua-subtab__badge { font-size: var(--font-size-label); font-weight: var(--font-weight-semibold); line-height: 1; padding: 2px 8px;
    border-radius: var(--radius-pill); background: var(--color-text-base-border); color: var(--color-neutral-description-icon-form-divider); }
.bua-subtab.active .bua-subtab__badge { background: var(--color-red-100); color: var(--color-status-error); }
/* overflow-x hidden: no horizontal scroll on the side nav (long labels truncate instead). */
.bua-modnav__list { flex: 1 1 auto; overflow-y: auto; overflow-x: hidden;
    display: flex; flex-direction: column; gap: var(--space-0); padding: var(--space-0); }
.bua-modnav__head { display: flex; flex-direction: column; gap: var(--space-sm); padding: 12px;
    border-bottom: 1px solid var(--color-text-base-border); }
.bua-save--block { width: 100%; justify-content: center; }
.bua-modnav__item { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm);
    padding: 12px 16px; border: none; border-radius: var(--radius-none);
    border-right: 1px solid var(--color-text-base-border); border-bottom: 1px solid var(--color-text-base-border);
    background: none; font-family: inherit;
    font-size: var(--font-size-nav); color: var(--color-neutral-description-icon-form-divider); text-align: left; cursor: pointer; }
.bua-modnav__item:hover { background: var(--color-text-base-disabled-bg); color: var(--color-neutral-title-content); }
/* Active item = white + red left bar, and NO right border → reads as connected to the white panel. */
.bua-modnav__item.active { background: var(--color-primary-surface); color: var(--color-navy-blue-900); font-weight: var(--font-weight-bold);
    box-shadow: inset 3px 0 0 var(--color-status-error); border-right-color: transparent; }
/* Icon + label group on the left of each nav item. Long labels truncate with an ellipsis so the
   nav never overflows horizontally. */
.bua-modnav__label { display: inline-flex; align-items: center; gap: 10px; min-width: 0; overflow: hidden; }
.bua-modnav__label > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bua-modnav__label svg { flex: none; }
.bua-modnav__count { flex: none; font-size: var(--font-size-label); opacity: .7; background: rgba(148, 163, 184, .25);
    border-radius: var(--radius-pill); padding: var(--space-px) var(--space-sm); }
.bua-modnav__item.active .bua-modnav__count { background: var(--color-red-100); color: var(--color-status-error); opacity: 1; }
.bua-modpanel { flex: 1 1 auto; min-width: 0; }
.bua-card-head { padding: var(--space-md) var(--space-lg); }
.bua-card-head--row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-md); }
.bua-card-title { margin: var(--space-0); font-size: var(--font-size-header-card); font-weight: var(--font-weight-semibold); line-height: var(--line-height-loose); color: var(--color-neutral-title-content); }
.bua-card-count { margin: var(--space-xs) 0 0; font-size: var(--font-size-caption); font-weight: var(--font-weight-bold); color: var(--color-neutral-description-icon-form-divider); }

/* Tables: full-bleed (no rounding), but the cell CONTENT lines up with the card title — the first/last
   cells carry 24px side padding so text aligns while the navy header still spans edge to edge.
   overflow visible (no inner scroll box) so the sticky thead pins to the PAGE scroll. */
.bua-table-wrap { overflow: visible; padding: var(--space-0); }
.bua-table { width: 100%; border-collapse: separate; border-spacing: 0;
    border-radius: var(--radius-none); border: none; }
.bua-table thead th:first-child, .bua-table tbody td:first-child { padding-left: var(--space-lg); }
.bua-table thead th:last-child, .bua-table tbody td:last-child { padding-right: var(--space-lg); }
/* Users table: a little breathing room below the filter divider. */
.pu-tablewrap { padding-top: var(--space-md); }
.bua-table thead th { background: var(--color-navy-blue-900); color: var(--color-text-base-white-text); font-size: var(--font-size-head-table); font-weight: var(--font-weight-bold);
    text-align: left; padding: 22px 16px; white-space: nowrap;
    position: sticky; top: -24px; z-index: 4; }
/* Red left accent on the table HEADER only — echoes the active module's red bar. */
.bua-modpanel .bua-table thead th:first-child { box-shadow: inset 3px 0 0 var(--color-status-error); }
.bua-table thead th.col-bu { text-align: center; width: 96px; }
.bua-table tbody td { padding: 14px 16px; font-size: var(--font-size-table-line); border-bottom: 1px solid var(--color-text-base-disabled-bg);
    vertical-align: middle; }
.bua-table tbody tr:last-child td { border-bottom: none; }
/* Alternate shaded band per permission group (flips whenever the code's feature group changes). */
.bua-table tbody tr.band td { background: var(--color-text-base-disabled-bg); }
.bua-table tbody tr:hover td { background: var(--color-text-base-background); }
.bua-table .cell-module { color: var(--color-text-base-description-icon-form); }
.bua-table .cell-label { font-weight: var(--font-weight-semibold); color: var(--color-neutral-title-content); }
.bua-table .cell-code { color: var(--color-text-base-description-icon-form); font-family: ui-monospace, 'Cascadia Code', monospace; font-size: var(--font-size-table-line); }
.bua-table .cell-action { font-weight: var(--font-weight-semibold); color: var(--color-neutral-title-content); white-space: nowrap; }
.bua-table .cell-check { text-align: center; width: 96px; }
.bua-table .cell-check input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--color-navy-blue-900); cursor: pointer; }

.bua-actions { display: flex; align-items: center; gap: 12px; }
.bua-save { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-sm);
    height: 44px; padding: 0 28px; border: none; border-radius: var(--radius-lg);
    background: var(--color-navy-blue-900); color: var(--color-text-base-white-text); font-family: inherit; font-size: var(--font-size-button); font-weight: var(--font-weight-semibold); cursor: pointer; }
.bua-save:disabled { opacity: 0.6; cursor: default; }
.bua-saved { font-size: var(--font-size-button); color: var(--color-status-success); font-weight: var(--font-weight-medium); }
/* Auto-save failure banner shown above the matrix table. */
.bua-error-banner { display: flex; align-items: center; gap: var(--space-sm); margin: 0 var(--space-lg) var(--space-md);
    padding: 12px 16px; border: 1px solid var(--color-red-200); border-radius: var(--radius-lg);
    background: var(--color-component-feedback-card-bg); color: var(--color-status-error); font-size: var(--font-size-body); font-weight: var(--font-weight-medium); }

/* Groups per BU: master (group list) + detail (grants) inside the card */
.bua-split { display: flex; gap: var(--space-0); align-items: stretch; }
.bua-master { flex: 0 0 280px; border-right: 1px solid var(--color-text-base-border); padding: var(--space-md); overflow-y: auto; max-height: 640px; }
.bua-master h3 { margin: 0 0 12px; font-size: var(--font-size-base); font-weight: var(--font-weight-bold); color: var(--color-neutral-title-content); }
.bua-grouplist { list-style: none; margin: 0 0 var(--space-md); padding: var(--space-0); display: flex; flex-direction: column; gap: var(--space-xs); }
.bua-groupitem { display: block; padding: 10px 12px; border-radius: var(--radius-lg); text-decoration: none;
    color: var(--color-neutral-description-icon-form-divider); font-size: var(--font-size-body); cursor: pointer; border: 1px solid transparent; }
.bua-groupitem:hover { background: var(--color-text-base-disabled-bg); }
.bua-groupitem.active { background: var(--color-text-base-background-soft); border-color: var(--color-blue-200); color: var(--color-blue-700); }
.bua-groupitem .bu { font-weight: var(--font-weight-bold); color: var(--color-primary-navigation-bg); }
.bua-groupitem.active .bu { color: var(--color-blue-700); }
.bua-newgroup { display: flex; flex-direction: column; gap: var(--space-sm); border-top: 1px solid var(--color-text-base-border); padding-top: var(--space-md); }
.bua-newgroup h4 { margin: var(--space-0); font-size: var(--font-size-body); font-weight: var(--font-weight-semibold); color: var(--color-neutral-description-icon-form-divider); }
.bua-input { height: 38px; padding: 0 12px; border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg); font-size: var(--font-size-body); }
.bua-detail { flex: 1; padding: var(--space-md) var(--space-lg); overflow-y: auto; max-height: 640px; }
.bua-detail h3 { margin: 0 0 var(--space-xs); font-size: var(--font-size-title); font-weight: var(--font-weight-semibold); color: var(--color-neutral-title-content); }
.bua-modblock { margin-top: var(--space-md); }
.bua-modblock h4 { margin: 0 0 var(--space-sm); font-size: var(--font-size-body); font-weight: var(--font-weight-bold); color: var(--color-navy-blue-900);
    text-transform: uppercase; letter-spacing: .5px; }
.bua-grant { display: flex; align-items: center; gap: var(--space-sm); padding: 6px 0; font-size: var(--font-size-body); color: var(--color-neutral-description-icon-form-divider); }
.bua-grant input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--color-navy-blue-900); }
.bua-error { color: var(--color-status-error); font-size: var(--font-size-body); margin: var(--space-sm) 0; }
.bua-tag { font-family: ui-monospace, monospace; font-size: var(--font-size-label); color: var(--color-text-base-description-icon-form);
    background: var(--color-text-base-disabled-bg); padding: 1px 6px; border-radius: 4px; }

/* ===== Users → Groups page ===== */
/* Filter bar: labelled fields in a row + a search button. */
.pu-filters { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-md); padding: var(--space-lg);
    border-bottom: 1px solid var(--color-text-base-border); }
.pu-field { display: flex; flex-direction: column; gap: 6px; flex: 1 1 180px; min-width: 0; }
.pu-field > label { font-size: var(--font-size-label); color: var(--color-text-base-description-icon-form); }
.pu-input { height: 44px; padding: 0 14px; border: 1px solid var(--color-text-base-border); border-radius: var(--radius-input);
    background: var(--color-primary-surface); font-family: inherit; font-size: var(--font-size-body); color: var(--color-neutral-title-content); min-width: 0; }
.pu-input:focus { outline: none; border-color: var(--color-navy-blue-900); box-shadow: 0 0 0 3px rgba(19, 40, 79, .12); }
.pu-searchbtn { flex: none; display: inline-flex; align-items: center; gap: var(--space-sm); height: 44px;
    padding: 0 22px; border: none; border-radius: var(--radius-input); background: var(--color-navy-blue-900); color: var(--color-text-base-white-text);
    font-family: inherit; font-size: var(--font-size-button); font-weight: var(--font-weight-semibold); cursor: pointer; }
.pu-searchbtn:hover { background: var(--color-navy-blue-800); }

/* Red left accent on the header (echoes the other permission tables). */
.pu-table thead th:first-child { box-shadow: inset 3px 0 0 var(--color-status-error); }
.pu-table thead th.pu-col-status { text-align: center; }
.pu-table thead th.pu-col-action { text-align: center; }
.pu-table td.pu-col-status { text-align: center; }
.pu-table td.pu-col-action { text-align: center; }

/* User / e-mail cell. */
.pu-usercell .pu-name { font-weight: var(--font-weight-semibold); color: var(--color-neutral-title-content); }
.pu-usercell .pu-email { font-size: var(--font-size-label); color: var(--color-status-error); font-family: ui-monospace, 'Cascadia Code', monospace; }

/* BU chips — single soft-yellow style for every BU. */
.pu-bucell { display: flex; flex-wrap: wrap; gap: 6px; }
/* Inactive BU chip — the user has no access to this BU. Solid grey so it reads as "not granted"
   next to the coloured active chips. Double-class beats base .pu-chip (same specificity, defined later). */
.pu-chip.pu-chip--off { background: var(--color-text-base-border); color: var(--color-text-base-description-icon-form); border-color: var(--color-text-base-button-cancel); opacity: .6; }
.pu-chip { display: inline-flex; align-items: center; padding: 6px 14px; border-radius: var(--radius-input);
    font-size: var(--font-size-tag); font-weight: var(--font-weight-bold); background: var(--color-semantic-extra-warning-bg); color: var(--color-semantic-extra-warning-text); border: 1px solid var(--color-yellow-300); }

/* Product-category required-metadata group chips (ProductCategoryList "กลุ่มข้อมูล" column).
   Figma Tag_/Count4. Each ticked group renders as its own tag — a comma-joined string ran together
   at a glance. Wraps rather than truncating: a category can tick up to 9 groups
   (MetadataGroupCatalog) and hiding any would misreport what the dynamic form actually requires.

   Two deliberate departures from the Figma frame, both because the mockup shows one fixed-size
   instance while this renders a variable list: the 154px width becomes content width (group names
   differ in length and a fixed box would clip them), and the 10px auto-layout gap is dropped since
   the tag holds a single text node — the 10px padding is kept as spec'd. */
.pc-chips { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.pc-chip { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center;
    padding: 10px; border-radius: var(--radius-lg); white-space: nowrap;
    font-size: var(--font-size-tag); font-weight: var(--font-weight-medium); line-height: 1.5;
    background: var(--color-semantic-extra-tag-bg); color: var(--color-semantic-extra-tag-text);
    border: 1px solid var(--color-semantic-extra-tag-border); }

/* Clickable pc-chip variant (2026-07-23, item_spec Primary Use tag multi-select — SkuDetail.razor's
   SpecPackaging tab). No dedicated Pec* tag/chip multi-select component exists yet, so this reuses the
   read-only .pc-chip's shape as a <button> toggle, borrowing the SAME selected-state token values
   .pec-choice__btn--selected already uses (components.css) — one "selected" look across the app, not a
   second hardcoded copy. */
.pc-chip[type="button"] { cursor: pointer; font-family: inherit; }
.pc-chip--unselected { background: var(--color-semantic-extra-tag-bg); color: var(--color-semantic-extra-tag-text);
    border: 1px solid var(--color-semantic-extra-tag-border); }
.pc-chip--selected { background: var(--color-navy-blue-900); color: var(--color-text-base-white-text);
    border: 1px solid var(--color-navy-blue-900); }
.pc-chip[type="button"]:disabled { cursor: not-allowed; opacity: 0.6; }
/* Toggle chip (ProductCategoryModal group selector) — text + a leading ✓ (unselected) or
   trailing ✕ (selected) icon; the icon inherits currentColor from the chip's text color. */
.pc-chip--toggle { gap: var(--space-xs); padding: 8px 12px; }
.pc-chip--toggle svg { flex: none; }
/* Toggle chip (Figma): selected = white fill + navy border/text + trailing ✕; unselected =
   slate fill, no visible border + muted grey text + leading ✓. Scoped to --toggle so the
   read-only .pc-chip keeps its amber --color-semantic-extra-tag-* palette. */
.pc-chip--toggle.pc-chip--selected {
    background: var(--color-neutral-background-over);
    color: var(--color-navy-blue-900);
    border-color: var(--color-navy-blue-900);
}
.pc-chip--toggle.pc-chip--unselected {
    background: var(--color-neutral-background-over);
    color: var(--color-text-base-disabled-text);
    border-color: var(--color-neutral-background-over);
}

/* Assigned groups — one "BU · Group" per line. */
.pu-groups .pu-grouprow { font-weight: var(--font-weight-semibold); color: var(--color-neutral-title-content); padding: var(--space-px) 0; }

/* Effective-permissions pill. */
.pu-pill { display: inline-flex; align-items: center; gap: var(--space-sm); padding: 6px 12px; border-radius: var(--radius-pill);
    font-size: var(--font-size-status); font-weight: var(--font-weight-semibold); white-space: nowrap; }
.pu-pill .pu-dot { width: 8px; height: 8px; border-radius: var(--radius-pill); background: currentColor; }
.pu-pill--ok { background: var(--color-green-50); color: var(--color-status-success); }
.pu-pill--muted { background: var(--color-text-base-disabled-bg); color: var(--color-text-base-placeholder-text); }

/* Status cell: badge + edit icon. */
.pu-statuswrap { display: inline-flex; align-items: center; gap: var(--space-sm); justify-content: center; }
.pu-status { display: inline-flex; align-items: center; padding: 4px 12px; border-radius: var(--radius-pill);
    font-size: var(--font-size-status); font-weight: var(--font-weight-semibold); }
.pu-status--on { background: var(--color-green-50); color: var(--color-status-success); }
.pu-status--off { background: var(--color-text-base-disabled-bg); color: var(--color-text-base-description-icon-form); }
.pu-iconbtn { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px;
    border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg); background: var(--color-primary-surface); color: var(--color-blue-700); cursor: pointer; }
.pu-iconbtn:hover { background: var(--color-text-base-disabled-bg); }

/* Edit dialog. */
.pu-editbody { display: flex; flex-direction: column; gap: 18px; }
.pu-edit-sub { margin: var(--space-0); font-size: var(--font-size-body); color: var(--color-text-base-description-icon-form); }
.pu-editfield { display: flex; flex-direction: column; gap: var(--space-sm); }
.pu-editfield > label { font-size: var(--font-size-label); font-weight: var(--font-weight-semibold); color: var(--color-neutral-description-icon-form-divider); }
.pu-input[readonly] { background: var(--color-neutral-background); color: var(--color-neutral-description-icon-form-divider); }
/* Group chips: selected = dark outline (removable), available = grey (addable). */
.pu-chips { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.pu-gchip { display: inline-flex; align-items: center; gap: var(--space-sm); padding: 10px 14px; border-radius: var(--radius-input);
    border: 1px solid var(--color-text-base-border); background: var(--color-text-base-disabled-bg); color: var(--color-text-base-description-icon-form); font-family: inherit; font-size: var(--font-size-body);
    font-weight: var(--font-weight-semibold); cursor: pointer; }
.pu-gchip:hover { background: var(--color-text-base-border); }
.pu-gchip.on { background: var(--color-primary-surface); border-color: var(--color-navy-blue-900); color: var(--color-navy-blue-900); }
/* Read-only group already assigned via a system / cross-BU group — shown for awareness, not editable. */
.pu-gchip--locked { cursor: default; background: var(--color-semantic-extra-highlight-bg); border-color: var(--color-orange-200); color: var(--color-semantic-extra-highlight-text); }
.pu-gchip--locked:hover { background: var(--color-semantic-extra-highlight-bg); }
.pu-edit-note { display: flex; align-items: center; gap: 6px; margin: var(--space-sm) 0 0; font-size: var(--font-size-label); color: var(--color-semantic-extra-highlight-text); }
.pu-effline { font-size: var(--font-size-body); color: var(--color-neutral-description-icon-form-divider); border-top: 1px solid var(--color-text-base-border); padding-top: 14px; }
.pu-effline b { color: var(--color-navy-blue-900); }

/* Users → Groups edit affordances inside the table */
.bua-linkbtn { background: none; border: 1px solid var(--color-text-base-button-cancel); border-radius: var(--radius-md); padding: 4px 12px;
    font-size: var(--font-size-button); color: var(--color-neutral-description-icon-form-divider); cursor: pointer; }
.bua-linkbtn:hover { background: var(--color-text-base-disabled-bg); }
.bua-checklist { display: flex; flex-direction: column; gap: var(--space-xs); }
.bua-checklist label { display: flex; align-items: center; gap: 6px; font-size: var(--font-size-label); }
.bua-preview { margin-top: var(--space-md); padding: var(--space-md) var(--space-lg); border-top: 1px solid var(--color-text-base-border); font-size: var(--font-size-body); color: var(--color-neutral-description-icon-form-divider); }
.bua-preview h3 { margin: 0 0 var(--space-sm); font-size: var(--font-size-base); color: var(--color-neutral-title-content); }

/* Create-group modal */
.bua-modal-overlay { position: fixed; inset: 0; background: rgba(15, 23, 42, 0.45);
    display: flex; align-items: center; justify-content: center; z-index: 1000; }
.bua-modal { width: 100%; max-width: 440px; background: var(--color-primary-surface); border-radius: var(--radius-card);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25); overflow: hidden; }
.bua-modal-head { display: flex; align-items: center; justify-content: space-between;
    padding: 20px 24px; border-bottom: 1px solid var(--color-text-base-border); }
.bua-modal-head h3 { margin: var(--space-0); font-size: var(--font-size-title); font-weight: var(--font-weight-bold); color: var(--color-neutral-title-content); }
.bua-modal-close { background: none; border: none; font-size: var(--font-size-summary); line-height: 1; color: var(--color-text-base-description-icon-form); cursor: pointer; }
.bua-modal-close:hover { color: var(--color-neutral-title-content); }
.bua-modal-body { padding: var(--space-lg); display: flex; flex-direction: column; gap: var(--space-md); }
.bua-field { display: flex; flex-direction: column; gap: 6px; font-size: var(--font-size-body); font-weight: var(--font-weight-medium); color: var(--color-neutral-description-icon-form-divider); }
.bua-field .bua-input { height: 40px; }
.bua-modal-foot { display: flex; align-items: center; justify-content: flex-end; gap: 12px;
    padding: var(--space-md) var(--space-lg); border-top: 1px solid var(--color-text-base-border); }
/* Footer buttons share one size (Cancel is a link-button, Create a save-button by default). */
.bua-modal-foot .bua-linkbtn,
.bua-modal-foot .bua-save { height: 44px; padding: 0 var(--space-lg); border-radius: var(--radius-lg);
    font-size: var(--font-size-button); font-weight: var(--font-weight-semibold); }
.bua-modal--wide { max-width: 720px; }
.bua-modal-split { flex-direction: row; gap: var(--space-lg); }
.bua-modal-col { flex: 1; min-width: 0; }
.bua-modal-col--preview { border-left: 1px solid var(--color-text-base-border); padding-left: var(--space-lg); }
.bua-col-label { margin: 0 0 12px; font-size: var(--font-size-body); font-weight: var(--font-weight-bold); color: var(--color-navy-blue-900);
    text-transform: uppercase; letter-spacing: .5px; }
.bua-checklist { max-height: 340px; overflow-y: auto; }
.bua-preview-stat { display: flex; gap: var(--space-lg); margin-bottom: 12px; }
.bua-preview-stat div { display: flex; flex-direction: column; }
.bua-preview-stat b { font-size: var(--font-size-summary); font-weight: var(--font-weight-bold); color: var(--color-navy-blue-900); line-height: 1; }
.bua-preview-stat span { font-size: var(--font-size-label); color: var(--color-text-base-description-icon-form); margin-top: var(--space-xs); }
.bua-preview-menus { font-size: var(--font-size-label); color: var(--color-neutral-description-icon-form-divider); line-height: 1.6; margin: var(--space-0); word-break: break-word; }

/* Search box in card head */
.bua-search { display: inline-flex; align-items: center; gap: var(--space-sm); height: 40px; padding: 0 12px;
    border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg); background: var(--color-primary-surface); min-width: 260px; }
.bua-search-input { border: none; outline: none; font-family: inherit; font-size: var(--font-size-body);
    color: var(--color-neutral-title-content); background: none; flex: 1; min-width: 0; }

/* Pager */
.bua-pager { display: flex; align-items: center; justify-content: center; gap: var(--space-md);
    padding: var(--space-md) var(--space-lg); border-top: 1px solid var(--color-text-base-border); }
.bua-pager-info { font-size: var(--font-size-body); color: var(--color-neutral-description-icon-form-divider); }
.bua-linkbtn:disabled { opacity: .5; cursor: default; }

/* ===== Settings hub ===== */
.set-page { display: flex; flex-direction: column; gap: var(--space-lg);
    font-family: var(--font-family-help), 'Segoe UI', sans-serif; color: var(--color-neutral-title-content); }
.set-head { display: flex; flex-direction: column; gap: var(--space-xs); }
.set-title { margin: var(--space-0); font-size: var(--font-size-heading); font-weight: var(--font-weight-bold); line-height: var(--line-height-heading); color: var(--color-text-base-title-content); }
.set-subtitle { margin: var(--space-0); font-size: var(--font-size-base); color: var(--color-text-base-description-icon-form); }

.set-section { display: flex; flex-direction: column; gap: 12px; }
.set-section-title { margin: var(--space-0); font-size: var(--font-size-title); font-weight: var(--font-weight-bold); color: var(--color-navy-blue-900); }

/* Cards tile horizontally (3-up on a wide viewport, reflowing down to 1-up) — the icon chip
   stacks above the title/desc block, arrow pinned to the right edge. */
.set-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }
.set-card { position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
    padding: 16px 44px 16px 16px;
    background: var(--color-component-card-bg); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-card); text-decoration: none;
    transition: box-shadow .15s ease, border-color .15s ease, transform .15s ease; }
.set-card:hover { border-color: var(--color-blue-200); }
.set-ico { flex-shrink: 0; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center;
    background: var(--color-blue-100); border-radius: var(--radius-button); color: var(--color-blue-600); }
.set-card-body { display: flex; flex-direction: column; gap: var(--space-xs); min-width: 0; }
.set-card-title { font-size: var(--font-size-base); font-weight: var(--font-weight-semibold); color: var(--color-neutral-title-content); }
.set-card-desc { font-size: var(--font-size-body); color: var(--color-text-base-description-icon-form); line-height: 1.4; }
.set-card-arrow { position: absolute; right: 16px; top: 50%; transform: translateY(-50%); display: flex; align-items: center; }

/* ═══════════════════════════════════════════════════════════
   Asset History (ah-*) + Timeline (tl-*)
   Page: /assets/{id}/history
   ═══════════════════════════════════════════════════════════ */

/* ── Asset header card ── */
.ah-card { background: var(--color-component-card-bg); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-input);
    box-shadow: 0 1px 3px rgba(15,23,42,.06); margin-bottom: var(--space-md); }
.ah-card__head { display: flex; align-items: flex-start; justify-content: space-between;
    padding: 20px 24px 0; gap: var(--space-md); }
.ah-card__title-group { display: flex; flex-direction: column; gap: var(--space-xs); min-width: 0; }
.ah-card__title { font-size: var(--font-size-title); font-weight: var(--font-weight-bold); color: var(--color-navy-blue-900); line-height: 1.3; }
.ah-card__subtitle { font-size: var(--font-size-label); color: var(--color-text-base-description-icon-form); }

.ah-status { display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px;
    border-radius: var(--radius-modal); font-size: var(--font-size-label); font-weight: var(--font-weight-semibold); letter-spacing: .02em;
    white-space: nowrap; flex-shrink: 0; }
.ah-status__dot { width: 7px; height: 7px; border-radius: 50%; }
.ah-status--available { background: var(--color-status-success-vbright); color: var(--color-status-success); }
.ah-status--available .ah-status__dot { background: var(--color-status-success); }
.ah-status--inuse { background: var(--color-semantic-extra-warning-bg); color: var(--color-status-waiting); }
.ah-status--inuse .ah-status__dot { background: var(--color-status-waiting); }
.ah-status--repair { background: var(--color-component-feedback-card-bg); color: var(--color-status-error); }
.ah-status--repair .ah-status__dot { background: var(--color-component-button-danger-bg); }
.ah-status--transit { background: var(--color-status-pending-vbright); color: var(--color-status-pending); }
.ah-status--transit .ah-status__dot { background: var(--color-status-pending); }
.ah-status--pending { background: var(--color-blue-100); color: var(--color-primary-primary); }
.ah-status--pending .ah-status__dot { background: var(--color-component-button-primary-bg); }
.ah-status--disabled { background: var(--color-neutral-background-over); color: var(--color-neutral-button-cancel); }
.ah-status--disabled .ah-status__dot { background: var(--color-neutral-button-cancel); }
.ah-status--cancelled { background: var(--color-status-error-vbright); color: var(--color-red-700); }
.ah-status--cancelled .ah-status__dot { background: var(--color-red-700); }
.ah-status--lost { background: var(--color-component-feedback-card-bg); color: var(--color-status-error); }
.ah-status--lost .ah-status__dot { background: var(--color-component-button-danger-bg); }

.ah-infogrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-0);
    padding: 16px 24px 20px; }
@media (max-width: 900px) { .ah-infogrid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .ah-infogrid { grid-template-columns: 1fr; } }

.ah-field { padding: var(--space-sm) 0; }
.ah-field__label { font-size: var(--font-size-tiny); font-weight: var(--font-weight-semibold); color: var(--color-text-base-placeholder-text);
    text-transform: uppercase; letter-spacing: .05em; margin-bottom: 2px; }
.ah-field__value { font-size: var(--font-size-body); color: var(--color-navy-blue-900); }
.ah-field__value--mono { font-family: "SF Mono","Cascadia Code","Fira Code",monospace;
    font-size: var(--font-size-label); color: var(--color-text-base-description-icon-form); }

.ah-scancode { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px;
    background: var(--color-text-base-disabled-bg); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-md);
    font-family: "SF Mono","Cascadia Code","Fira Code",monospace;
    font-size: var(--font-size-tiny); color: var(--color-text-base-description-icon-form); }
.ah-scancode__icon { font-size: var(--font-size-label); opacity: .6; }

/* ── Timeline card ── */
.tl-card { background: var(--color-component-card-bg); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-input);
    box-shadow: 0 1px 3px rgba(15,23,42,.06); }
.tl-card__head { display: flex; align-items: center; justify-content: space-between;
    padding: var(--space-md) var(--space-lg); border-bottom: 1px solid var(--color-text-base-border); }
.tl-card__title { font-size: var(--font-size-body); font-weight: var(--font-weight-bold); color: var(--color-navy-blue-900); }
.tl-card__count { font-size: var(--font-size-label); color: var(--color-text-base-placeholder-text); background: var(--color-text-base-disabled-bg);
    padding: 2px 10px; border-radius: var(--radius-button); font-variant-numeric: tabular-nums; }

.tl-body { padding: var(--space-xs) var(--space-lg) var(--space-lg); }
.tl-list { position: relative; list-style: none; }
.tl-list::before { content: ""; position: absolute; left: 15px; top: 24px; bottom: 24px;
    width: 2px; background: var(--color-text-base-border); border-radius: 1px; }

.tl-event { position: relative; display: grid; grid-template-columns: 30px 1fr;
    gap: var(--space-md); padding: var(--space-md) 0; }
.tl-event + .tl-event { border-top: 1px solid var(--color-text-base-disabled-bg); }

.tl-dot { width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--color-primary-surface);
    margin-top: var(--space-xs); justify-self: center; position: relative; z-index: 1;
    box-shadow: 0 0 0 3px var(--color-primary-surface); }
.tl-dot--qr { background: var(--color-purple-500); }
.tl-dot--transfer { background: #0ea5e9; }
.tl-dot--delivery { background: var(--color-status-success); }
.tl-dot--maintenance { background: var(--color-status-waiting); }
.tl-dot--generic { background: var(--color-text-base-description-icon-form); }

.tl-content { min-width: 0; }
.tl-header { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; margin-bottom: var(--space-xs); }
.tl-type { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: var(--radius-md);
    font-size: var(--font-size-tiny); font-weight: var(--font-weight-semibold); letter-spacing: .03em; }
.tl-type--qr { background: var(--color-status-pending-vbright); color: var(--color-purple-500); }
.tl-type--transfer { background: var(--color-primary-primary-very-bright); color: #0ea5e9; }
.tl-type--delivery { background: var(--color-status-success-vbright); color: var(--color-status-success); }
.tl-type--maintenance { background: var(--color-semantic-extra-warning-bg); color: var(--color-status-waiting); }
.tl-type--generic { background: var(--color-text-base-disabled-bg); color: var(--color-text-base-description-icon-form); }

.tl-date { font-size: var(--font-size-label); color: var(--color-text-base-placeholder-text); font-variant-numeric: tabular-nums; }
.tl-desc { font-size: var(--font-size-label); color: var(--color-text-base-description-icon-form); line-height: 1.5; }

.tl-details { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--space-sm); }
.tl-chip { display: inline-flex; align-items: center; gap: var(--space-xs); padding: 3px 10px;
    border-radius: var(--radius-md); background: var(--color-text-base-disabled-bg); border: 1px solid var(--color-text-base-border);
    font-size: var(--font-size-tiny); color: var(--color-text-base-description-icon-form); }
.tl-chip__label { font-weight: var(--font-weight-semibold); color: var(--color-text-base-placeholder-text); text-transform: uppercase;
    letter-spacing: .04em; margin-right: 2px; }

.tl-remark { margin-top: 6px; font-size: var(--font-size-label); color: var(--color-text-base-placeholder-text); font-style: italic;
    padding-left: 10px; border-left: 2px solid var(--color-text-base-border); }

.tl-empty { text-align: center; padding: var(--space-2xl) var(--space-lg); color: var(--color-text-base-placeholder-text); font-size: var(--font-size-body); }
.tl-empty__icon { margin-bottom: var(--space-sm); opacity: .5; }

/* ===== Admin: Item-Group rental-option catalog (roc-*) ===== */
.roc-page { display: flex; flex-direction: column; gap: var(--space-md); }
.roc-selector { display: flex; flex-direction: column; gap: var(--space-xs); max-width: 360px; }
.roc-selector__label { font-size: var(--font-size-label); color: var(--color-text-base-description-icon-form); font-weight: var(--font-weight-semibold); }
.roc-select { appearance: none; background: var(--color-primary-surface); border: 1px solid var(--color-text-base-border); border-radius: var(--radius-lg);
    padding: .55rem .75rem; font-size: var(--font-size-input); color: var(--color-navy-blue-900); min-height: 40px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M3 5l3 3 3-3' fill='none' stroke='%2364748b' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right .75rem center; padding-right: var(--space-xl); }
.roc-error { color: var(--color-status-error); font-size: var(--font-size-body); padding: var(--space-sm) 0; }
/* Retired options stay VISIBLE (never hidden), only dimmed — ADR 0033 Decision 7: an admin must
   see what exists, and a quotation already pinned to a retired option must stay resolvable. */
.roc-row--retired { opacity: .55; }

/* ===========================================================================================
   AssetDetail.razor (route /assets/skus/{Item}) — mobile pass (<=560px only, additive). Desktop
   is unaffected: `.ad-col-secondary` has no base-rule declaration at all above this point, so it
   is a pure no-op class everywhere above this breakpoint. */
@media (max-width: 560px) {
    /* Instances PecTable: AssetCode / Name / LicensePlateOrSerial / ScanCode / Status / action —
       6 columns is workable on desktop but cramped on a 375px phone even with the shared
       `.pec-table__scroll` horizontal-scroll wrapper (PecTable.razor, unmodified — this page-local
       fix does not touch the shared component, so every other PecTable call site is unaffected).
       Hiding the two lowest-value-per-pixel columns on a phone — LicensePlateOrSerial (often "—"
       for many asset types) and ScanCode (a raw GUID token, not human-scannable off a phone
       screen) — keeps AssetCode/Name/Status/the row-open action visible without any scroll at
       all for the common case, while the data is never lost (still one tap away on the instance's
       own detail page, and still visible on tablet/desktop). Hiding the <th> AND <td> keeps the
       table's own column count/alignment consistent (no dangling empty header cell). */
    .ad-col-secondary {
        display: none;
    }

    /* Status toggle field: see `.vd-field--half`'s own mobile rule above (shared, not repeated
       here) — this page is one of its two callers. */
}

/* ===== Printing: label-print queue page (lpj-*) — LabelPrintJobs.razor, route /printing/label-jobs =====
   The page shipped with class names but no stylesheet at all, so every one of them rendered as
   unstyled body text — which is why the agent line read as a stray sentence above the table rather
   than as the page's live-state readout. */

/* Lives in PecTable's own head slot, opposite the "งานพิมพ์ฉลาก" title — so no card chrome of its
   own: the table card already draws the box, and a second bordered box inside it reads as a nested
   panel. Just the label, the shared pill (PrinterStatusBadge) and how old the reading is. */
.lpj-heartbeat {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
}

.lpj-heartbeat__label {
    font-size: var(--font-size-caption);
    font-weight: var(--font-weight-bold);
    color: var(--color-neutral-title-content);
}

/* Trails the badge (it qualifies the badge — how old that reading is — and must not be mistaken for
   part of it). No `margin-left: auto` any more: the group is right-aligned inside the table head, so
   pushing this to the far end would stretch it across the whole card. */
.lpj-heartbeat__seen {
    font-size: var(--font-size-caption);
    color: var(--color-text-base-description-icon-form);
}

.lpj-error {
    margin-bottom: var(--space-md);
    padding: var(--space-sm) var(--space-md);
    font-size: var(--font-size-caption);
    color: var(--color-status-error);
    background: var(--color-status-error-vbright);
    border-radius: var(--radius-card);
}

/* The two settle actions for a Held job. Column, not row: the notice above them explains a state the
   operator has to physically verify at the printer before either button is safe to press, and a
   side-by-side pair invites the click before the sentence is read. */
.lpj-held { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-xs); }

.lpj-held__notice {
    max-width: 42ch;
    font-size: var(--font-size-caption);
    color: var(--color-text-base-description-icon-form);
}

/* ===== Printing: label-printer registry page (lpa-*) — LabelPrintAgents.razor, /printing/agents =====
   Sibling to the lpj-* block above and deliberately reuses its tokens: the queue page and the registry
   behind it are one system to an operator, and two different-looking pages would read as two. */

/* The add form is a PecDialog body, not a row in the table head — the head keeps only the button that
   opens it. Column gap matches the sibling form-in-PecDialog convention (.vd-form). */
.lpa-add {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    min-width: 20rem;
}

/* Centring is NOT done here. The footer slot is a grid item sized to its own content, so nothing set
   on it centres anything — the wrapper `.pcm-footer` inside it does the work, which is the same
   idiom ProductCategoryModal and the lot-receive modal already use. Only the equal-width pairing is
   page-scoped: fluent-button sizes its shadow ::part(control) to the host, so both halves are needed. */
.lpa-dialog .pcm-footer fluent-button {
    min-width: 9rem;
}

.lpa-dialog .pcm-footer fluent-button::part(control) {
    width: 100%;
}

/* The BU line, not a field — the acting BU is what a printer is registered under, and this says which
   one before the button is pressed. */
.lpa-add__bu {
    margin: 0;
    font-size: var(--font-size-caption);
    color: var(--color-text-base-description-icon-form);
}

.lpa-add__error {
    margin: 0;
    font-size: var(--font-size-caption);
    color: var(--color-status-error);
}

/* The one-time token. Given its own bordered panel BECAUSE it is the only moment this value exists —
   the page stores a hash, so a value that reads as an ordinary row is a value somebody scrolls past. */
.lpa-token {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-bottom: var(--space-md);
    padding: var(--space-md);
    border: 1px solid var(--color-neutral-border);
    border-radius: var(--radius-md);
    background: var(--color-neutral-background);
}

.lpa-token__notice {
    font-size: var(--font-size-caption);
    font-weight: var(--font-weight-bold);
    color: var(--color-neutral-title-content);
}

.lpa-token__value {
    font-family: var(--font-family-mono, monospace);
    word-break: break-all;
}

/* Which printer this button reaches, and what was worth saying about a job that WAS queued. The
   warning deliberately does not reuse .psb-error: the job was accepted, and red would send an operator
   looking for a failure that did not happen. */
.psb-destination {
    font-size: var(--font-size-caption);
    color: var(--color-neutral-title-content);
}

.psb-warning {
    font-size: var(--font-size-caption);
    color: var(--color-warning-content, var(--color-neutral-title-content));
}
