@import '_content/Microsoft.FluentUI.AspNetCore.Components/css/reboot.css';

/* ─── Body defaults ─── */
/* Pin the rem reference. Without this, rem-sized text follows each browser's configurable
   default font size (Firefox users often have ≠16px) while token-sized text stays at the
   Fluent type ramp — the two drift apart and the same page renders inconsistently. */
html {
    font-size: 16px;
}

/* Static type-ramp defaults so token-sized text is correct even before (or without) the
   FAST design-token script, which re-declares these via document.adoptedStyleSheets and
   therefore still wins once loaded. */
:root {
    --type-ramp-base-font-size: 14px;
    --type-ramp-base-line-height: 20px;
}

body {
    --body-font: "Segoe UI Variable", "Segoe UI", system-ui, sans-serif;
    font-family: var(--body-font);
    font-size: var(--type-ramp-base-font-size, 14px);
    line-height: var(--type-ramp-base-line-height, 20px);
    margin: 0;
}

/* =====================================================================
   Shell — full-viewport flex column; only nav + content scroll.
   ===================================================================== */
.app-shell {
    display: flex;
    flex-direction: column;
    height: 100dvh;
    overflow: hidden;
}

.shell-toggle {
    position: absolute;
    width: 0;
    height: 0;
    opacity: 0;
    pointer-events: none;
}

.app-header {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 6px;
    height: 48px;
    padding: 0 12px;
    background: var(--neutral-layer-1);
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
    position: relative;
    z-index: 200;
}

.app-body-row {
    display: flex;
    flex-direction: row;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    position: relative;
}

/* ---- brand ---- */
.app-brand {
    display: flex;
    align-items: center;
    gap: 8px;
    text-decoration: none;
    color: var(--neutral-foreground-rest);
    white-space: nowrap;
    border-radius: 4px;
}

.brand-icon {
    width: 30px;
    height: 30px;
    border-radius: 6px;
    object-fit: cover;
    flex-shrink: 0;
}

.brand-text {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
}

.brand-name {
    font-size: 18px;
    font-weight: 700;
}

.brand-sub {
    font-size: 10px;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--neutral-foreground-hint);
}

/* ---- header actions ---- */
.hdr-actions {
    margin-inline-start: auto;
    display: flex;
    align-items: center;
    gap: 4px;
}

.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--neutral-foreground-rest);
    cursor: pointer;
}

    .icon-btn:hover {
        background: color-mix(in srgb, var(--neutral-foreground-rest) 8%, transparent);
    }

.wms-notif {
    position: relative;
    display: inline-flex;
}

    .wms-notif[data-has-unread="true"]::after {
        content: "";
        position: absolute;
        top: 6px;
        right: 6px;
        width: 8px;
        height: 8px;
        border-radius: 50%;
        background: var(--error, #d13438);
        border: 2px solid var(--neutral-layer-1);
        pointer-events: none;
    }

/* =====================================================================
   Sidebar
   ===================================================================== */
.app-sidebar {
    flex-shrink: 0;
    width: 280px;
    display: flex;
    flex-direction: column;
    background: var(--neutral-layer-1);
    border-inline-end: 1px solid var(--neutral-stroke-divider-rest);
    overflow: hidden;
    z-index: 50;
    transition: width 200ms cubic-bezier(.4, 0, .2, 1);
    will-change: width;
}

.sidebar-header {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 6px;
    height: 48px;
    padding: 0 8px;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
}

.sidebar-title {
    flex: 1;
    padding-left: 6px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--neutral-foreground-hint);
    white-space: nowrap;
    overflow: hidden;
}

.collapse-btn .ico-expand {
    display: none;
}

.app-navmenu {
    flex: 1 1 auto;
    min-height: 0;
    width: 100% !important;
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: thin;
    scrollbar-color: var(--neutral-stroke-rest) transparent;
    overscroll-behavior: none;
}

/* Fluent nav link / group sizing (colors stay from theme) */
fluent-nav-link::part(content) {
    padding: 4px 10px !important;
    margin: 1px 6px !important;
    min-height: 32px !important;
    border-radius: 6px !important;
    font-size: 14px !important;
    gap: 10px !important;
    white-space: nowrap !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
}

fluent-nav-group::part(heading) {
    font-size: 12px !important;
    font-weight: 700 !important;
    text-transform: uppercase !important;
    letter-spacing: .5px !important;
    padding: 10px 12px 2px !important;
}

/* ---- profile footer (pinned bottom) ---- */
.sidebar-profile-footer {
    flex-shrink: 0;
    border-top: 1px solid var(--neutral-stroke-divider-rest);
}

.usermenu {
    position: relative;
}

.sidebar-profile-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 56px;
    padding: 10px 12px;
    border: none;
    background: transparent;
    color: var(--neutral-foreground-rest);
    cursor: pointer;
    text-align: start;
    line-height: 1rem;
    transition: background 140ms ease;
}

    .sidebar-profile-btn:hover {
        background: color-mix(in srgb, var(--neutral-foreground-rest) 7%, transparent);
    }

.sidebar-avatar {
    width: 32px;
    height: 32px;
    min-width: 32px;
    border-radius: 50%;
    flex-shrink: 0;
    display: grid;
    place-items: center;
    background: var(--accent-fill-rest);
    color: var(--accent-foreground-rest, #fff);
}

.sidebar-profile-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.sidebar-profile-name {
    font-size: 14px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar-profile-email {
    font-size: 12px;
    color: var(--neutral-foreground-hint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---- profile popover ---- */
.userpop-backdrop {
    position: fixed;
    inset: 0;
    z-index: 999;
}

/* Fixed so it floats above the sidebar (which clips with overflow:hidden) instead of
   being cut off. Anchored above the profile button / footer at the bottom-left. */
.userpop {
    position: fixed;
    left: 12px;
    bottom: 100px;
    width: 244px;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: .6rem;
    padding: .75rem;
    background: var(--neutral-layer-1);
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: 10px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, .14);
}

.userpop-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
}

.userpop-accentrow {
    flex-wrap: wrap;
}

.userpop-sep {
    height: 1px;
    background: var(--neutral-stroke-divider-rest);
}

.sidebar-control-label {
    font-size: .85rem;
}

.sidebar-accent {
    display: flex;
    gap: .4rem;
}

    .sidebar-accent .swatch {
        width: 22px;
        height: 22px;
        padding: 0;
        border-radius: 50%;
        border: 2px solid transparent;
        cursor: pointer;
        box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
        transition: transform .1s ease, border-color .1s ease;
    }

        .sidebar-accent .swatch:hover {
            transform: scale(1.12);
        }

        .sidebar-accent .swatch.is-active {
            border-color: var(--neutral-foreground-rest);
        }

.sidenav-logout fluent-button {
    width: 100%;
}

/* =====================================================================
   Content + footer
   ===================================================================== */
.app-content {
    flex: 1 1 0;
    min-width: 0;
    min-height: 0;
    overflow: auto;
    background: var(--neutral-layer-1);
    scrollbar-width: thin;
}

.app-content-inner {
    min-height: 100%;
    padding: 1.5rem 2rem;
}

.app-footer {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    padding: 10px 16px;
    font-size: 13px;
    background: var(--neutral-layer-1);
    border-top: 1px solid var(--neutral-stroke-divider-rest);
    color: var(--neutral-foreground-hint);
}

.footer-copyright,
.footer-version {
    font-size: .75rem;
    opacity: .7;
}

.footer-version {
    margin-inline-start: auto;
}

/* ==========================================================
   CONSISTENT SCROLLBAR
   ========================================================== */

.app-navmenu,
.app-content,
.body-content,
.lookup-panel-scroll {
    scrollbar-width: thin;
    scrollbar-color: var(--neutral-stroke-rest) transparent;
    scroll-behavior: smooth;
    will-change: scroll-position;
}

    .app-navmenu::-webkit-scrollbar,
    .app-content::-webkit-scrollbar,
    .body-content::-webkit-scrollbar,
    .lookup-panel-scroll::-webkit-scrollbar {
        width: 4px;
    }

    .app-navmenu::-webkit-scrollbar-thumb,
    .app-content::-webkit-scrollbar-thumb,
    .body-content::-webkit-scrollbar-thumb,
    .lookup-panel-scroll::-webkit-scrollbar-thumb {
        background: var(--neutral-stroke-rest);
        border-radius: 999px;
    }

        .app-navmenu::-webkit-scrollbar-thumb:hover,
        .app-content::-webkit-scrollbar-thumb:hover,
        .body-content::-webkit-scrollbar-thumb:hover,
        .lookup-panel-scroll::-webkit-scrollbar-thumb:hover {
            background: var(--neutral-foreground-hint);
        }

/* Desktop-wide fallback: any other scrollable area (dialog bodies, etc.) gets the same slim
   treatment. Mouse-driven desktop use (wheel/drag) doesn't need a grabbable scrollbar — it's
   just a position indicator — so it can stay thin everywhere, not just the containers above.
   Left off <768px: touch scrolling already uses the OS's own auto-hiding overlay scrollbar. */
@media (min-width: 768px) {
    html {
        scrollbar-width: thin;
        scrollbar-color: var(--neutral-stroke-rest) transparent;
    }

    *::-webkit-scrollbar {
        width: 4px;
        height: 4px;
    }

    *::-webkit-scrollbar-thumb {
        background: var(--neutral-stroke-rest);
        border-radius: 999px;
    }

    *::-webkit-scrollbar-thumb:hover {
        background: var(--neutral-foreground-hint);
    }

    *::-webkit-scrollbar-track {
        background: transparent;
    }
}

/* =====================================================================
   Desktop collapse (icons only) + mobile overlay  — pure CSS via :has()
   ===================================================================== */
@media (min-width: 768px) {
    .mobile-only {
        display: none !important;
    }

    .mobile-overlay {
        display: none !important;
    }

    .app-shell:has(#nav-collapse:checked) .app-sidebar {
        width: 56px;
    }

    .app-shell:has(#nav-collapse:checked) .sidebar-title,
    .app-shell:has(#nav-collapse:checked) .sidebar-profile-text,
    .app-shell:has(#nav-collapse:checked) .fluent-nav-text,
    .app-shell:has(#nav-collapse:checked) .expand-collapse-button,
    .app-shell:has(#nav-collapse:checked) .rotate,
    .app-shell:has(#nav-collapse:checked) .collapse-btn .ico-collapse {
        display: none !important;
    }

    .app-shell:has(#nav-collapse:checked) .collapse-btn .ico-expand {
        display: inline-flex !important;
    }

    .app-shell:has(#nav-collapse:checked) .sidebar-header {
        justify-content: center;
        padding: 0;
    }

    .app-shell:has(#nav-collapse:checked) .sidebar-profile-btn {
        justify-content: center;
        padding-inline: 0;
    }

    .app-shell:has(#nav-collapse:checked) fluent-nav-link::part(content) {
        justify-content: center !important;
        padding: 4px !important;
    }

    .app-shell:has(#nav-collapse:checked) .fluent-nav-item,
    .app-shell:has(#nav-collapse:checked) .fluent-nav-link,
    .app-shell:has(#nav-collapse:checked) .positioning-region,
    .app-shell:has(#nav-collapse:checked) .content-region {
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
        width: 100% !important;
        padding-inline: 0 !important;
        gap: 0 !important;
        margin-inline-start: unset !important;
    }

    .app-shell:has(#nav-collapse:checked) .fluent-nav-icon {
        margin: 0 !important;
    }

    /* Drop the active vertical-bar indicator when collapsed — otherwise it gets centered
       and overlaps the icon. */
    .app-shell:has(#nav-collapse:checked) .positioning-region::before,
    .app-shell:has(#nav-collapse:checked) .positioning-region::after,
    .app-shell:has(#nav-collapse:checked) .content-region::before,
    .app-shell:has(#nav-collapse:checked) .content-region::after {
        content: unset !important;
        display: none !important;
    }

    /* Collapsed rail: hide group children (their collapsible container is a sibling of the
       group heading), keeping only top-level items + group icons. */
    .app-shell:has(#nav-collapse:checked) .fluent-collapsible-region-container {
        display: none !important;
    }
}

@media (max-width: 767px) {
    .desktop-only {
        display: none !important;
    }

    .app-sidebar {
        position: absolute;
        top: 0;
        bottom: 0;
        inset-inline-start: 0;
        width: 0;
        border-inline-end: none;
    }

    .app-shell:has(#nav-mobile:checked) .app-sidebar {
        width: 280px;
        box-shadow: 4px 0 20px rgba(0, 0, 0, .28);
    }

    .mobile-overlay {
        display: none;
        position: absolute;
        inset: 0;
        z-index: 49;
        background: rgba(0, 0, 0, .4);
    }

    .app-shell:has(#nav-mobile:checked) .mobile-overlay {
        display: block;
    }

    .app-content-inner {
        padding: 1rem;
    }

    /* Keep dialogs (edit + confirmation) off the screen edges on small screens. */
    fluent-dialog::part(control) {
        max-width: 92vw !important;
    }
}

/* =====================================================================
   Standard content header
   ===================================================================== */
.page-header {
    margin-bottom: 1.25rem;
}

    .page-header h1 {
        margin: 0;
        font-size: 1.6rem;
        font-weight: 600;
    }

.page-subtitle {
    margin: .25rem 0 0;
    color: var(--neutral-foreground-hint);
}

.page-header-row {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.muted-hint {
    margin: 0;
    padding: .5rem 0;
    color: var(--neutral-foreground-hint);
}

.confirm-text {
    margin: 0;
    line-height: 1.45;
}

/* Responsive list pattern: data grid on desktop, stacked items on mobile. */
.list-mobile {
    display: none;
}

@media (max-width: 767px) {
    .list-desktop {
        display: none;
    }

    /* Each record becomes its own card; drop the outer WmsCard chrome so frames don't nest. */
    .wms-card:has(.list-mobile) {
        background: transparent;
        border: none;
        box-shadow: none;
        padding: 0;
    }

    .list-mobile {
        display: flex;
        flex-direction: column;
        gap: .6rem;
    }

    .m-item {
        display: flex;
        flex-direction: column;
        gap: .15rem;
        padding: .75rem .9rem .85rem;
        background: var(--neutral-layer-1);
        border: 1px solid var(--neutral-stroke-divider-rest);
        border-radius: 12px;
        box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
    }

    .m-item-top {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: .5rem;
        margin-bottom: .1rem;
    }

    .m-badge {
        display: inline-flex;
        align-items: center;
        padding: 2px 9px;
        border-radius: 999px;
        font-size: .72rem;
        font-weight: 700;
        letter-spacing: .04em;
        color: var(--accent-fill-rest);
        background: color-mix(in srgb, var(--accent-fill-rest) 12%, transparent);
    }

    .m-title {
        font-size: .95rem;
        font-weight: 600;
        line-height: 1.3;
        overflow-wrap: anywhere;
    }

    .m-meta {
        font-size: .8rem;
        line-height: 1.4;
        color: var(--neutral-foreground-hint);
        overflow-wrap: anywhere;
    }
}

/* Cost summary rows (Packaging formula → Cost card). */
.cost-summary {
    display: flex;
    flex-direction: column;
    gap: .35rem;
    padding: .75rem 1rem;
    background: var(--neutral-fill-stealth-rest, rgba(0, 0, 0, .02));
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: 6px;
}

.cost-row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    font-size: .9rem;
}

.cost-row-total {
    font-weight: 700;
    padding-top: .5rem;
    border-top: 1px solid var(--neutral-stroke-divider-rest);
}

/* Item image gallery (Items → Images tab). */
.item-image-grid {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    margin-top: .75rem;
}

.item-image-thumb {
    position: relative;
    width: 120px;
    height: 120px;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--neutral-stroke-divider-rest);
    background: var(--neutral-layer-2);
}

    .item-image-thumb.is-primary {
        border-color: var(--accent-fill-rest);
        border-width: 2px;
    }

    .item-image-thumb img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        display: block;
    }

/* Non-image attachment (PDF, etc) rendered in the same thumb slot as a photo. */
.attachment-file-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    height: 100%;
    padding: 8px;
    text-align: center;
    color: var(--neutral-foreground-rest);
    font-size: .75rem;
    overflow: hidden;
    word-break: break-all;
}

.item-image-caption {
    position: absolute;
    top: 6px;
    left: 6px;
    padding: 1px 7px;
    border-radius: 4px;
    font-size: .68rem;
    font-weight: 600;
    color: var(--foreground-on-accent-rest, #fff);
    background: var(--accent-fill-rest);
}

/* Fluent file picker dropzone (Items → Images). */
.image-uploader {
    display: block;
    border: 1px dashed var(--neutral-stroke-rest);
    border-radius: 8px;
    background: var(--neutral-fill-stealth-rest, transparent);
    transition: border-color 120ms ease, background 120ms ease;
}

    .image-uploader:hover {
        border-color: var(--accent-fill-rest);
    }

.image-dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 20px;
    min-height: 90px;
    cursor: pointer;
    color: var(--neutral-foreground-hint);
    font-size: .875rem;
    text-align: center;
}

    .image-dropzone strong {
        color: var(--accent-fill-rest);
    }

.item-image-actions {
    position: absolute;
    bottom: 0;
    right: 0;
    left: 0;
    justify-content: center;
    background: linear-gradient(to top, rgba(0, 0, 0, .55), transparent);
    padding: 4px 0 2px;
}

/* =====================================================================
   Item detail — read-only master view (hero + spec grid).
   ===================================================================== */
.item-hero {
    display: flex;
    gap: 20px;
    align-items: flex-start;
}

.item-hero-media {
    flex: 0 0 auto;
    width: 112px;
    height: 112px;
    border-radius: 10px;
    overflow: hidden;
    border: 1px solid var(--neutral-stroke-divider-rest);
    background: var(--neutral-layer-2);
    display: flex;
    align-items: center;
    justify-content: center;
}

    .item-hero-media img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        display: block;
    }

    .item-hero-media .item-hero-placeholder {
        color: var(--neutral-foreground-hint);
    }

.item-hero-body {
    flex: 1 1 auto;
    min-width: 0;
}

.item-hero-code {
    font-size: .8rem;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--neutral-foreground-hint);
}

.item-hero-name {
    font-size: 1.35rem;
    font-weight: 600;
    line-height: 1.2;
    margin: 2px 0 0;
    color: var(--neutral-foreground-rest);
    word-break: break-word;
}

.item-hero-alias {
    font-size: .9rem;
    color: var(--neutral-foreground-hint);
    margin-top: 3px;
}

.item-hero-pills {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    margin-top: 12px;
}

@media (max-width: 560px) {
    .item-hero { gap: 14px; }
    .item-hero-media { width: 84px; height: 84px; }
}

/* Label/value specification grid used on read-only detail views. */
.detail-specs {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 16px 24px;
}

.detail-spec { min-width: 0; }
.detail-spec.fg-full { grid-column: 1 / -1; }

.detail-spec-label {
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .6px;
    color: var(--neutral-foreground-hint);
    margin-bottom: 3px;
}

.detail-spec-value {
    font-size: .92rem;
    color: var(--neutral-foreground-rest);
    word-break: break-word;
}

    .detail-spec-value.is-empty { color: var(--neutral-foreground-hint); }

/* Text list of sub-records (units / barcodes) inside a spec entry — one readable row each. */
.detail-list {
    display: flex;
    flex-direction: column;
    gap: 7px;
    margin-top: 2px;
}

.detail-list-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: .92rem;
    line-height: 1.3;
    color: var(--neutral-foreground-rest);
    padding-bottom: 7px;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
}

    .detail-list-item:last-child {
        padding-bottom: 0;
        border-bottom: none;
    }

    .detail-list-item .dt-hint { font-size: .86rem; }

/* Read-only image gallery (detail view) reuses .item-image-thumb without hover actions. */
.item-image-grid.is-readonly .item-image-thumb { cursor: default; }

/* Mobile polish for the read-only item detail view. Below 560px the auto-fill
   track (minmax 190px) only ever fits 1 column, turning short facts (Batch
   tracked: Yes) into one long undifferentiated scroll — force a real 2-column
   grid instead so short label/value pairs sit side by side; .fg-full entries
   (Description, Units, Barcodes) still span both columns via the existing rule. */
@media (max-width: 560px) {
    .item-hero-name { font-size: 1.15rem; }
    .item-image-grid.is-readonly .item-image-thumb { width: 88px; height: 88px; }
    .detail-specs { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 16px; }
}

/* Action buttons inside a data-grid row: centered, compact, never touching row borders. */
.grid-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: .15rem;
    height: 100%;
}

    .grid-actions .fluent-button {
        --button-height: 28px;
        min-width: 28px;
    }

/* =====================================================================
   Custom card (lighter than FluentCard) + dashboard shortcuts
   ===================================================================== */
.wms-card {
    background: var(--neutral-layer-1);
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: 10px;
    padding: 1.25rem;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
}

.wms-card-title {
    font-weight: 600;
    margin-bottom: .75rem;
}

.placeholder-card {
    max-width: 640px;
}

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 1rem;
}

.shortcut-card {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.1rem 1.25rem;
    border-radius: 10px;
    background: var(--neutral-layer-1);
    border: 1px solid var(--neutral-stroke-divider-rest);
    text-decoration: none;
    color: var(--neutral-foreground-rest);
    transition: border-color .15s ease, background-color .15s ease;
}

    .shortcut-card:hover {
        border-color: var(--accent-fill-rest);
        background: color-mix(in srgb, var(--accent-fill-rest) 5%, var(--neutral-layer-1));
    }

.shortcut-icon {
    width: 46px;
    height: 46px;
    border-radius: 10px;
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    background: var(--accent-fill-rest);
    color: var(--accent-foreground-rest, #fff);
}

.shortcut-text {
    display: flex;
    flex-direction: column;
}

.shortcut-title {
    font-weight: 600;
}

.shortcut-sub {
    font-size: .82rem;
    color: var(--neutral-foreground-hint);
}

/* =====================================================================
   Login (EmptyLayout)
   ===================================================================== */
.login-wrapper {
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: radial-gradient(1100px 520px at 50% -10%, color-mix(in srgb, var(--accent-fill-rest) 26%, var(--neutral-layer-2)), var(--neutral-layer-2));
}

.login-card {
    width: 100%;
    max-width: 400px;
    background: var(--neutral-layer-1);
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: 16px;
    padding: 2.25rem 2rem;
    box-shadow: 0 12px 40px rgba(0, 0, 0, .18);
}

.login-brand {
    text-align: center;
    margin-bottom: 1.5rem;
}

.login-mark {
    width: 56px;
    height: 56px;
    margin: 0 auto .85rem;
    display: block;
    border-radius: 16px;
    object-fit: cover;
}

.login-title {
    margin: 0;
    font-size: 1.3rem;
    font-weight: 700;
}

.login-subtitle {
    margin: .25rem 0 0;
    color: var(--neutral-foreground-hint);
}

.login-field {
    margin-bottom: 1rem;
    display: flex;
    flex-direction: column;
}

    .login-field label {
        font-size: .82rem;
        font-weight: 600;
        margin-bottom: .3rem;
    }

.login-input {
    padding: .6rem .75rem;
    font: inherit;
    border-radius: 8px;
    border: 1px solid var(--neutral-stroke-rest);
    background: var(--neutral-layer-1);
    color: var(--neutral-foreground-rest);
}

    .login-input:focus {
        outline: none;
        border-color: var(--accent-fill-rest);
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-fill-rest) 25%, transparent);
    }

.login-remember {
    display: flex;
    align-items: center;
    gap: .45rem;
    margin: .25rem 0 1.25rem;
    font-size: .9rem;
}

.login-submit {
    width: 100%;
    padding: .7rem;
    font: inherit;
    font-weight: 600;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    color: var(--foreground-on-accent-rest, #fff);
    background: var(--accent-fill-rest, #0f6cbd);
    transition: filter .15s ease, transform .05s ease;
}

    .login-submit:hover {
        filter: brightness(1.07);
    }

    .login-submit:active {
        transform: translateY(1px);
    }

.login-alert {
    margin-bottom: 1rem;
    padding: .6rem .75rem;
    border-radius: 8px;
    background: color-mix(in srgb, var(--error, #d13438) 14%, transparent);
    color: var(--error, #d13438);
    font-size: .88rem;
}

.validation-message {
    color: var(--error, #d13438);
    font-size: .8rem;
    margin-top: .25rem;
}

.login-info {
    margin-bottom: 1rem;
    padding: .6rem .75rem;
    border-radius: 8px;
    background: color-mix(in srgb, var(--accent-fill-rest) 12%, transparent);
    color: var(--neutral-foreground-rest);
    font-size: .88rem;
    line-height: 1.45;
}

.login-links {
    margin-top: 1.1rem;
    text-align: center;
    font-size: .88rem;
}

    .login-links a {
        color: var(--accent-fill-rest);
        text-decoration: none;
    }

        .login-links a:hover {
            text-decoration: underline;
        }

/* =====================================================================
   Error UI
   ===================================================================== */
#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

/* =====================================================================
   Basis-style design system — page skeleton, cards, data tables.
   Ported from D:\BASIS-APP\Basis.Shared (same Fluent UI version) so list
   and form pages read as one clean, professional system.
   ===================================================================== */

/* ---- Page header extras (breadcrumb + title) ---- */
.page-title {
    font-size: 24px;
    font-weight: 600;
    margin: 0 0 3px;
    line-height: 1.2;
    color: var(--neutral-foreground-rest);
}

/* Routes.razor's <FocusOnNavigate Selector="h1"> moves keyboard/screen-reader focus to
   the title on every navigation — good for accessibility (announces the new page), but
   its default focus ring around the title reads as a stray visual artifact on every
   navigation/refresh. Keep the focus move, just drop the visible ring. */
.page-title:focus {
    outline: none;
}

/* Compact page header on phones: smaller title, and .hide-sm lets header action
   buttons drop their text label (icon-only) so they don't wrap or overlap. */
@media (max-width: 560px) {
    .page-title { font-size: 17px; }
    .page-header h1 { font-size: 1.15rem; }
    .page-subtitle { font-size: .82rem; }
    .hide-sm { display: none !important; }
    /* Hiding the label text (.hide-sm) leaves FluentButton's own icon-to-content gap reserved,
       so an icon-only button renders as a wide pill instead of a square. Force a fixed square
       control and zero out the icon's own trailing margin/gap so it centers with no leftover
       space — covers both the light-DOM class and (if the version in use renders one) the
       custom-element/::part() form, since only one of these actually matches at runtime. */
    .page-header .dt-actions .fluent-button,
    .page-header .dt-actions fluent-button {
        width: 30px !important;
        min-width: 30px !important;
        gap: 0 !important;
    }
    .page-header .dt-actions .fluent-button::part(control),
    .page-header .dt-actions fluent-button::part(control) {
        width: 30px !important;
        padding: 0 !important;
        justify-content: center !important;
        gap: 0 !important;
    }
    .page-header .dt-actions .fluent-button::part(start),
    .page-header .dt-actions fluent-button::part(start),
    .page-header .dt-actions .fluent-button svg,
    .page-header .dt-actions fluent-button svg {
        margin: 0 !important;
    }
}

.page-breadcrumb {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 13px;
    color: var(--neutral-foreground-hint);
    margin-bottom: 6px;
}

    .page-breadcrumb a {
        color: var(--accent-foreground-rest, var(--accent-fill-rest));
        text-decoration: none;
        font-weight: 500;
    }

    .page-breadcrumb a:hover {
        text-decoration: underline;
    }

/* ---- Card ---- */
.fluent-card {
    background: var(--neutral-layer-1);
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: 8px;
    padding: 12px 20px;
}

.fluent-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
}

.fluent-card-title {
    font-size: 16px;
    font-weight: 600;
    margin: 0;
    color: var(--neutral-foreground-rest);
}

.dt-record-count {
    font-size: 13px;
    font-weight: 400;
    color: var(--neutral-foreground-hint);
    margin-inline-start: 4px;
}

/* ---- Stat cards ---- */
.stat-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
}

.stat-card {
    background: var(--neutral-layer-1);
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: 8px;
    padding: 16px 20px;
    display: flex;
    flex-direction: column;
    gap: 5px;
    position: relative;
    overflow: hidden;
    transition: box-shadow 180ms ease, transform 120ms ease;
}

    .stat-card:hover {
        box-shadow: 0 2px 8px rgba(0, 0, 0, .08);
        transform: translateY(-1px);
    }

    .stat-card::before {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        height: 3px;
        background: var(--accent-fill-rest);
        border-radius: 8px 8px 0 0;
    }

.stat-card-label {
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .6px;
    color: var(--neutral-foreground-hint);
    display: flex;
    align-items: center;
    gap: 5px;
}

.stat-card-value {
    font-size: 22px;
    font-weight: 600;
    line-height: 1.1;
    color: var(--neutral-foreground-rest);
}

.stat-card-value.warn { color: #b25e00; }

.stat-card-sub {
    font-size: 11px;
    color: var(--neutral-foreground-hint);
}

/* ---- Dashboard "needs attention" list ---- */
.attn-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.attn-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 8px;
    border: 1px solid var(--neutral-stroke-divider-rest);
    background: var(--neutral-layer-1);
    text-decoration: none;
    color: var(--neutral-foreground-rest);
    transition: border-color .15s ease, background-color .15s ease;
}

    .attn-row:hover {
        border-color: var(--accent-fill-rest);
        background: color-mix(in srgb, var(--accent-fill-rest) 5%, var(--neutral-layer-1));
    }

.attn-count {
    flex: 0 0 auto;
    min-width: 26px;
    height: 26px;
    padding: 0 8px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 13px;
    color: var(--accent-fill-rest);
    background: color-mix(in srgb, var(--accent-fill-rest) 14%, transparent);
}

.attn-text {
    flex: 1 1 auto;
    font-size: 14px;
}

/* ---- Dashboard trend cards (7-day sparkline) ---- */
.trend-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}

.trend-row.single { grid-template-columns: minmax(0, 1fr); }

.trend-card {
    background: var(--neutral-layer-1);
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: 8px;
    padding: 12px 16px;
}

.trend-top {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 4px;
}

.trend-name {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--neutral-foreground-hint);
}

.trend-delta { font-size: 11px; font-weight: 700; white-space: nowrap; }
.trend-delta.up { color: #107c10; }
.trend-delta.down { color: var(--error, #d13438); }

.trend-value {
    font-size: 17px;
    font-weight: 700;
    margin-bottom: 6px;
}

.trend-value .unit { font-size: 11px; font-weight: 400; color: var(--neutral-foreground-hint); }

svg.spark { display: block; width: 100%; height: 34px; }

@media (max-width: 767px) {
    .trend-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
}

/* ---- Grid + spacing utilities ---- */
/* minmax(0, 1fr) (not plain 1fr) so a track may shrink below its content's intrinsic
   width. Without it a child holding a min-width table (.dt-line) forces the column
   wider than the viewport, so the page scrolls instead of the table's own .dt-line-wrap
   showing a horizontal scrollbar. Pair with min-width:0 on the items to be sure. */
.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
.grid-5 { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 14px; }
.grid-auto { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }

.grid-2 > *, .grid-3 > *, .grid-4 > *, .grid-5 > * { min-width: 0; }

@media (max-width: 767px) {
    .grid-2, .grid-3, .grid-4, .grid-5 { grid-template-columns: minmax(0, 1fr); }
}

.d-flex { display: flex; }
.align-center { align-items: center; }
.justify-between { justify-content: space-between; }

/* Page-header action row (title/subtitle left, buttons right): let it wrap on
   phones instead of the buttons overlapping the subtitle text. The title block
   may shrink (min-width:0); the button cluster keeps its size and stays right-
   aligned even after wrapping to its own line. */
.page-header .d-flex.justify-between {
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 8px 12px;
}

.page-header .d-flex.justify-between > :first-child {
    min-width: 0;
    flex: 1 1 220px;
}

.page-header .d-flex.justify-between > :last-child {
    flex-shrink: 0;
    margin-left: auto;
}
.gap-1 { gap: 4px; }
.gap-2 { gap: 8px; }
.gap-3 { gap: 12px; }
.gap-4 { gap: 16px; }
.mt-2 { margin-top: 8px; }
.mt-3 { margin-top: 12px; }
.mt-4 { margin-top: 16px; }
.mb-2 { margin-bottom: 8px; }
.mb-3 { margin-bottom: 12px; }
.mb-4 { margin-bottom: 16px; }

/* ---- List filters bar ---- */
.list-filters {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    align-items: end;
    gap: 10px;
}

/* Same fluent-select built-in min-width fix as .form-grid (see below) */
.list-filters fluent-select,
.list-filters fluent-combobox,
.list-filters fluent-text-field {
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100%;
}

/* =====================================================================
   Data table system (.dt) — clean HTML table, mobile → stacked cards.
   ===================================================================== */
.dt-wrap {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--neutral-stroke-rest) transparent;
}

.dt {
    font-size: .875rem;
    width: 100%;
    border-collapse: collapse;
    table-layout: auto;
    min-width: 720px;
}

.dt thead th {
    padding: 8px 10px;
    text-align: start;
    font-size: .78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.45px;
    color: var(--neutral-foreground-hint);
    background: var(--neutral-layer-2, var(--neutral-layer-1));
    border-bottom: 1px solid var(--neutral-stroke-rest);
    white-space: nowrap;
    -webkit-user-select: none;
    user-select: none;
}

    .dt thead th.dt-end { text-align: end; }

.dt-sortable {
    cursor: pointer;
    transition: background 80ms ease, color 80ms ease;
}

    .dt-sortable:hover {
        background: var(--neutral-fill-stealth-hover, rgba(0, 0, 0, .04));
        color: var(--neutral-foreground-rest);
    }

/* Sort-icon side follows the column's own alignment: left/center headers keep the icon trailing
   the label (unchanged); a right-aligned (numeric) header instead pins the icon to the LEFT edge
   of the cell via absolute positioning, so the label text — still a plain inline text node,
   text-align:end as before — hugs the right edge on its own. display:flex was tried here first and
   REJECTED: setting display:flex on a <th> replaces its table-cell display entirely, so it stops
   participating in the table's column layout and the whole header row collapses/wraps instead of
   staying a normal grid of columns. Absolute positioning leaves display: table-cell (the <th>
   default) untouched — only the icon leaves the flow, nothing about the cell's own layout mode
   changes. */
.dt thead th.dt-sortable {
    position: relative;
}

.dt thead th.dt-sortable.dt-end .dt-sort-icon {
    position: absolute;
    inset-inline-start: 8px;
    top: 50%;
    transform: translateY(-50%);
    margin-inline-start: 8px;
}

.dt-sort-icon {
    display: inline-block;
    margin-inline-start: 4px;
    font-size: 12px;
    opacity: 0.35;
    line-height: 1;
}

.dt-sortable.dt-sorted .dt-sort-icon {
    opacity: 1;
    color: var(--accent-fill-rest);
}

.dt tbody tr {
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
    transition: background 60ms ease;
}

    .dt tbody tr:last-child { border-bottom: none; }
    .dt tbody tr:hover { background: var(--neutral-fill-stealth-hover, rgba(0, 0, 0, .03)); }

.dt tbody td {
    padding: 7px 10px;
    vertical-align: middle;
    white-space: nowrap;
}

    .dt tbody td.dt-end { text-align: end; }

    .dt tbody td.dt-wrap-text {
        white-space: normal;
        word-break: break-word;
        min-width: 120px;
        max-width: 320px;
    }

/* Totals row (report pages). tbody td owns the only padding rule in this table — a tfoot with
   none of its own renders its text flush against the cell edge, which visibly does not line up
   under thead/tbody's padded columns even though the cells share the same boundaries. Match the
   padding so it lines up, and add a top border to set the summary row apart from the data above. */
.dt tfoot td {
    padding: 10px;
    font-weight: 700;
    border-top: 1px solid var(--neutral-stroke-rest);
}

    .dt tfoot td.dt-end { text-align: end; }

/* Grouped report rows (e.g. Sales Detail): a document "header" row (shaded, bold, carries the
   document's own totals) sits above its indented item-line rows — same column grid throughout,
   just different cells populated per row, no colspan. */
.dt-group-row td {
    background: var(--neutral-layer-2, var(--neutral-layer-1));
    border-top: 2px solid var(--neutral-stroke-rest);
    font-weight: 600;
}

.dt-detail-row td {
    font-size: .92em;
}

.dt-detail-row td:first-child {
    padding-inline-start: 20px;
}

.dt-mono { /* letter-spacing: -0.03em; */ }
.dt-hint { color: var(--neutral-foreground-hint); }

.dt-link {
    color: var(--accent-fill-rest);
    text-decoration: none;
    cursor: pointer;
}

    .dt-link:hover { text-decoration: underline; }

.dt-actions {
    display: flex;
    gap: 3px;
    justify-content: flex-end;
    align-items: center;
}

    .dt-actions .fluent-button { --button-height: 28px; min-width: 28px; }

/* Right-side slide-out panels (Stock/Customer Lookup, Notifications) get a lighter, smaller
   header than Fluent's centered-modal default (24px/weight 400, 24px bottom padding) — a
   slide-out doesn't carry the same visual weight as a full dialog. Scoped to fluent-dialog.right
   only, so centered confirm/edit dialogs keep their normal header. */
fluent-dialog.right .fluent-dialog-header {
    padding-bottom: 14px !important;
}

/* This title is always rendered as an <h4> by FluentUI's own DialogParameters.Title — there's
   no TitleTemplate/tag override in its public API, so it can't be swapped for a real <h2>.
   Size/weight it like one instead (h2-ish, ~20px/600) so it balances against the 20px close
   button, rather than the library's h4-but-24px/weight-400 default.
   !important: Fluent's own component styling (likely a ::slotted() rule inside fluent-dialog's
   shadow root, invisible to document.styleSheets) otherwise wins over an equal/higher-specificity
   light-DOM rule here — same class of problem as the ::part() overrides above. */
fluent-dialog.right .fluent-dialog-header h4 {
    font-size: 1.25rem !important;
    font-weight: 600 !important;
    line-height: 1.3 !important;
}

/* A long title (e.g. an attachment's original filename) otherwise runs straight into the close
   button — FluentUI wraps the title in its own div with an inline style="width:100%" (not
   reachable through any Blazor parameter), which claims the whole header row and leaves the
   close button no space to sit in. Applies to every fluent-dialog, not just .right — the same
   layout bug hits a centered dialog just as easily (e.g. AttachmentPreviewDialog on a narrow
   screen). !important on the wrapper only: nothing but !important beats an inline style. */
.fluent-dialog-header > div:first-child {
    width: auto !important;
    min-width: 0;
    flex: 1 1 auto;
}

.fluent-dialog-header h4 {
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fluent-dialog-header fluent-button {
    flex-shrink: 0;
}

/* Shared shell for header slide-out "lookup" panels (Stock Lookup, Customer Lookup, …):
   search stays put; the results (however many rows) scroll in the remaining panel height
   instead of pushing the search field off-screen or growing the panel past the viewport.
   min-height:0 on the scroll child is required for a flex child to actually shrink and
   scroll rather than overflow its flex parent. No padding here — fluent-dialog's own
   .control part already applies 24px on every side; adding more here was doubling the
   inset (44px combined) and needlessly narrowing the usable content width. */
.lookup-panel-root {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.lookup-panel-search {
    flex-shrink: 0;
}

.lookup-panel-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    margin-top: 12px;
}

/* Lookup panels: always phone-style cards, never the desktop .dt table — the panel itself
   is always phone-width (min(480px, 100vw)), so there's no wider layout to switch to. Tapping
   a card expands it in place to show extra detail (no menu on these panels, so whole-card-click
   is unambiguous here, unlike the app-wide dt-card convention). */
.lookup-panel-cards {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.lookup-panel-card {
    cursor: pointer;
    transition: border-color .15s ease;
}

    .lookup-panel-card:hover,
    .lookup-panel-card.is-expanded {
        border-color: var(--accent-fill-rest);
    }

    .lookup-panel-card .dt-card-header svg {
        color: var(--neutral-foreground-hint);
        flex-shrink: 0;
        margin-top: 2px;
    }

/* ---- Mobile: table → stacked cards at <768px ---- */
.dt-mobile { display: none; }

@media (max-width: 767px) {
    .dt-wrap { display: none; }
    .dt-mobile { display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
    /* Line tables opting into the card treatment (read-only document views) */
    .dt-line-wrap.dt-line-desktop { display: none; }
}

/* ---- WmsPager: desktop bar (numbered pages + page-size) / mobile prev-next strip.
   Same <768px switch as the table above — .dt-pager-desktop and .dt-pager-mobile were
   rendering unstyled and simultaneously (no rules existed for either class at all) until
   this block. */
.dt-pager {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--neutral-stroke-divider-rest);
    font-size: .85rem;
}

.dt-pager-mobile { display: none; }

.dt-pager-btn {
    min-width: 30px;
    height: 30px;
    padding: 0 8px;
    border: 1px solid var(--neutral-stroke-rest);
    border-radius: 6px;
    background: var(--neutral-layer-1);
    color: var(--neutral-foreground-rest);
    font-size: .85rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color .15s ease, border-color .15s ease;
}

    .dt-pager-btn:hover:not(:disabled) {
        background: var(--neutral-layer-2);
        border-color: var(--neutral-foreground-hint);
    }

    .dt-pager-btn:disabled {
        opacity: .4;
        cursor: not-allowed;
    }

    .dt-pager-btn.dt-pager-active {
        background: var(--accent-fill-rest);
        border-color: var(--accent-fill-rest);
        color: var(--accent-foreground-rest, #fff);
        font-weight: 600;
    }

.dt-pager-info {
    margin: 0 4px;
    color: var(--neutral-foreground-hint);
    white-space: nowrap;
}

.dt-pager-size {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    color: var(--neutral-foreground-hint);
}

    .dt-pager-size select {
        height: 30px;
        border: 1px solid var(--neutral-stroke-rest);
        border-radius: 6px;
        background: var(--neutral-layer-1);
        color: var(--neutral-foreground-rest);
        font-size: .85rem;
        padding: 0 6px;
    }

@media (max-width: 767px) {
    .dt-pager-desktop { display: none; }

    .dt-pager-mobile {
        display: flex;
        width: 100%;
        justify-content: space-between;
        align-items: center;
    }

        .dt-pager-mobile .dt-pager-btn {
            min-width: 76px;
        }
}

.dt-card {
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: 8px;
    padding: 11px 13px;
    background: var(--neutral-layer-1);
}

.dt-card-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 8px;
    margin-bottom: 4px;
}

.dt-card-title {
    font-size: .95rem;
    font-weight: 600;
    line-height: 1.3;
    overflow-wrap: anywhere;
}

.dt-card-meta {
    font-size: .8rem;
    color: var(--neutral-foreground-hint);
    margin-top: 2px;
    overflow-wrap: anywhere;
}

/* ---- Sticky save footer for forms ---- */
.save-footer {
    position: sticky;
    bottom: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    margin-top: 16px;
    background: var(--neutral-layer-1);
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: 8px;
    box-shadow: 0 -4px 8px rgba(0, 0, 0, .08);
}

.save-footer-summary {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: .875rem;
    color: var(--neutral-foreground-hint);
    min-width: 0;
    flex: 1;
}

/* Button cluster on the right: always a flex row with a gap so Save/Cancel don't touch. */
.save-footer > div:last-child {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

@media (max-width: 479px) {
    .save-footer { flex-direction: column; align-items: stretch; }
    .save-footer > div:last-child fluent-button { flex: 1; }
}

/* Compact, evenly-spaced action buttons inside table rows. */
.dt-actions fluent-button::part(control),
.grid-actions fluent-button::part(control) {
    height: 30px;
    min-width: 30px;
    padding: 0 6px;
}

/* ---- Status pill (list badges) ---- */
.dt-pill {
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .02em;
    white-space: nowrap;
}

.dt-pill-accent {
    color: var(--accent-fill-rest);
    background: color-mix(in srgb, var(--accent-fill-rest) 12%, transparent);
}

.dt-pill-neutral {
    color: var(--neutral-foreground-hint);
    background: color-mix(in srgb, var(--neutral-foreground-hint) 12%, transparent);
}

.dt-pill-warning {
    color: #b25e00;
    background: color-mix(in srgb, #e08700 14%, transparent);
}

.dt-pill-danger {
    color: var(--error, #d13438);
    background: color-mix(in srgb, var(--error, #d13438) 12%, transparent);
}

/* =====================================================================
   Form line-item table (.dt-line) + section headers + empty states.
   Used inside form cards for editable child collections (BOM materials,
   item units/barcodes, etc.).
   ===================================================================== */
.dt-line-wrap {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--neutral-stroke-rest) transparent;
}

.dt-line {
    font-size: .875rem;
    width: 100%;
    border-collapse: collapse;
    table-layout: auto;
    min-width: 480px;
}

.dt-line thead th {
    padding: 8px 10px;
    text-align: start;
    font-size: .78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.45px;
    color: var(--neutral-foreground-hint);
    border-bottom: 1px solid var(--neutral-stroke-rest);
    white-space: nowrap;
    -webkit-user-select: none;
    user-select: none;
}

    .dt-line thead th.dt-end { text-align: end; }

.dt-line-row {
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
    transition: background 60ms ease;
}

    .dt-line-row:last-child { border-bottom: none; }
    .dt-line-row:hover { background: var(--neutral-fill-stealth-hover, rgba(0, 0, 0, .03)); }

    .dt-line-row td {
        padding: 7px 10px;
        vertical-align: middle;
        white-space: nowrap;
    }

.dt-line-name { font-weight: 500; }
.dt-bold { font-weight: 600; }

/* dt-line column helpers */
.col-num { width: 28px; color: var(--neutral-foreground-hint); font-size: .75rem; }
.col-code { width: 72px; }
.col-item { min-width: 160px; }
.col-num-r { min-width: 80px; text-align: end; }
.col-actions { width: 90px; white-space: nowrap; text-align: end; }

/* Right-align numeric column HEADERS to match their right-aligned cells.
   Needed because `.dt thead th` / `.dt-line thead th` (text-align:start) out-specifies
   the plain `.col-num-r` class, leaving headers left while values are right. */
.dt thead th.col-num-r,
.dt thead th.dt-end,
.dt-line thead th.col-num-r,
.dt-line thead th.col-actions,
.dt-line thead th.dt-end { text-align: end; }

/* =====================================================================
   Row/line card standard: identity + overflow menu header, then
   label/value rows with hairline dividers. Used inside .dt-card (mobile
   list rows) and as the mobile fallback for .dt-line (editable/read-only
   line items). A row for a field that doesn't apply just isn't rendered
   — never left blank — so nothing misaligns between cards.
   ===================================================================== */
.dt-card-id { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.dt-card-lineno { font-size: .68rem; color: var(--neutral-foreground-hint); }
.dt-card-code { font-size: .72rem; }

.dt-card-menu { position: relative; flex-shrink: 0; }
.dt-card-menu summary {
    list-style: none;
    width: 30px; height: 30px;
    display: flex; align-items: center; justify-content: center;
    border-radius: 6px; cursor: pointer;
    color: var(--neutral-foreground-hint); font-size: 1.1rem; font-weight: 700;
}
    .dt-card-menu summary::-webkit-details-marker { display: none; }
    .dt-card-menu summary:hover { background: var(--neutral-fill-stealth-hover, rgba(0, 0, 0, .04)); color: var(--neutral-foreground-rest); }
.dt-card-menu[open] summary { background: color-mix(in srgb, var(--accent-fill-rest) 12%, transparent); color: var(--accent-fill-rest); }
.dt-card-menu-list {
    position: absolute; right: 0; top: 34px; z-index: 20; min-width: 130px;
    background: var(--neutral-layer-1); border: 1px solid var(--neutral-stroke-divider-rest); border-radius: 8px;
    box-shadow: 0 4px 14px rgba(0, 0, 0, .16);
    padding: 4px; display: flex; flex-direction: column; gap: 1px;
}
    .dt-card-menu-list button {
        all: unset; padding: 7px 10px; font-size: .82rem; border-radius: 5px; cursor: pointer;
        color: var(--neutral-foreground-rest);
    }
    .dt-card-menu-list button:hover { background: color-mix(in srgb, var(--accent-fill-rest) 12%, transparent); color: var(--accent-fill-rest); }
    .dt-card-menu-list button.danger:hover { background: color-mix(in srgb, var(--error, #d13438) 12%, transparent); color: var(--error, #d13438); }

.dt-card-div { border-top: 1px solid var(--neutral-stroke-divider-rest); margin: 9px 0 8px; }

.dt-rows .dt-row {
    display: flex; justify-content: space-between; gap: 10px;
    padding: 5px 0; font-size: .83rem;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
}
    .dt-rows .dt-row:last-child { border-bottom: none; }
    .dt-rows .dt-row .k { color: var(--neutral-foreground-hint); }
    .dt-rows .dt-row .v { font-weight: 600; text-align: right; }
    .dt-rows .dt-row.hero .v { color: var(--accent-fill-rest); }

/* Label-above-value variant for long/multi-line text (address, notes, free-text reasons) —
   the default .dt-row squeezes wrapped text into the right half of a flex row, which reads
   badly past ~2 lines; .wide stacks label then value, full width, left-aligned. */
.dt-rows .dt-row.wide {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
}
    .dt-rows .dt-row.wide .v { text-align: left; font-weight: 500; overflow-wrap: anywhere; }

/* Inline section header (title + count + hint on the left, action on the right) */
.section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}

.section-head-left {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.section-title {
    font-size: 16px;
    font-weight: 600;
    margin: 0;
    color: var(--neutral-foreground-rest);
}

.section-hint {
    color: var(--neutral-foreground-hint);
    font-size: .85rem;
}

/* Mobile: the title + hint sit inline on desktop, but on a phone that squeezes the
   hint into a cramped sliver next to the title. Stack them (title over full-width
   hint) and keep any right-side action pinned to the top row beside the title.
   Breakpoint matches the table→card collapse (<768px) so the whole card reads as
   mobile consistently. */
@media (max-width: 767px) {
    .section-head {
        align-items: flex-start;
        gap: 8px 10px;
    }

    .section-head-left {
        flex: 1 1 auto;
        min-width: 0;
        flex-direction: column;
        align-items: flex-start;
        gap: 3px;
    }

    .section-hint {
        font-size: .8rem;
        line-height: 1.35;
    }
}

/* Dashed empty-state box inside a form card */
.dt-empty {
    text-align: center;
    padding: 28px;
    color: var(--neutral-foreground-hint);
    border: 1px dashed var(--neutral-stroke-rest);
    border-radius: 6px;
}

/* Form card gets roomier padding than list cards */
.form-card { padding: 20px 24px; }

/* ============================================================
   form-grid — document-header layout. Every column is guaranteed at
   least 240px (so a field is never squeezed too narrow to read) and
   auto-fit drops the column count 4→3→2→1 fluidly as the card narrows
   — no hand-picked breakpoints, so no per-field ordering to get right.
   .fg-full spans whatever the current column count is.
   ============================================================ */
.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 14px 16px;
}

.form-grid > div { min-width: 0; max-width: 480px; }
.form-grid .fg-full { grid-column: 1 / -1; max-width: none; }
/* .fg-wide is intentionally NOT given a grid-column span here. It looks like it should mean
   "span 2 columns" (and briefly did — see git history), but every one of the ~30 forms using it
   across the app was built and visually tuned around it being a plain 1-column field; making it
   actually span 2 broke field grouping across all of them. Company Profile's Identity card (the
   one place that actually wanted a 2-column-wide field) now has its own dedicated
   .company-identity-fields grid instead of relying on this class — see below. */

/* Keep every field flush with its column. fluent-select (and friends) ship a
   built-in min-width (~250px) that stops them shrinking with the grid cell and
   makes controls overlap on small screens — zero it out inside the grid. */
.form-grid fluent-text-field,
.form-grid fluent-number-field,
.form-grid fluent-select,
.form-grid fluent-combobox,
.form-grid fluent-search,
.form-grid .fluent-datepicker,
.form-grid fluent-text-area {
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100%;
}

.form-grid fluent-select::part(control),
.form-grid fluent-combobox::part(control) {
    min-width: 0;
    width: 100%;
}

/* 2-column variant for narrow containers (modal dialogs) */
.form-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* ============================================================
   form-row — flexbox sibling of .form-grid for header groups that mix a
   short, fixed-vocabulary field (a code, a date, a dropdown with short
   options) with a field whose content length actually varies (warehouse/
   supplier name, free text). Grid's auto-fit gives every column an equal
   1fr share, which stretches the short field just as wide as the long
   one on a roomy screen; flex lets the short field cap out at a sensible
   width while the long field (plain "flex:1", no .fg-narrow) absorbs
   whatever room is left — filling the row without the short field
   looking absurdly wide. flex-wrap reflows to fewer fields per line as
   the container narrows, same as .form-grid's auto-fit, no media query
   needed.
   ============================================================ */
.form-row {
    display: flex;
    flex-wrap: wrap;
    gap: 14px 16px;
}

.form-row > div {
    flex: 1 1 240px;
    min-width: 200px;
    max-width: 480px;
}

.form-row > .fg-narrow {
    flex: 0 1 240px;
    min-width: 160px;
    max-width: 240px;
}

.form-row fluent-text-field,
.form-row fluent-number-field,
.form-row fluent-select,
.form-row fluent-combobox,
.form-row fluent-search,
.form-row .fluent-datepicker,
.form-row fluent-text-area {
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100%;
}

.form-row fluent-select::part(control),
.form-row fluent-combobox::part(control) {
    min-width: 0;
    width: 100%;
}

/* Below this width, a .fg-narrow field is almost always alone on its wrapped line —
   but it would still cap at 240px and leave a dead gap beside it while plain (grow)
   fields on other lines stretch to fill the row, producing a ragged, inconsistent
   right edge down a single-column mobile form. Once nothing pairs up side by side
   anyway, drop the narrow/grow distinction entirely so every field is a uniform
   full-width row, matching how .form-grid already behaves at this width.

   .form-grid needs the same breakpoint for a different reason: grid tracks obey
   minmax(240px, 1fr) as a hard floor — a column never shrinks below 240px, unlike
   a flex item's soft min-width. Below ~290px of available card width that floor
   makes .form-grid fields sit wider than their .form-row siblings (pinned at
   240px while flex items keep shrinking), producing a visible width mismatch
   between e.g. Destination warehouse and Salesman box on a narrow phone. Forcing
   a single explicit 1fr column removes the 240px floor so every field — grid or
   row — shrinks identically. */
@media (max-width: 560px) {
    .form-row > div,
    .form-row > .fg-narrow {
        flex: 1 1 100%;
        max-width: 100%;
    }

    .form-grid {
        grid-template-columns: 1fr;
    }
}

/* Stacked field-group grids/rows in the same card — e.g. Stock In's header splits into
   doc/date/warehouse, reason/supplier, delivery/invoice, and notes as four separate
   .form-grid/.form-row blocks so each group reflows independently on resize without needing
   .fg-spacer cells to hold alignment. Give consecutive groups breathing room. */
.form-card .form-grid + .form-grid,
.form-card .form-grid + .form-row,
.form-card .form-row + .form-grid,
.form-card .form-row + .form-row {
    margin-top: 18px;
}

/* Dialogs: never let a fluent field's built-in min-width push past the dialog edge */
fluent-dialog fluent-select,
fluent-dialog fluent-combobox,
fluent-dialog fluent-search,
fluent-dialog fluent-text-field,
fluent-dialog fluent-number-field,
fluent-dialog fluent-text-area {
    min-width: 0 !important;
    max-width: 100%;
}

/* Uniform label-to-input spacing in dialog forms. Fluent inputs render their label
   as a SEPARATE sibling node, so inside a vertical FluentStack the stack gap lands
   between a label and its own control. Zero the flex gap and rebuild spacing with
   margins: 4px label→control, 14px between field groups. */
fluent-dialog .stack-vertical {
    gap: 0 !important;
}

fluent-dialog .stack-vertical > * {
    margin-bottom: 14px;
}

fluent-dialog .stack-vertical > label.fluent-input-label {
    margin-bottom: 4px;
}

fluent-dialog .stack-vertical > *:last-child {
    margin-bottom: 0;
}

/* ============================================================
   Single-image upload row — company logo, customer ID document, …
   ============================================================ */
.img-upload-row {
    display: flex;
    gap: 20px;
    align-items: flex-start;
    flex-wrap: wrap;
}

.img-upload-preview {
    width: 140px;
    height: 140px;
    border: 1px solid var(--wms-border, #d9dbe0);
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #fff;
    padding: 10px;
    flex: 0 0 auto;
}

.img-upload-preview img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* Company profile — Identity card: logo left, field grid right (logo + fields as one unit,
   not two separate cards). */
.company-identity {
    display: flex;
    gap: 24px;
    align-items: flex-start;
}

.company-identity-logo {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
    text-align: center;
    max-width: 140px;
}

/* Own small grid rather than reusing .form-grid's auto-fit/spacer system — that system's
   breakpoints assume the grid owns the full page width, which breaks once it's a flex sibling
   of the logo. Two fixed columns, no dead spacer cell to hide: NPWP/Phone pair up, everything
   else (name, email, address) just takes the full row. */
.company-identity-fields {
    flex: 1 1 auto;
    min-width: 0;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px 16px;
}

.company-identity-fields .ci-full { grid-column: 1 / -1; }

@media (max-width: 560px) {
    .company-identity { flex-direction: column; align-items: stretch; }
    /* .company-identity-logo now stretches to the full card width (align-items:stretch above) —
       justify-content centers the row within that width instead of it hugging the left edge. */
    .company-identity-logo { flex-direction: row; justify-content: center; max-width: none; }
    .company-identity-fields { grid-template-columns: 1fr; }
}

/* Single-image slots (company logo, …) where the frame itself is the click target — no
   separate dropzone panel needed since only one image is ever allowed. The clicking label wraps
   only the image; the bottom overlay bar is a sibling (not nested in the label) so the Remove
   button living in that bar doesn't also trigger the label's "open file picker" default action. */
.img-upload-preview-clickable {
    position: relative;
    overflow: hidden;
    padding: 0;
}

.img-upload-preview-clickable > label {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 10px;
    cursor: pointer;
}

.img-upload-preview-overlay {
    position: absolute;
    bottom: 0;
    right: 0;
    left: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 4px;
    padding: 2px 2px 2px 8px;
    font-size: .68rem;
    font-weight: 600;
    color: #fff;
    background: linear-gradient(to top, rgba(0, 0, 0, .55), transparent);
}

.img-upload-preview-change {
    display: flex;
    align-items: center;
    gap: 4px;
    cursor: pointer;
    color: inherit;
}

/* Compact icon-only Remove button riding in the same slim overlay bar as "Change". */
.img-upload-preview-overlay fluent-button::part(control) {
    height: 22px;
    min-width: 22px;
    padding: 0 4px;
    color: #fff;
}

/* FluentInputFile's own scoped CSS puts a dashed border + hover background on its wrapping
   .fluent-inputfile-container — appropriate for the drag/drop galleries (item images, customer ID
   doc) but redundant/double-boxed around a click-to-upload frame that already draws its own
   border. Scoped to the company logo slot only, via !important since the library's rule carries
   a scope-hash attribute selector this can't out-specificity otherwise. */
.company-identity-logo .fluent-inputfile-container {
    background-color: transparent !important;
    border: none !important;
}

.img-upload-controls {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 240px;
    flex: 1 1 260px;
}

/* ============================================================
   Printable documents (surat jalan, receipts, invoices)
   A screen preview that looks like paper, and clean print output.
   Forces light document colors regardless of the app theme.
   ============================================================ */
/* Embedded document preview: sticky action bar + a scrollable canvas that holds the
   "paper" sheet, all inside the normal app content (not a full-page takeover). */
.doc-toolbar {
    position: sticky;
    top: 0;
    z-index: 6;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    height: 48px;                 /* match .sidebar-header height */
    padding: 0 16px;
    background: var(--neutral-layer-1, #fff);
    border-bottom: 1px solid var(--neutral-stroke-divider-rest, #e2e4e9);
}

.doc-toolbar-left { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1 1 auto; }
.doc-toolbar-title { font-weight: 700; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.doc-toolbar-right { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }

.doc-preview-wrap {
    padding: 24px 16px;
    overflow: auto;
    background: #e9ebef;
}

@media (prefers-color-scheme: dark) {
    .doc-preview-wrap { background: #26282c; }
}
:root[data-theme="dark"] .doc-preview-wrap { background: #26282c; }
:root[data-theme="light"] .doc-preview-wrap { background: #e9ebef; }

/* Preview pages: let the canvas fill the content area (drop the inner page padding). */
.app-content-inner:has(.doc-preview-wrap) { padding: 0; }

/* The sheet is a FIXED A4 page — it never reflows or scales down. It stays centered
   (margin auto); on screens narrower than the page the canvas simply scrolls, so the
   paper is always true A4 (matches Basis's fixed 794px document iframe). */
.print-sheet {
    background: #fff;
    color: #1a1c20;
    width: 210mm;
    min-height: 297mm;
    margin: 0 auto;
    padding: 18mm 16mm;
    box-sizing: border-box;
    box-shadow: 0 6px 30px rgba(0, 0, 0, .18);
    font-size: 12px;
    line-height: 1.45;
}

/* Wide/many-column reports opt into landscape instead of being squeezed into portrait — paired with
   the "landscape-page" named @page rule below (screen preview only; print sizing is reset under
   @media print same as .print-sheet, then re-widened via the page: landscape-page assignment). */
.print-sheet-landscape {
    width: 297mm;
    min-height: 210mm;
}

/* Letterhead */
.print-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 20px;
    border-bottom: 2px solid #1a1c20;
    padding-bottom: 12px;
}

.print-head-brand { display: flex; gap: 14px; align-items: flex-start; }
.print-logo { width: 64px; height: 64px; object-fit: contain; flex: 0 0 auto; }
.print-company-name { font-size: 17px; font-weight: 700; letter-spacing: .01em; }
.print-company-line { font-size: 11px; color: #3a3d43; }
.print-company-address { white-space: pre-line; }
.print-head-right { flex: 0 0 auto; text-align: right; }
.print-doctitle {
    font-size: 18px;
    font-weight: 700;
    letter-spacing: .12em;
}

/* Document meta (No./date/ref) sitting directly under the title, right side */
.print-headmeta {
    display: inline-block;
    margin-top: 8px;
    min-width: 230px;
    text-align: left;
}
.print-headmeta-row {
    display: flex;
    justify-content: space-between;
    gap: 14px;
    font-size: 11px;
    margin-bottom: 2px;
}
.print-headmeta-label { color: #55585f; }
.print-headmeta-value { font-weight: 600; }

.print-void {
    margin-top: 10px;
    text-align: center;
    font-weight: 700;
    letter-spacing: .2em;
    color: #b42318;
    border: 2px solid #b42318;
    padding: 4px;
}

/* Parties: ship-to (left) + source warehouse (right) */
.print-parties {
    display: flex;
    justify-content: space-between;
    gap: 30px;
    margin-top: 18px;
}

.print-party-block { flex: 1 1 0; min-width: 0; }
.print-party-right { text-align: right; }
.print-party-label {
    font-size: 11px;
    color: #55585f;
    text-transform: uppercase;
    letter-spacing: .03em;
    margin-bottom: 2px;
}
.print-party-name { font-weight: 700; font-size: 13px; }
.print-party-line { font-size: 11px; color: #3a3d43; }

/* Line table */
.print-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 16px;
}

.print-table th,
.print-table td {
    border: 1px solid #c2c3c5;
    padding: 6px 8px;
    text-align: left;
    vertical-align: top;
}

.print-table thead th {
    background: #f0f1f4;
    font-weight: 700;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .03em;
}

.print-table tfoot td {
    font-weight: 700;
    background: #f7f8fa;
}

/* Grouped/register-style report tables (e.g. Sales Detail): a document "header" row per group,
   many of whose columns are intentionally blank (filled only on its item-line rows below, or
   vice versa). The default .print-table gives every th/td a full box border — fine for a normal
   line-item table, but on a table with lots of blank cells it reads as a grid full of empty boxes.
   .print-table-plain drops the per-cell box grid in favor of row-separator lines only (matches a
   classic register/ledger report look), same idea as the app's screen-side .dt table which never
   had per-cell borders to begin with. Opt in with class="print-table print-table-plain". */
.print-table-plain th,
.print-table-plain td {
    border: none;
    border-bottom: 1px solid #d7d9e0;
}

.print-table-plain thead th {
    border-bottom: 1.5px solid #c2c3c5;
}

.print-table-plain tfoot td {
    border: none;
    border-top: 2px solid #1a1c20;
}

.print-table .pt-group-row td {
    background: #eef0f4;
    font-weight: 700;
    border-top: 1.5px solid #1a1c20;
}

.print-table .pt-detail-row td:first-child {
    padding-inline-start: 16px;
}

/* Numbers/codes/dates should never wrap onto a second line inside their narrow column —
   only free-text columns (item name, etc, left at the browser default) wrap. */
.print-table .pt-num { width: 36px; text-align: center; white-space: nowrap; }
.print-table .pt-code { width: 90px; white-space: nowrap; }
.print-table .pt-qty { width: 80px; text-align: right; white-space: nowrap; }
.print-table .pt-unit { width: 70px; white-space: nowrap; }
.print-table .pt-total-label { text-align: right; }

.print-notes {
    margin-top: 12px;
    font-size: 11px;
}

.print-notes-label { font-weight: 700; }

/* Signatures */
.print-signs {
    display: flex;
    gap: 30px;
    margin-top: 34px;
}

.print-sign { flex: 1 1 0; text-align: center; }
.print-sign-role { font-size: 11px; color: #3a3d43; }
.print-sign-space { height: 60px; }
.print-sign-name { border-top: 1px solid #c2c3c5; padding-top: 4px; font-size: 11px; }

@media print {
    /* Print only the document sheet — hide all app chrome + the preview toolbar. Report pages
       (Stock Mutation / Sales / Inventory Valuation) and Stock Card reuse this same mechanism via
       dedicated /print routes + DocumentPrintShell, exactly like every other document type — there
       is no separate "aggregate report" print path to account for here. */
    .app-header,
    .app-sidebar,
    .app-footer,
    .mobile-overlay,
    .doc-toolbar { display: none !important; }

    .app-body-row { display: block !important; }
    .app-content,
    .app-content-inner {
        padding: 0 !important;
        margin: 0 !important;
        overflow: visible !important;
    }

    body,
    .doc-preview-wrap,
    .print-sheet { background: #fff !important; }
    .doc-preview-wrap {
        padding: 0 !important;
        overflow: visible !important;
    }

    .print-sheet {
        width: auto;
        margin: 0;
        padding: 0;
        box-shadow: none;
        min-height: 0;
        font-size: 11pt;
    }
    .print-table thead { display: table-header-group; }
    .print-table tr { page-break-inside: avoid; }

    /* Assigns the landscape named page (below) to this sheet instead of the default portrait @page. */
    .print-sheet-landscape { page: landscape-page; }
}

@page {
    size: A4;
    margin: 14mm;
}

@page landscape-page {
    size: A4 landscape;
    margin: 14mm;
}
