﻿/* ----- Brand tokens (Al Nooran.Net logo + legacy desktop app) ------------- */
:root {
    --brand-navy: #1C3A62;        /* logo lettering, primary */
    --brand-navy-dark: #132A48;
    --brand-gold: #F8B214;        /* logo accent */
    --brand-gold-soft: #FFF4D6;   /* paper only (prints are always white) */
    /* On screen a highlight is a tint of the page's own surface, so it stays readable in
       both themes: cream on white in light mode, a warm navy in dark mode — never a light
       block under light text. */
    --app-highlight: color-mix(in srgb, var(--mud-palette-secondary) 16%, var(--mud-palette-surface));
    --app-highlight-strong: color-mix(in srgb, var(--mud-palette-secondary) 26%, var(--mud-palette-surface));
    --app-highlight-text: var(--mud-palette-text-primary);
    --brand-orange: #F28C28;      /* desktop menu ribbon */
    --brand-teal: #1F6B82;        /* desktop side rail */
    --brand-charcoal: #3C3A45;    /* desktop title bar */
}

/* ----- Global resets / typography ---------------------------------------- */
html, body { margin: 0; padding: 0; height: 100%; }

body {
    font-family: 'Inter', 'Cairo', 'Segoe UI', Tahoma, sans-serif;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

[dir="rtl"] body {
    font-family: 'Cairo', 'Tajawal', 'Inter', 'Segoe UI', sans-serif;
}

/* ----- Login / unauthorized shell ---------------------------------------- */
.auth-shell {
    min-height: 100vh;
    min-height: 100dvh;
    background: radial-gradient(circle at 15% 0%, rgba(28, 58, 98, 0.14), transparent 45%),
                radial-gradient(circle at 100% 100%, rgba(248, 178, 20, 0.16), transparent 45%),
                var(--mud-palette-background);
}

.login-page {
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 32px 16px;
}

.login-card {
    width: 100%;
    max-width: 420px;
    padding: 32px;
    border-radius: 12px;
    background: var(--mud-palette-surface);
}

.login-card { border-top: 4px solid var(--brand-gold); }
.login-brand { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px; }
.login-logo { width: 170px; height: auto; }
.login-title { color: var(--mud-palette-primary); font-weight: 700; }

/* ----- App shell --------------------------------------------------------- */
.app-shell { min-height: 100vh; min-height: 100dvh; background: var(--mud-palette-background); }
.app-content { background: var(--mud-palette-background); min-height: calc(100vh - 60px);
               min-height: calc(100dvh - 60px); }
.app-drawer { border-inline-end: none; box-shadow: 2px 0 8px rgba(0, 0, 0, 0.08); }

/* Top bar: white surface + the desktop app's gold→orange ribbon underneath. */
.app-appbar { border-bottom: 3px solid transparent;
              border-image: linear-gradient(90deg, var(--brand-gold), var(--brand-orange) 55%, var(--brand-gold)) 1; }
.app-brand-link { display: flex; align-items: center; gap: 8px; }
.app-brand-logo { width: 34px; height: 34px; }

/* Sidebar (teal rail): white text, gold active item. */
.app-drawer .mud-nav-link { color: var(--mud-palette-drawer-text); }
.app-drawer .mud-nav-link:hover:not(.mud-nav-link-disabled) { background-color: rgba(255, 255, 255, 0.10); }
.app-drawer .mud-nav-link.active:not(.mud-nav-link-disabled) {
    background-color: rgba(248, 178, 20, 0.16);
    color: var(--brand-gold);
    box-shadow: inset 3px 0 0 var(--brand-gold);
}
[dir="rtl"] .app-drawer .mud-nav-link.active:not(.mud-nav-link-disabled) { box-shadow: inset -3px 0 0 var(--brand-gold); }
.app-drawer .mud-nav-link.active .mud-nav-link-icon { color: var(--brand-gold); }

.app-sidebar-brand {
    display: flex;
    align-items: center;
    padding: 16px 20px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(0, 0, 0, 0.10);
}

.app-sidebar-brand .brand-logo { width: 40px; height: 40px; flex: 0 0 40px; }

.app-sidebar-brand .brand-text {
    margin-inline-start: 8px;
    font-weight: 600;
    font-size: 0.95rem;
    color: #FFFFFF;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.app-sidebar-nav { padding: 8px 0; }

.app-sidebar-heading {
    padding: 10px 20px 4px;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.6);
    letter-spacing: 0.04em;
}

/* ----- Top bar ----------------------------------------------------------- */
.app-topbar-content { display: flex; align-items: center; width: 100%; gap: 4px; }
.app-brand-link { cursor: pointer; margin-inline-end: 16px; }
.app-brand-text { font-weight: 600; color: var(--mud-palette-text-primary); }
.app-search { max-width: 320px; flex: 1 1 auto; }
.app-user-menu-header { padding: 12px 16px; min-width: 220px; }

/* ----- Page header ------------------------------------------------------- */
.app-page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 0 12px;
    flex-wrap: wrap;
    gap: 12px;
}

.app-page-header-text { display: flex; flex-direction: column; }
.app-page-title { font-weight: 600; }
.app-page-subtitle { margin-top: 2px; }
.app-page-header-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* ----- Cards ------------------------------------------------------------- */
.app-card {
    border: 1px solid var(--mud-palette-divider);
    border-radius: 8px;
    background: var(--mud-palette-surface);
    overflow: hidden;
    transition: box-shadow 120ms ease;
}

.app-card:hover { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04); }

.app-card-header { display: flex; align-items: center; padding: 12px 16px; }
.app-card-title { font-weight: 600; color: var(--mud-palette-text-primary); }
.app-card-actions { display: flex; gap: 6px; }
.app-card-body { padding: 16px; }

/* ----- Tables ------------------------------------------------------------ */
.app-table { border: 1px solid var(--mud-palette-divider); border-radius: 8px; overflow: hidden; }
.app-table-search { max-width: 320px; }

/* ----- Loader ------------------------------------------------------------ */
.app-loader {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 48px 16px;
}

.app-loader.inline { flex-direction: row; padding: 8px; }
.app-loader.inline .mud-progress-circular { margin-inline-end: 8px; }

/* ----- Breadcrumbs ------------------------------------------------------- */
.app-breadcrumbs { padding: 0 0 4px; }

/* ----- Modal ------------------------------------------------------------- */
.app-modal-title { display: flex; flex-direction: column; }
.app-modal-body { padding: 8px 4px; min-width: 360px; }

/* ----- RTL tweaks -------------------------------------------------------- */
[dir="rtl"] .app-search input { text-align: right; }
[dir="rtl"] .me-2 { margin-right: 0 !important; margin-left: 0.5rem !important; }
[dir="rtl"] .ms-2 { margin-left: 0 !important; margin-right: 0.5rem !important; }
[dir="rtl"] .me-3 { margin-right: 0 !important; margin-left: 1rem !important; }
[dir="rtl"] .ms-3 { margin-left: 0 !important; margin-right: 1rem !important; }
[dir="rtl"] .ms-1 { margin-left: 0 !important; margin-right: 0.25rem !important; }

/* ----- Error UI (Blazor default) ---------------------------------------- */
#blazor-error-ui {
    background: #b32121;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    color: #fff;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem;
    position: fixed;
    inset-inline: 0;
    z-index: 1300;          /* above the bottom nav (1100): a dead circuit must be recoverable */
}

#blazor-error-ui .dismiss { cursor: pointer; position: absolute; inset-inline-end: 0.75rem; top: 0.5rem; }

/* ----- Utilities used by the phone layout (all sizes) --------------------- */
/* A cell holding two stacked facts (name + code, batch + expiry). Without this the
   two children sit side by side at ~100px each once a row stacks into a card. */
.cell-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
              min-width: 0; width: 100%; }
/* A filter control above a list: fixed-ish on desktop, full width on a phone. */
.filter-select { min-width: 160px; flex: 0 1 200px; }
/* Keeps a form's primary action reachable instead of 2000px below the fold. */
.app-form-actions { display: flex; justify-content: flex-end; gap: 8px; }
.u-hide-xs { }

/* ----- Bottom-nav clearance (wherever the nav renders — below md) --------- */
/* This has to beat MudBlazor's `.pa-4 { padding: 16px !important }`, which sits on
   the very same element; without !important the rule silently does nothing and the
   last 56px of every page stays buried under the nav. */
@media (max-width: 959.98px) {
    .app-content-wrap.has-bottom-nav {
        padding-bottom: calc(72px + env(safe-area-inset-bottom)) !important;
    }
}

/* ----- Mobile breakpoints (xs only — < 600px) ---------------------------- */
@media (max-width: 599.98px) {
    /* Single-column page header on phone, with actions that share the width */
    .app-page-header { flex-direction: column; align-items: stretch; }
    .app-page-header-actions { justify-content: stretch; gap: 8px; }
    .app-page-header-actions > * { flex: 1 1 140px; }

    /* Larger tap zones in tables on phone */
    .mud-table-cell { padding: 12px 16px !important; }

    /* --- Stacked table rows read as cards ---------------------------------
       MudTable already switches to its small-device layout at xs; what it does
       not do is make the result legible. */
    .app-table .mud-table-row,
    .mud-table-root .mud-table-row {
        display: block;
        border: 1px solid var(--mud-palette-divider);
        border-radius: 10px;
        margin-block-end: 8px;
        overflow: hidden;
    }
    .mud-table-cell { flex-wrap: wrap; }
    .mud-table-cell:before { color: var(--mud-palette-text-secondary); font-size: .78rem; }
    .mud-table-cell .mud-input-control { flex: 1 1 100%; }
    .mud-table-cell:empty { display: none; }
    /* Columns hidden at narrow widths are exactly what a salesman opens the app to
       look up — a mobile number, a credit limit, a status. Once the row is a card
       there is room for them, so bring them back. */
    .mud-table-cell.d-none { display: flex !important; }

    /* The toolbar wraps instead of clipping — `.app-table { overflow: hidden }`
       used to cut the filter box off, so a phone user could not filter a list. */
    .app-table .mud-table-toolbar { flex-wrap: wrap; height: auto; min-height: 0;
                                    padding: 8px; gap: 8px; }
    .app-table-search { max-width: none; width: 100%; }
    /* The Arabic "rows per page" caption + select + arrows overflow 375px. */
    .mud-table-pagination-caption, .mud-table-pagination-select { display: none !important; }
    /* A simple table cannot stack — let it scroll sideways inside its own box. */
    .mud-simple-table { overflow-x: auto; }

    /* --- Dialogs take the whole screen ------------------------------------
       .mud-dialog-width-full is calc(100% - 64px) inside a fixed centring flexbox,
       so an over-wide dialog overflows BOTH edges and its start edge is unreachable. */
    .mud-dialog-container { align-items: stretch; justify-content: stretch; }
    .mud-dialog-container .mud-dialog:not(.mud-dialog-fullscreen) {
        margin: 0; width: 100%; max-width: 100%;
        height: 100dvh; max-height: 100dvh; border-radius: 0;
    }
    .mud-dialog-content { padding-inline: 12px; }
    .app-modal-body { min-width: 0; overflow-x: auto; }

    /* --- Top bar fits 375px ----------------------------------------------- */
    .app-brand-text { display: none; }
    .app-topbar-content { gap: 0; }
    .app-branch-chip { max-width: 96px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

    /* --- Filters and forms ------------------------------------------------ */
    .filter-select { flex: 1 1 100%; max-width: 100% !important; min-width: 0; }
    /* The primary action travels with the page instead of hiding under the fold. */
    .app-form-actions { position: sticky; inset-block-end: calc(72px + env(safe-area-inset-bottom));
                        background: var(--mud-palette-surface); padding-block: 8px; z-index: 2; }

    /* Keep the recovery bar and snackbars clear of the bottom nav. */
    #blazor-error-ui { bottom: calc(56px + env(safe-area-inset-bottom)); }
    .mud-snackbar-location-bottom-right,
    .mud-snackbar-location-bottom-left,
    .mud-snackbar-location-bottom-center {
        bottom: calc(72px + env(safe-area-inset-bottom)); inset-inline: 8px;
    }

    /* --- A plain table becomes cards ---------------------------------------
       MudSimpleTable is a bare <table>: it has no small-device mode, so a 4-column
       one simply runs off the screen with its last column — usually the field the
       user actually operates — unreachable. Opt in with class="app-cards-xs" and
       put data-label on each <td>. */
    .app-cards-xs thead { display: none; }
    .app-cards-xs tr {
        display: block;
        border: 1px solid var(--mud-palette-divider);
        border-radius: 10px;
        padding: 8px;
        margin-block-end: 8px;
    }
    .app-cards-xs td {
        display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center;
        gap: 8px; border: 0 !important; padding: 4px 0 !important; text-align: start !important;
    }
    .app-cards-xs td[data-label]:before {
        content: attr(data-label);
        color: var(--mud-palette-text-secondary);
        font-size: .78rem;
    }
    /* A cell holding a control gets the whole line for it, under its caption. */
    .app-cards-xs td .mud-input-control { flex: 1 1 100%; max-width: none; }
    .price-picker-input { max-width: none !important; }

    /* Columns a phone has no room for opt out with this class. */
    .u-hide-xs { display: none !important; }
}

/* ----- Touch-target enforcement (any touch device, any size) ------------- */
@media (hover: none) and (pointer: coarse) {
    .mud-button-root,
    .mud-icon-button {
        min-height: 44px;
        min-width: 44px;
    }
    /* The controls a thumb actually misses: menu rows (logout, cash account,
       payment method, supplier), sidebar links, dense inputs, and the branch
       chip — which is the only way to change branch. */
    .mud-nav-link { min-height: 44px; }
    .mud-list-item, .mud-popover .mud-list-item { min-height: 44px; }
    .mud-chip.mud-clickable { min-height: 32px; }
    .app-branch-chip { min-height: 44px; padding-inline: 12px; }
    .mud-input-control-margin-dense .mud-input-root { min-height: 44px; }
    /* A keyboard hint is noise on a device with no F-keys. */
    .pos-key { display: none; }
}

/* ----- Bottom nav --------------------------------------------------------- */
.app-bottom-nav {
    position: fixed;
    bottom: 0;
    inset-inline: 0;          /* RTL-safe equivalent of left:0; right:0 */
    z-index: 1100;
    background: var(--mud-palette-surface);
    border-top: 1px solid var(--mud-palette-divider);
    padding-bottom: env(safe-area-inset-bottom);   /* home-indicator gap on iOS */
}

.app-bottom-nav .bn-row {
    display: flex;
    width: 100%;
    height: 56px;
}

.app-bottom-nav .bn-item {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    padding: 6px 4px;
    color: var(--mud-palette-text-secondary);
    font-family: inherit;
    cursor: pointer;
    transition: color 120ms ease;
}

.app-bottom-nav .bn-item.active { color: var(--mud-palette-primary); }
.app-bottom-nav .bn-item:hover { color: var(--mud-palette-primary); }
.app-bottom-nav .bn-item:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -2px;
}

.app-bottom-nav .bn-label {
    font-size: 0.7rem;
    margin-top: 2px;
    line-height: 1;
}

/* RTL: bottom nav already mirrors thanks to flex; nothing to add. */

/* ============================================================================
   Printable tax invoice (/sales/invoices/{id}/print) — bilingual AR/EN, A4.
   ============================================================================ */
.print-shell { background: #eef0f3; min-height: 100vh; min-height: 100dvh; color: #111; }
.tax-invoice {
    background: #fff; max-width: 210mm; margin: 0 auto 24px; padding: 14mm 12mm;
    font-family: "Segoe UI", Tahoma, Arial, sans-serif; font-size: 12px; line-height: 1.45;
    box-shadow: 0 1px 6px rgba(0, 0, 0, .12);
}
.tax-invoice table { border-collapse: collapse; width: 100%; }
.ti-head { display: grid; grid-template-columns: 1fr auto 1fr; gap: 12px; align-items: start;
           border-bottom: 3px solid var(--brand-navy); padding-bottom: 10px; }
.ti-title-ar, .ti-title-en { color: var(--brand-navy); }
.ti-party .ti-name { font-weight: 700; font-size: 14px; }
.ti-title { text-align: center; padding-top: 4px; }
.ti-logo { display: block; width: 22mm; height: auto; margin: 0 auto 4px; }
/* The document number as bars, under the title — where the eye already looks for it. */
.ti-barcode { margin-top: 6px; font-size: 11px; letter-spacing: .03em; }
.ti-barcode .code128 { display: block; width: 52mm; height: 10mm; margin: 0 auto 2px; }
.ti-title-ar { font-size: 20px; font-weight: 700; }
.ti-title-en { font-size: 14px; letter-spacing: .5px; }
.ti-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 12px 0; }
.ti-meta th, .ti-meta td { border: 1px solid #c9ccd1; padding: 4px 6px; text-align: start; }
.ti-meta th { background: #f4f5f7; font-weight: 600; width: 45%; }
.ti-lines th, .ti-lines td { border: 1px solid #c9ccd1; padding: 5px 6px; text-align: center; vertical-align: top; }
.ti-lines thead th { background: #f4f5f7; font-size: 11px; }
.ti-left { text-align: start !important; }
.ti-small { font-size: 10px; color: #555; word-break: break-all; }
.ti-foot { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; margin-top: 12px; }
.ti-totals { max-width: 340px; }
.ti-totals th, .ti-totals td { border: 1px solid #c9ccd1; padding: 5px 8px; }
.ti-totals th { background: #f4f5f7; text-align: start; font-weight: 600; }
.ti-totals th span { font-weight: 400; font-size: 10px; color: #555; }
.ti-totals td { text-align: end; white-space: nowrap; }
.ti-grand th, .ti-grand td { font-size: 14px; font-weight: 700; background: var(--brand-gold-soft); }
.ti-notes { margin-top: 12px; border-top: 1px dashed #c9ccd1; padding-top: 6px; }

@media print {
    @page { size: A4; margin: 8mm; }
    .no-print { display: none !important; }
    .print-shell { background: #fff; }
    .tax-invoice { box-shadow: none; margin: 0; padding: 0; max-width: none; }
}

/* Tables: navy-tinted header row, like the desktop grids' header strip. */
.app-table .mud-table-head .mud-table-cell {
    background: rgba(28, 58, 98, 0.06);
    color: var(--mud-palette-primary);
    font-weight: 600;
}

/* Secondary = brand gold, but pages historically use Color.Secondary on MudText /
   MudIcon to mean "muted caption". Gold text on white is unreadable, so text and
   icon usages fall back to the muted text colour; gold stays on buttons, chips,
   progress bars and the active sidebar item (which don't use this class). */
.mud-secondary-text { color: var(--mud-palette-text-secondary) !important; }
.ti-reason { margin: 0 0 10px; padding: 6px 8px; background: var(--brand-gold-soft); border-inline-start: 3px solid var(--brand-gold); }

/* ----- Treasury ----------------------------------------------------------- */
.treasury-card { border: 1px solid var(--mud-palette-divider); border-radius: 10px;
                 border-top: 3px solid var(--mud-palette-primary); }
.treasury-total { border: 1px solid var(--mud-palette-divider); border-radius: 8px;
                  background: var(--app-highlight); color: var(--app-highlight-text); }
.amount-words { padding: 6px 10px; border-radius: 6px; background: var(--app-highlight);
                border-inline-start: 3px solid var(--brand-gold); color: var(--app-highlight-text); }

/* Printable voucher */
.voucher-print { max-width: 210mm; font-size: 13px; }
.voucher-body { margin-top: 14px; }
.voucher-body th, .voucher-body td { border: 1px solid #c9ccd1; padding: 8px 10px; text-align: start; }
.voucher-body th { background: #f4f5f7; width: 17%; white-space: nowrap; }
.voucher-amount { font-size: 16px; }
.voucher-void { margin-top: 6px; color: #c62828; font-weight: 700; border: 2px solid #c62828;
                display: inline-block; padding: 2px 10px; transform: rotate(-4deg); }
.voucher-signs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: 48px; }
.voucher-signs div { border-top: 1px solid #111; padding-top: 6px; text-align: center; }
/* Cash handover: two people sign — the one who handed the cash over and the one who took it. */
.voucher-signs.two { grid-template-columns: repeat(2, 1fr); gap: 48px; }
.voucher-signs .sign-name { margin-top: 4px; font-weight: 700; min-height: 1.2em; border: 0; padding: 0; }
.handover-stamp { margin-top: 6px; font-weight: 700; border: 2px solid; border-radius: 4px; padding: 2px 8px; display: inline-block; }
.handover-stamp.ok { color: #2e7d32; border-color: #2e7d32; }
.handover-stamp.pending { color: #b26a00; border-color: #b26a00; }
/* Named page: only the voucher prints on A5 landscape; invoices and sheets stay A4. */
@page voucher { size: A5 landscape; margin: 8mm; }
.voucher-print { page: voucher; }

/* ----- Sales invoice counter --------------------------------------------- */
.inv-panel { border: 1px solid var(--mud-palette-divider); border-radius: 10px; }
.inv-totals { border-top: 3px solid var(--brand-gold); }
.inv-grand { font-size: 2rem; font-weight: 700; color: var(--mud-palette-primary); text-align: end; line-height: 1.2; }
.inv-grand small { font-size: .9rem; font-weight: 500; color: var(--mud-palette-text-secondary); }
.inv-payment-row { display: grid; grid-template-columns: 1fr 1fr 1fr auto; gap: 6px; align-items: center; margin-bottom: 6px; }
.inv-payment-row > .mud-input-control:nth-child(4) { grid-column: 1 / 4; }
.barcode-box input { font-size: 1.05rem; letter-spacing: .04em; }
@media (max-width: 600px) { .inv-payment-row { grid-template-columns: 1fr; } }

/* ----- Daily treasury (يومية الخزينة) ------------------------------------ */
.session-card { border: 1px solid var(--mud-palette-divider); border-radius: 10px; border-top: 3px solid var(--brand-gold); }
.session-card.is-open { border-top-color: var(--mud-palette-success); }
.session-stat { border: 1px solid var(--mud-palette-divider); border-radius: 8px; padding: 10px 12px; height: 100%; }
.session-stat .label { font-size: .8rem; color: var(--mud-palette-text-secondary); }
.session-stat .value { font-size: 1.25rem; font-weight: 700; }
.session-debit { color: var(--mud-palette-success); }
.session-credit { color: var(--mud-palette-error); }
.session-print .ti-lines td.num, .session-print .ti-lines th.num { text-align: end; white-space: nowrap; }
.session-print .ti-lines tfoot td { font-weight: 700; background: #f4f5f7; }

/* Invoice line: unit button + manually typed price */
.inv-unit-btn { justify-content: space-between; text-transform: none; min-width: 90px; }
.inv-price-manual input { color: var(--brand-teal, #1F6B82); font-weight: 600; }

.inv-price-missing { color: var(--mud-palette-warning); display: block; line-height: 1.2; margin-top: 2px; }
/* Pickers: current row highlight readable in light and dark themes. */
.picker-current td { background: rgba(248, 178, 20, .18) !important; font-weight: 600; }
.price-picker-input { max-width: 130px; margin-inline-start: auto; }
.price-picker-input input { text-align: end; }

/* Role permission matrix */
.perm-group { border: 1px solid var(--mud-palette-divider); border-radius: 10px; }
.perm-group .mud-checkbox { margin-block: -4px; }


/* ----- Point of sale ------------------------------------------------------ */
/* The till owns the whole viewport: a fixed bar, then a two-column body that
   scrolls only inside the cart. Nothing here leaks into the rest of the app. */
.pos-shell { height: 100vh; height: 100dvh; display: flex; flex-direction: column;
             background: var(--mud-palette-background); }
.pos-bar { display: flex; align-items: center; gap: 16px; padding: 6px 14px; min-height: 52px;
           background: var(--pos-bar-bg, var(--mud-palette-primary)); color: #fff; }
.pos-bar .mud-input, .pos-bar .mud-input-label, .pos-bar .mud-select-input { color: #fff !important; }
.pos-bar .mud-input-underline:before { border-color: rgba(255,255,255,.4) !important; }
.pos-bar-start { display: flex; align-items: center; font-size: 15px; }
.pos-bar-mid { display: flex; align-items: center; gap: 12px; flex: 1; }
.pos-bar-end { display: flex; align-items: center; gap: 4px; }
.pos-bar-end .mud-icon-button { color: #fff; }
.pos-bar-select { max-width: 200px; }

.pos-body { flex: 1; display: grid; grid-template-columns: 1fr 340px; gap: 12px; padding: 12px; min-height: 0; }
/* With the item panel on, the till reads right-to-left exactly like the desktop one:
   categories, then the wall of items, then the lines, then the totals. */
.pos-body.with-board { grid-template-columns: var(--pos-cats-w, 180px) var(--pos-board-w, 1.2fr) 1.4fr 320px; }
.pos-body.with-board.no-rail { grid-template-columns: var(--pos-board-w, 1.2fr) 1.4fr 320px; }
.pos-cart { display: flex; flex-direction: column; min-height: 0;
            border: 1px solid var(--mud-palette-divider); border-radius: 10px; background: var(--mud-palette-surface); }
.pos-scan { display: flex; gap: 10px; align-items: center; padding: 10px; border-bottom: 1px solid var(--mud-palette-divider); }
.pos-scan-box { flex: 1; }
.pos-scan-box .mud-input-root { font-size: 18px; }
.pos-lines { flex: 1; overflow: auto; min-height: 0; }
.pos-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
             color: var(--mud-palette-text-secondary); }

.pos-table { width: 100%; border-collapse: collapse; }
.pos-table thead th { position: sticky; top: 0; z-index: 1; background: rgba(28, 58, 98, 0.06);
                      color: var(--mud-palette-primary); font-weight: 600; font-size: 12px;
                      padding: 8px 10px; text-align: start; }
.pos-table td { padding: 6px 10px; border-bottom: 1px solid var(--mud-palette-divider); vertical-align: middle; }
.pos-table tbody tr { cursor: pointer; }
.pos-row-active { background: var(--app-highlight-strong); }
.pos-row-active td, .pos-row-active input { color: var(--app-highlight-text) !important; }
.pos-muted { font-size: 11px; color: var(--mud-palette-text-secondary); }
.pos-qty { display: flex; align-items: center; gap: 2px; }
.pos-qty-field { max-width: 70px; }
.pos-qty-field input { text-align: center; font-weight: 600; }

.pos-side { display: flex; flex-direction: column; gap: 12px; min-height: 0; }
.pos-customer, .pos-totals, .pos-actions { border: 1px solid var(--mud-palette-divider); border-radius: 10px;
                                           background: var(--mud-palette-surface); padding: 10px; }
.pos-totals { flex: 1; display: flex; flex-direction: column; justify-content: center; }
.pos-totals .row { display: flex; justify-content: space-between; padding: 3px 0; font-size: 14px; }
.pos-totals .grand { border-top: 1px solid var(--mud-palette-divider); margin-top: 6px; padding-top: 8px;
                     font-size: 26px; font-weight: 700; color: var(--mud-palette-primary); }
.pos-words { margin-top: 8px; padding: 6px 8px; border-radius: 6px; background: var(--app-highlight);
             color: var(--app-highlight-text); font-size: 12px; }
.pos-count { margin-top: 6px; font-size: 12px; color: var(--mud-palette-text-secondary); }
.pos-actions { display: flex; flex-direction: column; gap: 8px; }
.pos-actions-row { display: flex; gap: 8px; }
.pos-last { border-top: 1px dashed var(--mud-palette-divider); padding-top: 8px; }
.pos-key { display: inline-block; margin-inline-start: 6px; padding: 0 5px; border-radius: 4px;
           border: 1px solid currentColor; font-size: 10px; opacity: .75; }

/* Payment dialog */
.pos-pay-due { display: flex; justify-content: space-between; align-items: baseline;
               padding: 10px 12px; border-radius: 8px; background: var(--app-highlight); color: var(--app-highlight-text); }
.pos-pay-due b { font-size: 26px; }
.pos-pay-input input { font-size: 24px; text-align: center; font-weight: 700; }
.pos-quick { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.pos-pay-change { display: flex; justify-content: space-between; align-items: baseline; margin-top: 12px;
                  padding: 10px 12px; border-radius: 8px; background: rgba(46, 125, 50, .12); }
.pos-pay-change b { font-size: 24px; color: #2e7d32; }
.pos-pay-change.short { background: rgba(198, 40, 40, .12); }
.pos-pay-change.short b { color: #c62828; }

/* Item picker */
.pos-pick { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; margin-top: 12px;
            max-height: 46vh; overflow: auto; }
.pos-pick-item { display: flex; flex-direction: column; gap: 2px; padding: 10px; min-height: 76px;
                 border: 1px solid var(--mud-palette-divider); border-radius: 8px; cursor: pointer;
                 background: var(--mud-palette-surface); color: inherit; text-align: start; font: inherit; }
.pos-pick-item:hover { border-color: var(--mud-palette-primary); background: rgba(28, 58, 98, .05); }
.pos-pick-item .name { font-weight: 600; font-size: 13px; }
.pos-pick-item .meta, .pos-pick-item .price { font-size: 11px; color: var(--mud-palette-text-secondary); }

@media (max-width: 1400px) {
    /* Not enough width for four columns: the category rail folds away first, then the
       board, because a cashier can still scan and search without either. */
    .pos-body.with-board { grid-template-columns: var(--pos-board-w, 1.2fr) 1.4fr 320px; }
    .pos-body.with-board .pos-rail { display: none; }
}

@media (max-width: 1100px) {
    .pos-body, .pos-body.with-board, .pos-body.with-board.no-rail { grid-template-columns: 1fr; }
    .pos-body.with-board .pos-board { display: none; }
    .pos-side { flex-direction: row; flex-wrap: wrap; }
    .pos-customer, .pos-totals, .pos-actions { flex: 1 1 280px; }
}

/* ----- Thermal receipt (80 mm roll) --------------------------------------- */
/* Its own named page so invoices stay A4 and vouchers stay A5. */
@page receipt { size: 80mm auto; margin: 3mm; }
.pos-receipt { page: receipt; width: 74mm; margin: 0 auto; padding: 6px 0; background: #fff; color: #000;
               font-family: "Tahoma", "Segoe UI", sans-serif; font-size: 11px; line-height: 1.45; }
.pos-receipt .r-head { text-align: center; }
.pos-receipt .r-name { font-size: 15px; font-weight: 700; }
.pos-receipt .r-title { margin-top: 6px; padding: 3px 0; border-block: 1px dashed #000; font-weight: 700; }
.pos-receipt .r-meta { margin-top: 6px; }
.pos-receipt .r-meta div { display: flex; justify-content: space-between; }
.pos-receipt .r-lines { width: 100%; border-collapse: collapse; margin-top: 8px; }
.pos-receipt .r-lines th { border-bottom: 1px dashed #000; font-size: 10px; padding: 3px 2px; text-align: start; }
.pos-receipt .r-lines td { padding: 3px 2px; vertical-align: top; text-align: start; }
.pos-receipt .r-lines td:not(.r-item) { text-align: end; white-space: nowrap; }
.pos-receipt .r-item { width: 46%; }
.pos-receipt .r-sub { font-size: 9px; color: #444; }
.pos-receipt .r-totals { margin-top: 8px; border-top: 1px dashed #000; padding-top: 6px; }
.pos-receipt .r-totals div { display: flex; justify-content: space-between; padding: 1px 0; }
.pos-receipt .r-grand { margin-top: 4px; padding-top: 4px; border-top: 1px solid #000; font-size: 15px; font-weight: 700; }
.pos-receipt .r-qr { margin-top: 10px; text-align: center; }
.pos-receipt .r-foot { margin-top: 10px; text-align: center; border-top: 1px dashed #000; padding-top: 6px; }

/* The narrow roll: its own named page, and a smaller type size so four columns of a
   line still fit in 54 mm. */
@page receipt58 { size: 58mm auto; margin: 2mm; }
.pos-receipt.w58 { page: receipt58; width: 54mm; font-size: 10px; }
.pos-receipt.w58 .r-name { font-size: 13px; }
.pos-receipt.w58 .r-grand { font-size: 13px; }
.pos-receipt.w58 .r-lines th { font-size: 9px; }

/* The emblem, small. A thermal head prints black or nothing, so a colour logo is
   greyscaled and hardened rather than left to the printer to dither into a smudge. */
.pos-receipt .r-logo { display: block; width: 20mm; height: auto; margin: 0 auto 4px; }
.pos-receipt.w58 .r-logo { width: 15mm; }

/* The invoice number as bars, for the scanner at the return counter. Kept narrower
   than the roll: stretched across 74 mm the bars get no easier to read, only harder
   to fit in a scanner's window. */
.pos-receipt .r-barcode { margin-top: 8px; text-align: center; }
.pos-receipt .r-barcode .code128 { display: block; width: 100%; max-width: 62mm; height: 11mm; margin: 0 auto; }
.pos-receipt.w58 .r-barcode .code128 { height: 9mm; }

/* A second copy is its own slip: its own page on screen, its own cut on the roll. */
.pos-receipt + .pos-receipt { margin-top: 14px; border-top: 1px dashed #999; padding-top: 10px; }

.rcp-preview { display: flex; justify-content: center; padding: 12px; background: #eef0f3; border-radius: 8px; }

@media print {
    .pos-receipt { width: auto; }
    .pos-receipt .r-logo { filter: grayscale(1) contrast(1.4); }
    .pos-receipt + .pos-receipt { break-before: page; margin-top: 0; border-top: 0; padding-top: 6px; }
}

.pos-branch { margin-inline-start: 10px; padding: 1px 8px; border-radius: 10px; font-size: 11px;
              background: rgba(255,255,255,.18); }
.pos-flag { margin-inline-start: 6px; padding: 0 5px; border-radius: 4px; font-size: 10px; font-weight: 600; }
.pos-flag.danger { background: rgba(198,40,40,.15); color: #c62828; }
.pos-flag.warn { background: rgba(245,124,0,.15); color: #ef6c00; }

/* ----- Money inputs ------------------------------------------------------- */
/* Numbers stay Latin and left-to-right even on an Arabic page, and they sit at
   the end of the box where the eye looks for them. Without this, a right-to-left
   context reorders "1,234.50" and a long value is clipped instead of scrolled. */
.inv-num input, .pos-qty-field input, .price-picker-input input {
    direction: ltr;
    text-align: end;
    font-variant-numeric: tabular-nums;
}
.inv-num-cell { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* The price picker used to be an adornment INSIDE the field, which ate the width
   the number needed. It is a button beside the field now. */
.inv-price-cell { display: flex; align-items: center; gap: 2px; }
.inv-price-cell .mud-input-control { flex: 1 1 auto; min-width: 0; }
.inv-price-btn { flex: 0 0 auto; }

/* ----- Till skin ---------------------------------------------------------- */
/* Everything a shop can change about the till comes through these custom
   properties, set once on .pos-skin from the saved settings. No component
   branches on a colour or a size — they read a variable. */
.pos-skin { flex: 1; display: flex; flex-direction: column; min-height: 0;
            font-size: calc(1rem * var(--pos-font-scale, 1)); }
.pos-skin .pos-table td, .pos-skin .pos-table th { height: var(--pos-row-h, 38px); }

/* التصنيف — the category column */
.pos-rail { display: flex; flex-direction: column; min-height: 0; gap: 8px; padding: 10px;
            border: 1px solid var(--mud-palette-divider); border-radius: 10px;
            background: var(--mud-palette-surface); }
.pos-rail-head { font-weight: 700; font-size: 13px; color: var(--mud-palette-text-secondary); }
.pos-rail-list { display: flex; flex-direction: column; gap: 6px; overflow: auto; min-height: 0; }
.pos-rail-empty { padding: 10px; font-size: 12px; color: var(--mud-palette-text-secondary); text-align: center; }
.pos-cat { border: 0; border-radius: 8px; cursor: pointer; text-align: start; font: inherit;
           padding: 0 10px; min-height: var(--pos-row-h, 38px); line-height: 1.2;
           background: var(--pos-cat-bg, #3C3A45); color: #fff; font-size: .82em; }
.pos-cat:hover { filter: brightness(1.15); }
.pos-cat-on { outline: 3px solid var(--pos-accent, #F8B214); outline-offset: -3px; font-weight: 700; }

/* TUCH — the item wall */
.pos-board { display: flex; flex-direction: column; min-height: 0; gap: 8px; padding: 10px;
             border: 1px solid var(--mud-palette-divider); border-radius: 10px;
             background: var(--mud-palette-surface); }
.pos-board-head { display: flex; align-items: center; gap: 8px; }
.pos-board-pager { display: flex; align-items: center; gap: 2px; font-size: 12px; white-space: nowrap; }
.pos-board-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
                   color: var(--mud-palette-text-secondary); font-size: 13px; }
.pos-board-grid { flex: 1; overflow: auto; min-height: 0; display: grid; gap: var(--pos-tile-gap, 8px);
                  grid-template-columns: repeat(auto-fill, minmax(var(--pos-tile-size, 130px), 1fr));
                  align-content: start; }
.pos-tile { display: flex; flex-direction: column; align-items: stretch; justify-content: space-between;
            aspect-ratio: var(--pos-tile-aspect, 1.5); overflow: hidden; cursor: pointer;
            border: 0; border-radius: 8px; padding: 6px 6px 0; font: inherit; text-align: center;
            background: var(--pos-tile-bg, #1F6B82); color: var(--pos-tile-fg, #fff); }
.pos-tile:hover { filter: brightness(1.12); }
.pos-tile:active { transform: translateY(1px); }
.pos-tile-art { flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;
                font-size: 1.6em; font-weight: 700; opacity: .85; }
.pos-tile-art img { max-width: 100%; max-height: 100%; object-fit: contain; }
.pos-tile-name { font-size: .78em; font-weight: 600; line-height: 1.25; overflow: hidden;
                 display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.pos-tile-code { font-size: .65em; opacity: .75; }
.pos-tile-price { margin: 4px -6px 0; padding: 3px 0; font-size: .78em; font-weight: 700;
                  background: var(--pos-tile-price-bg, #0F4E5F); }

/* the same items as a list, for a shop that prefers reading to tapping */
.pos-board-list { flex: 1; overflow: auto; min-height: 0; display: flex; flex-direction: column; gap: 4px; }
.pos-listrow { display: flex; align-items: center; gap: 10px; cursor: pointer; font: inherit; text-align: start;
               padding: 0 10px; min-height: var(--pos-row-h, 38px); border-radius: 8px;
               border: 1px solid var(--mud-palette-divider); background: var(--mud-palette-surface); color: inherit; }
.pos-listrow:hover { border-color: var(--pos-accent, #F8B214); }
.pos-listrow .name { flex: 1; font-size: .82em; font-weight: 600; }
.pos-listrow .code { font-size: .7em; color: var(--mud-palette-text-secondary); }
.pos-listrow .price { font-size: .82em; font-weight: 700; }

/* ----- The till on a phone (xs) ------------------------------------------ */
/* A third stage after the 1400px and 1100px ones. The 1100px rule hides the item
   board, which on a phone would leave a cashier hand-typing barcodes — so here the
   board comes back and the board and the cart take turns instead. */
.pos-phonetabs { display: none; }
.pos-actions-total { display: flex; justify-content: space-between; align-items: baseline;
                     font-size: 1.05rem; padding-bottom: 4px; }
.pos-actions-total b { font-size: 1.3rem; }

@media (max-width: 599.98px) {
    .pos-phonetabs { display: flex; gap: 8px; padding: 8px 8px 0; }

    .pos-body { overflow: auto; padding: 8px; gap: 8px; }
    /* Undo the 1100px hide, then show one pane at a time. */
    .pos-body.with-board .pos-board { display: flex; }
    .pos-body.ph-cart .pos-board { display: none; }
    .pos-body.ph-items .pos-cart,
    .pos-body.ph-items .pos-side { display: none; }
    .pos-board-grid { --pos-tile-size: 110px; }

    /* The top bar wraps instead of giving the whole page a sideways scroll. */
    .pos-bar { flex-wrap: wrap; gap: 8px; padding: 6px 10px; }
    .pos-bar-mid { flex-basis: 100%; order: 3; }
    .pos-bar-select { max-width: none; flex: 1 1 140px; }

    /* Cart lines become cards: the hand-rolled table needs ~660px against ~351px,
       so the line total and the delete X were reachable only by side-swiping. */
    .pos-table thead { display: none; }
    .pos-table tr { display: grid; grid-template-columns: 1fr auto; gap: 4px;
                    padding: 8px; border-bottom: 1px solid var(--mud-palette-divider); }
    .pos-table td { display: block; border: 0; padding: 2px 0; }
    .pos-table td:first-child { grid-column: 1 / -1; }

    /* The -/qty/+ stepper needs ~158px in a ~56px column, so + was off-screen —
       and it is the most common gesture at a till. */
    .pos-qty { width: 100%; justify-content: space-between; gap: 8px; }
    .pos-qty-field { max-width: none; flex: 1; }

    /* Pay stays on screen with the amount beside it. */
    .pos-actions { position: sticky; inset-block-end: 0; z-index: 2;
                   box-shadow: 0 -2px 8px rgba(0, 0, 0, .12); }
}

/* ============================================================================
   Charts (the dashboard)
   Marks are drawn in the component; this file holds only the chrome around them.
   Everything here reads the MudBlazor palette variables, so light and dark follow
   the app's own theme instead of being flipped by hand.
   ============================================================================ */

.viz { width: 100%; }

/* The hover band is invisible until it is hovered — then it lifts the whole
   column slightly so the pointer has visible feedback before the tooltip lands. */
.viz-band { cursor: crosshair; }
.viz-band:hover { fill: var(--mud-palette-action-default-hover); }

.viz-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    margin-top: 10px;
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
}

.viz-legend-item { display: inline-flex; align-items: center; gap: 6px; }

.viz-legend-item b { color: var(--mud-palette-text-primary); }

/* A square, not a line: at 10px a colour reads more reliably as a filled chip. */
.viz-swatch {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    display: inline-block;
    flex: 0 0 auto;
}

.viz-share-track {
    display: flex;
    /* 2px of surface between segments, so two adjacent fills never merge into one. */
    gap: 2px;
    height: 14px;
    border-radius: 7px;
    overflow: hidden;
    background: var(--mud-palette-action-default-hover);
}

.viz-share-seg { min-width: 3px; }

.viz-empty {
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    padding: 10px 0;
}

/* A ranked row's inline bar: the table is the data, the bar is the shape of it. */
.viz-rank {
    position: relative;
    height: 6px;
    border-radius: 3px;
    background: var(--mud-palette-action-default-hover);
    overflow: hidden;
    min-width: 60px;
}

.viz-rank > span {
    display: block;
    height: 100%;
    border-radius: 3px;
}

/* KPI tile. The delta sits under the number, never beside it — beside it, a long
   number pushes the delta off the card on a phone. */
.kpi {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-height: 96px;
    justify-content: center;
}

.kpi-label {
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    display: flex;
    align-items: center;
    gap: 6px;
}

.kpi-value {
    font-size: 24px;
    font-weight: 700;
    line-height: 1.2;
    color: var(--mud-palette-text-primary);
}

.kpi-delta { font-size: 12px; display: flex; align-items: center; gap: 3px; }
.kpi-up { color: var(--mud-palette-success); }
.kpi-down { color: var(--mud-palette-error); }
.kpi-flat { color: var(--mud-palette-text-secondary); }

@media (max-width: 599.98px) {
    .kpi { min-height: 78px; }
    .kpi-value { font-size: 19px; }
}

/* ============================================================================
   Printing a report
   The browser's own print dialogue is also how a PDF gets made, and it is the
   one path where Arabic shaping is already solved. So the page prints the
   report and nothing else: no nav, no filters, no buttons.
   ============================================================================ */

@media print {
    body:has(#report-print) .mud-appbar,
    body:has(#report-print) .mud-drawer,
    body:has(#report-print) .app-bottom-nav,
    body:has(#report-print) .mud-snackbar-provider {
        display: none !important;
    }

    /* Everything on the page is hidden, then the report alone is brought back —
       a print stylesheet that lists what to hide always misses something. */
    body:has(#report-print) .app-content-wrap > * { display: none !important; }
    body:has(#report-print) #report-print,
    body:has(#report-print) #report-print * { display: revert !important; }
    body:has(#report-print) #report-print { display: block !important; }

    body:has(#report-print) .app-content-wrap { padding: 0 !important; }
    #report-print .app-card { box-shadow: none !important; border: none !important; padding: 0 !important; }
    #report-print .rep-table { font-size: 11px; }
    /* A long report keeps its header on every page. */
    #report-print thead { display: table-header-group; }
    #report-print tr { break-inside: avoid; }
}

/* ============================================================================
   The assistant
   A chat, laid out so the conversation owns the screen: the thread scrolls, the
   composer stays put, and the page itself never scrolls.
   ============================================================================ */

.ai-shell {
    display: flex;
    gap: 16px;
    /* Fill what is left under the app bar. 100dvh, because on a phone 100vh is
       measured against a browser chrome that is not there. */
    height: calc(100dvh - 140px);
    min-height: 420px;
}

.ai-rail {
    width: 260px;
    flex: 0 0 260px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
    border: 1px solid var(--mud-palette-divider);
    border-radius: 10px;
    background: var(--mud-palette-surface);
    overflow: hidden;
}

.ai-threads { overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }

.ai-thread {
    position: relative;
    padding: 8px 10px;
    border-radius: 8px;
    cursor: pointer;
    font-size: 13px;
}

.ai-thread:hover { background: var(--mud-palette-action-default-hover); }
.ai-thread-active { background: var(--mud-palette-primary-hover); }
.ai-thread-title { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ai-thread-date { font-size: 11px; color: var(--mud-palette-text-secondary); }

/* The delete button stays out of the way until the row is pointed at. */
.ai-thread-delete { position: absolute; inset-inline-end: 4px; top: 6px; opacity: 0; }
.ai-thread:hover .ai-thread-delete { opacity: .75; }

.ai-main {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-width: 0;
    border: 1px solid var(--mud-palette-divider);
    border-radius: 10px;
    background: var(--mud-palette-surface);
    overflow: hidden;
}

.ai-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--mud-palette-divider);
}

.ai-title { font-weight: 700; }
.ai-sub { font-size: 12px; color: var(--mud-palette-text-secondary); }
.ai-rail-toggle { display: none; }

.ai-thread-body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.ai-msg { display: flex; flex-direction: column; max-width: 86%; }
.ai-msg-user { align-self: flex-end; align-items: flex-end; }
.ai-msg-bot { align-self: flex-start; align-items: flex-start; }

.ai-bubble {
    padding: 10px 14px;
    border-radius: 14px;
    line-height: 1.6;
    overflow-wrap: anywhere;
}

.ai-msg-user .ai-bubble {
    background: var(--mud-palette-primary);
    color: var(--mud-palette-primary-text);
    border-end-end-radius: 4px;
}

.ai-msg-bot .ai-bubble {
    background: var(--mud-palette-action-default-hover);
    color: var(--mud-palette-text-primary);
    border-end-start-radius: 4px;
}

/* Markdown coming out of the model: enough styling to be readable, not enough to
   fight the rest of the app. */
.ai-bubble p { margin: 0 0 8px; }
.ai-bubble p:last-child { margin-bottom: 0; }
.ai-bubble ul, .ai-bubble ol { margin: 4px 0 8px; padding-inline-start: 22px; }
.ai-bubble li { margin: 2px 0; }
.ai-bubble h1, .ai-bubble h2, .ai-bubble h3 { font-size: 15px; font-weight: 700; margin: 10px 0 6px; }
.ai-bubble code {
    font-family: Consolas, monospace; font-size: 12px;
    background: var(--mud-palette-background); padding: 1px 5px; border-radius: 4px;
}
.ai-bubble table { border-collapse: collapse; margin: 8px 0; font-size: 13px; width: 100%; }
.ai-bubble th, .ai-bubble td {
    border: 1px solid var(--mud-palette-divider); padding: 5px 8px; text-align: start;
}
.ai-bubble th { background: var(--mud-palette-background); font-weight: 600; }
/* Figures inside an answer stay Latin and left-to-right even on an Arabic page. */
.ai-bubble td:not(:first-child) { font-variant-numeric: tabular-nums; }

/* Where the answer came from. Small, quiet, and always there. */
.ai-sources {
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px;
    margin-top: 5px; padding-inline: 4px;
    font-size: 11px; color: var(--mud-palette-text-secondary);
}
.ai-source-failed { color: var(--mud-palette-error); }

/* Follow-ups. The assistant knows what it could answer next better than the user
   does, so it offers; the chip simply asks the question again. */
.ai-suggests { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; padding-inline: 4px; }
.ai-suggest {
    border: 1px dashed var(--mud-palette-divider);
    background: transparent;
    color: var(--mud-palette-text-secondary);
    border-radius: 16px; padding: 6px 12px; font: inherit; font-size: 12px;
    cursor: pointer; min-height: 34px; text-align: start;
}
.ai-suggest:hover { border-style: solid; border-color: var(--mud-palette-primary); color: var(--mud-palette-primary); }

/* An answer the assistant could not give. Marked, not hidden. */
.ai-bubble-puzzled { border-inline-start: 3px solid var(--mud-palette-warning); }

.ai-welcome { margin: auto; text-align: center; max-width: 620px; display: grid; gap: 10px; }
.ai-welcome-title { font-size: 18px; font-weight: 700; }
.ai-welcome-text { color: var(--mud-palette-text-secondary); font-size: 13px; }

.ai-starters { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 8px; }

.ai-starter {
    border: 1px solid var(--mud-palette-divider);
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    border-radius: 18px;
    padding: 7px 14px;
    font: inherit;
    font-size: 13px;
    cursor: pointer;
    /* 44px of touch target even though the text is small. */
    min-height: 40px;
}
.ai-starter:hover { border-color: var(--mud-palette-primary); color: var(--mud-palette-primary); }

.ai-tools { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 14px; font-size: 11px; }
.ai-tool-chip {
    border: 1px solid var(--mud-palette-divider); border-radius: 12px; padding: 2px 9px;
    color: var(--mud-palette-text-secondary);
}

.ai-composer {
    display: flex; align-items: flex-end; gap: 10px;
    padding: 10px 14px; border-top: 1px solid var(--mud-palette-divider);
}
.ai-composer .mud-input-control { flex: 1 1 auto; }

.ai-disclaimer {
    padding: 0 14px 8px; font-size: 11px; color: var(--mud-palette-text-secondary); text-align: center;
}

/* Three dots while it works. The only animation in the app, and it earns its place:
   a question can take several seconds of looking things up. */
.ai-typing { display: flex; gap: 4px; align-items: center; padding: 14px; }
.ai-typing span {
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--mud-palette-text-secondary);
    animation: ai-blink 1.4s infinite both;
}
.ai-typing span:nth-child(2) { animation-delay: .2s; }
.ai-typing span:nth-child(3) { animation-delay: .4s; }

@keyframes ai-blink {
    0%, 80%, 100% { opacity: .25; }
    40% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .ai-typing span { animation: none; opacity: .6; }
}

@media (max-width: 959.98px) {
    .ai-shell { height: calc(100dvh - 190px); }
    .ai-rail-toggle { display: inline-flex; }
    .ai-rail {
        position: fixed;
        inset-block: 0;
        inset-inline-start: 0;
        z-index: 1300;
        width: 84vw; max-width: 320px;
        transform: translateX(-110%);
        transition: transform .2s ease;
        border-radius: 0;
    }
    html[dir="rtl"] .ai-rail { transform: translateX(110%); }
    .ai-rail-open { transform: none !important; }
    .ai-msg { max-width: 94%; }
}

/* ============================================================================
   Shelf labels
   One label per page of the roll, at the size in print settings. Every size in a
   label is in mm and pt, never px, so the label on paper is the label in the
   settings. Laid out in BarcodeLabel.razor with the desktop's proportions.
   ============================================================================ */

.bc-label {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: #fff;
    color: #000;
    font-family: Arial, "Tahoma", sans-serif;
    text-align: center;
}
/* One line each, cut with an ellipsis rather than wrapped — the desktop's NoWrap +
   EllipsisCharacter. A wrapped item name would push the price off the label. */
.bc-company, .bc-digits, .bc-item, .bc-price {
    flex: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.bc-digits, .bc-price { font-weight: 700; }
.bc-digits { font-variant-numeric: tabular-nums; letter-spacing: .02em; }
.bc-bars { flex: none; }
.bc-bars .code128 { display: block; width: 100%; height: 100%; }

/* On screen the roll is never shown: the preview is the one to look at. */
.lbl-roll { display: none; }

.lbl-grid { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 16px; }
@media (max-width: 900px) { .lbl-grid { grid-template-columns: 1fr; } }

.lbl-preview {
    display: flex; justify-content: center; align-items: center;
    min-height: 140px; padding: 18px;
    background: repeating-linear-gradient(45deg, rgba(0,0,0,.03) 0 8px, transparent 8px 16px);
    border-radius: 8px;
}
/* A 40 mm label is about 150 px on a screen — shown larger so it can be checked, and
   outlined so its edge is visible against the page. */
.lbl-preview .bc-label { zoom: 1.8; outline: 1px dashed rgba(0,0,0,.35); }
.lbl-mono, .lbl-mono input { font-family: "Consolas", "Courier New", monospace; }

@media print {
    body:has(#label-print) .mud-appbar,
    body:has(#label-print) .mud-drawer,
    body:has(#label-print) .mud-drawer-overlay,
    body:has(#label-print) .app-bottom-nav,
    body:has(#label-print) .mud-snackbar-provider {
        display: none !important;
    }
    body:has(#label-print) .app-content-wrap > *:not(#label-print) { display: none !important; }

    /* The main content is pushed down for the app bar and across for the drawer. On an
       A4 report that is a blank strip; on a label roll it moves every label off its
       sticker. So every offset between the page edge and the first label is zeroed. */
    body:has(#label-print),
    body:has(#label-print) .mud-layout,
    body:has(#label-print) .mud-main-content,
    body:has(#label-print) .app-content,
    body:has(#label-print) .app-content-wrap {
        margin: 0 !important;
        padding: 0 !important;
        min-height: 0 !important;
        background: #fff !important;
    }

    #label-print { display: block !important; }
    #label-print .bc-label { page: label-roll; break-after: page; }
    #label-print .bc-label:last-child { break-after: auto; }
}

/* ============================================================================
   Treasury statement
   The البيان is the widest thing on the row and the one people read, so it gets the
   room and may wrap; the numbers stay on one line.
   ============================================================================ */
.trs-statement { min-width: 280px; white-space: normal; line-height: 1.5; }

/* The desktop's footer: opening, in, out, closing — and the net in words. */
.trs-totals {
    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px 16px;
    padding: 12px 16px; border: 1px solid var(--mud-palette-divider); border-radius: 8px;
}
.trs-totals > div { display: flex; flex-direction: column; gap: 2px; }
.trs-totals > div > span { font-size: 12px; color: var(--mud-palette-text-secondary); }
.trs-totals > div > b { font-size: 16px; font-variant-numeric: tabular-nums; }
.trs-totals .in b { color: var(--mud-palette-success); }
.trs-totals .out b { color: var(--mud-palette-error); }
.trs-totals .net b { font-size: 18px; color: var(--mud-palette-primary); }
.trs-totals .words, .trs-totals .count { grid-column: 1 / -1; font-size: 13px; }
.trs-totals .words { font-weight: 600; }
.trs-totals .count { color: var(--mud-palette-text-secondary); font-size: 12px; }
@media (max-width: 700px) { .trs-totals { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* The shop's logo on the company screen — shown on a neutral square, as it prints. */
.company-logo-box { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
    min-height: 120px; padding: 12px; border: 1px dashed var(--mud-palette-divider); border-radius: 10px;
    background: #fff; color: #6b7280; }
.company-logo-box img { max-width: 100%; max-height: 110px; object-fit: contain; }

/* A5 invoice: the same document, set smaller so the nine columns still fit 148 mm. */
@page a5doc { size: A5; margin: 6mm; }
.tax-invoice.paper-a5 { page: a5doc; max-width: 148mm; padding: 9mm 7mm; font-size: 9.5px; line-height: 1.35; }
.tax-invoice.paper-a5 .ti-party .ti-name { font-size: 11px; }
.tax-invoice.paper-a5 .ti-title-ar { font-size: 15px; }
.tax-invoice.paper-a5 .ti-title-en { font-size: 11px; }
.tax-invoice.paper-a5 .ti-logo { width: 15mm; }
.tax-invoice.paper-a5 .ti-barcode .code128 { width: 40mm; height: 8mm; }
.tax-invoice.paper-a5 .ti-meta { gap: 6px; margin: 8px 0; }
.tax-invoice.paper-a5 .ti-meta th, .tax-invoice.paper-a5 .ti-meta td { padding: 2px 4px; }
.tax-invoice.paper-a5 .ti-lines th, .tax-invoice.paper-a5 .ti-lines td { padding: 3px 3px; }
.tax-invoice.paper-a5 .ti-lines thead th { font-size: 8px; }
.tax-invoice.paper-a5 .ti-small { font-size: 8px; }
.tax-invoice.paper-a5 .ti-totals { max-width: 250px; }
.tax-invoice.paper-a5 .ti-totals th, .tax-invoice.paper-a5 .ti-totals td { padding: 3px 5px; }
.tax-invoice.paper-a5 .ti-totals th span { font-size: 8px; }
.tax-invoice.paper-a5 .ti-grand th, .tax-invoice.paper-a5 .ti-grand td { font-size: 11px; }
.ti-logo { object-fit: contain; max-height: 22mm; }
/* The paper the print button uses, beside its label. */
.print-paper-tag { margin-inline-start: 6px; font-size: .75em; opacity: .75; font-weight: 400; }

/* Assistant: the buttons under an answer that open its screen or report. */
.ai-actions { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 2px; max-width: 100%; }
.ai-actions .mud-button-root { text-transform: none; font-weight: 600; }
.ai-bubble ol { padding-inline-start: 1.4em; margin: .3em 0; }
.ai-bubble ol li { margin: .15em 0; }
.ai-bubble h3 { font-size: 1.02rem; margin: 0 0 .35em; color: var(--mud-palette-primary); }

/* ============================================================================
   The dashboard's showroom look (`.dash3d`)
   Depth is built from three things only: light (gradients and a highlight on the
   top edge), shadow (several soft layers rather than one hard one) and a real
   perspective transform on the tiles. Everything is scoped under .dash3d so no
   other screen inherits it, and everything reads the MudBlazor palette, so dark
   mode is the same design re-lit rather than a second design.
   ============================================================================ */

.dash3d {
    --d3-navy: #1C3A62;
    --d3-gold: #F8B214;
    --d3-teal: #1F6B82;
    --d3-shadow: 16, 32, 58;               /* the colour shadows are cast in */
    --d3-edge: rgba(255, 255, 255, .85);   /* light catching a top edge */
    --d3-radius: 18px;
    position: relative;
    isolation: isolate;
}

.dash3d.dash3d-dark {
    --d3-shadow: 0, 0, 0;
    --d3-edge: rgba(255, 255, 255, .08);
}

/* The room the panels stand in: two faint lamps, gold and teal. */
.dash3d::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    border-radius: 28px;
    background:
        radial-gradient(60% 420px at 100% 0%, color-mix(in srgb, var(--d3-gold) 11%, transparent), transparent 70%),
        radial-gradient(55% 520px at 0% 38%, color-mix(in srgb, var(--d3-teal) 12%, transparent), transparent 70%);
}

/* ----- Tilt --------------------------------------------------------------
   app.js writes --rx / --ry (degrees) and --mx / --my (where the pointer is) on
   the outer element; the inner one leans. With no script, or on a touch screen,
   the variables are simply never set and the panel stands straight. */
.d3-tilt { perspective: 1100px; }

.d3-tilt-body {
    transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
    transform-style: preserve-3d;
    transition: transform 220ms cubic-bezier(.2, .8, .2, 1), box-shadow 220ms ease;
    will-change: transform;
}

/* ----- Hero -------------------------------------------------------------- */
.d3-hero { margin-bottom: 16px; }

.d3-hero-body {
    position: relative;
    display: flex;
    align-items: center;
    gap: 24px;
    padding: 26px 30px;
    border-radius: 24px;
    color: #fff;
    min-height: 210px;
    box-shadow:
        0 2px 0 rgba(255, 255, 255, .16) inset,
        0 6px 0 0 #0C1B30,
        0 34px 50px -26px rgba(var(--d3-shadow), .75),
        0 14px 24px -14px rgba(var(--d3-shadow), .45);
}

/* The painted surface is its own layer: clipping the body itself would flatten the
   3D space the children float in. */
.d3-hero-bg {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    overflow: hidden;
    background:
        radial-gradient(420px 260px at 88% 18%, rgba(248, 178, 20, .30), transparent 70%),
        radial-gradient(520px 320px at 8% 120%, rgba(63, 163, 189, .38), transparent 70%),
        linear-gradient(135deg, #0D1F3A 0%, #1C3A62 46%, #1F6B82 100%);
}

/* A floor running away from the viewer under the chart. */
.d3-hero-bg::before {
    content: '';
    position: absolute;
    inset-inline: -20%;
    bottom: -42%;
    height: 95%;
    background-image:
        linear-gradient(rgba(255, 255, 255, .09) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, .09) 1px, transparent 1px);
    background-size: 44px 44px;
    transform: perspective(520px) rotateX(64deg);
    transform-origin: 50% 0;
    mask-image: linear-gradient(to bottom, transparent 0%, #000 45%, transparent 100%);
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 45%, transparent 100%);
}

/* The gold hairline along the top edge. */
.d3-hero-bg::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    top: 0;
    height: 3px;
    background: linear-gradient(90deg, transparent, var(--d3-gold) 30%, #FFE08A 50%, var(--d3-gold) 70%, transparent);
}

.d3-hero-copy {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1 1 320px;
    min-width: 0;
}

.d3-hero-eyebrow { font-size: 13px; color: rgba(255, 255, 255, .78); }

.d3-hero-title {
    margin: 0;
    font-size: 26px;
    font-weight: 700;
    line-height: 1.25;
    color: #fff;
}

.d3-hero-figure { display: flex; flex-direction: column; gap: 2px; margin-top: 10px; }

.d3-hero-label {
    font-size: 12px;
    letter-spacing: .04em;
    color: #FFD668;
    font-weight: 600;
}

.d3-hero-value {
    font-size: 40px;
    font-weight: 700;
    line-height: 1.12;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
    background: linear-gradient(180deg, #FFFFFF 0%, #FFE9AE 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    filter: drop-shadow(0 3px 6px rgba(0, 0, 0, .35));
}

.d3-hero-delta {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    align-self: flex-start;
    margin-top: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    background: rgba(255, 255, 255, .12);
    box-shadow: 0 1px 0 rgba(255, 255, 255, .18) inset;
    color: rgba(255, 255, 255, .82);
}

/* On navy the theme's success and error reds sit too dark: these are the same
   meanings, lifted to stay readable. */
.d3-hero-delta.kpi-up { color: #6EE7A8; }
.d3-hero-delta.kpi-down { color: #FFA4A4; }
.d3-hero-delta .mud-icon-root { font-size: 15px; }

.d3-hero-range {
    margin-top: 8px;
    font-size: 12px;
    color: rgba(255, 255, 255, .66);
    font-variant-numeric: tabular-nums;
    align-self: flex-start;
}

.d3-hero-art {
    position: relative;
    flex: 0 1 460px;
    min-width: 0;
    filter: drop-shadow(0 16px 14px rgba(0, 0, 0, .38));
}

.d3-hero-art svg text { font-weight: 700; }

.d3-hero .d3-hero-refresh {
    position: absolute;
    top: 16px;
    inset-inline-end: 18px;
    color: #fff;
    border-color: rgba(255, 255, 255, .34);
    background: rgba(255, 255, 255, .08);
    border-radius: 999px;
    text-transform: none;
}

.d3-hero .d3-hero-refresh:hover { background: rgba(255, 255, 255, .16); border-color: var(--d3-gold); }
.d3-hero .d3-hero-refresh.mud-button-disabled,
.d3-hero .d3-hero-refresh:disabled { color: rgba(255, 255, 255, .45) !important; }

/* ----- Period bar --------------------------------------------------------- */
.dash3d .d3-filter {
    border-radius: 16px;
    border: 1px solid color-mix(in srgb, var(--mud-palette-text-primary) 8%, transparent);
    background: color-mix(in srgb, var(--mud-palette-surface) 86%, transparent);
    box-shadow:
        0 1px 0 var(--d3-edge) inset,
        0 12px 22px -16px rgba(var(--d3-shadow), .35);
}

/* ----- Tiles -------------------------------------------------------------- */
/* Columns follow the room the dashboard actually has (the side menu may be open or
   shut), not the window: hence a container, not a media query. Five tiles never leave
   one stranded on a row of its own — where they would, the first takes two places. */
.d3-grids { container-type: inline-size; }

.d3-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    margin-bottom: 20px;
}

.d3-grid:not(.d3-grid-4) > .d3-tilt:first-child { grid-column: span 2; }

@container (min-width: 640px) {
    .d3-grid:not(.d3-grid-4) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@container (min-width: 860px) {
    .d3-grid.d3-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@container (min-width: 1040px) {
    .d3-grid:not(.d3-grid-4) { grid-template-columns: repeat(5, minmax(0, 1fr)); }
    .d3-grid:not(.d3-grid-4) > .d3-tilt:first-child { grid-column: auto; }
}

.d3-acc-navy    { --acc: #3D6CA8; --acc2: #1C3A62; --acc-ink: #fff; }
.d3-acc-gold    { --acc: #FFD15C; --acc2: #DE9800; --acc-ink: #3A2600; }
.d3-acc-teal    { --acc: #35A0BE; --acc2: #1F6B82; --acc-ink: #fff; }
.d3-acc-emerald { --acc: #3FD69B; --acc2: #0E9466; --acc-ink: #fff; }
.d3-acc-plum    { --acc: #A68BF0; --acc2: #5B3FB8; --acc-ink: #fff; }
.d3-acc-ruby    { --acc: #F98080; --acc2: #C22F2F; --acc-ink: #fff; }

.dash3d-dark .d3-acc-navy { --acc: #7FB0EA; --acc2: #2E5C99; }

.d3-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-height: 132px;
    height: 100%;
    padding: 16px 16px 18px;
    border-radius: var(--d3-radius);
    border: 1px solid color-mix(in srgb, var(--acc2) 22%, transparent);
    background: linear-gradient(155deg,
        color-mix(in srgb, #fff 5%, var(--mud-palette-surface)) 0%,
        color-mix(in srgb, var(--acc) 10%, var(--mud-palette-surface)) 100%);
    /* A slab with thickness: the solid band under the face is its edge. */
    box-shadow:
        0 1px 0 var(--d3-edge) inset,
        0 5px 0 0 color-mix(in srgb, var(--acc2) 72%, var(--mud-palette-surface)),
        0 24px 30px -18px color-mix(in srgb, var(--acc2) 60%, transparent),
        0 12px 18px -12px rgba(var(--d3-shadow), .30);
}

/* The light that follows the pointer across the face. It is the tile's own colour and
   faint: a white glare would wash the grey caption out in dark mode and vanish on a
   white tile in light mode. */
.d3-tile::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    opacity: 0;
    transition: opacity 220ms ease;
    background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 0%),
        color-mix(in srgb, var(--acc) 24%, transparent), transparent 70%);
}

.d3-tile-head { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.d3-tile .kpi-label { font-size: 12.5px; font-weight: 600; }
.d3-tile .kpi-value { font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.d3-tile .kpi-delta { margin-top: auto; }

.d3-tile-link { cursor: pointer; }
.d3-tile-link:focus-visible { outline: 2px solid var(--acc2); outline-offset: 3px; }

/* The cut stone the icon sits in. */
.d3-gem {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border-radius: 13px;
    color: var(--acc-ink);
    background: linear-gradient(145deg, var(--acc) 0%, var(--acc2) 100%);
    box-shadow:
        0 1px 0 rgba(255, 255, 255, .55) inset,
        0 -4px 7px rgba(0, 0, 0, .22) inset,
        0 10px 14px -8px var(--acc2);
}

.d3-gem .mud-icon-root { font-size: 22px; }

.d3-tile > *, .d3-tile-head > * { transition: transform 220ms cubic-bezier(.2, .8, .2, 1); }

@media (hover: hover) and (pointer: fine) {
    .d3-tilt:hover > .d3-tile {
        box-shadow:
            0 1px 0 var(--d3-edge) inset,
            0 5px 0 0 color-mix(in srgb, var(--acc2) 72%, var(--mud-palette-surface)),
            0 38px 40px -22px color-mix(in srgb, var(--acc2) 70%, transparent),
            0 20px 26px -14px rgba(var(--d3-shadow), .38);
    }
    .d3-tilt:hover > .d3-tile::before { opacity: 1; }
    /* Layers at different heights: that parallax is what reads as depth. */
    .d3-tilt:hover > .d3-tile .d3-gem { transform: translateZ(38px); }
    .d3-tilt:hover > .d3-tile .kpi-value { transform: translateZ(26px); }
    .d3-tilt:hover > .d3-tile .kpi-label,
    .d3-tilt:hover > .d3-tile .kpi-delta { transform: translateZ(14px); }
    .d3-hero.d3-tilt:hover .d3-hero-art { transform: translateZ(46px); }
    .d3-hero.d3-tilt:hover .d3-hero-copy { transform: translateZ(22px); }
}

.d3-hero-art, .d3-hero-copy { transition: transform 260ms cubic-bezier(.2, .8, .2, 1); }

/* ----- Cards -------------------------------------------------------------- */
.dash3d .app-card {
    border-radius: var(--d3-radius);
    border: 1px solid color-mix(in srgb, var(--mud-palette-text-primary) 8%, transparent);
    background: linear-gradient(180deg,
        color-mix(in srgb, #fff 4%, var(--mud-palette-surface)) 0%,
        var(--mud-palette-surface) 60%);
    box-shadow:
        0 1px 0 var(--d3-edge) inset,
        0 2px 3px rgba(var(--d3-shadow), .05),
        0 16px 26px -16px rgba(var(--d3-shadow), .30),
        0 38px 60px -40px rgba(var(--d3-shadow), .40);
    transition: transform 240ms cubic-bezier(.2, .8, .2, 1), box-shadow 240ms ease;
}

@media (hover: hover) and (pointer: fine) {
    .dash3d .app-card:hover {
        transform: translateY(-3px);
        box-shadow:
            0 1px 0 var(--d3-edge) inset,
            0 2px 3px rgba(var(--d3-shadow), .05),
            0 24px 34px -18px rgba(var(--d3-shadow), .38),
            0 50px 70px -42px rgba(var(--d3-shadow), .50);
    }
}

.dash3d .app-card-header {
    padding: 14px 18px;
    background: linear-gradient(180deg, color-mix(in srgb, var(--d3-gold) 7%, transparent), transparent);
    flex-wrap: wrap;
    gap: 8px 0;
}

/* The header icon becomes a small navy stone with a gold rim of light. */
.dash3d .app-card-header > .mud-icon-root {
    box-sizing: content-box;
    padding: 6px;
    border-radius: 10px;
    color: #fff !important;
    background: linear-gradient(145deg, #3D6CA8, var(--d3-navy));
    box-shadow:
        0 1px 0 rgba(255, 255, 255, .45) inset,
        0 -3px 5px rgba(0, 0, 0, .25) inset,
        0 8px 12px -7px var(--d3-navy);
}

.dash3d .app-card-title { font-size: 15px; font-weight: 700; }

/* The rule under a header: gold fading out, in place of a grey line. */
.dash3d .app-card-header + .mud-divider {
    border: 0;
    height: 2px;
    background: linear-gradient(90deg, var(--d3-gold), color-mix(in srgb, var(--d3-gold) 25%, transparent) 40%, transparent 85%);
}

[dir="rtl"] .dash3d .app-card-header + .mud-divider {
    background: linear-gradient(270deg, var(--d3-gold), color-mix(in srgb, var(--d3-gold) 25%, transparent) 40%, transparent 85%);
}

.dash3d .app-table { border-radius: 12px; }

/* ----- Charts ------------------------------------------------------------- */
/* A share bar becomes a glass tube: lit along the top, shaded underneath. */
.dash3d .viz-share-track {
    position: relative;
    height: 22px;
    border-radius: 11px;
    box-shadow:
        0 2px 4px rgba(0, 0, 0, .22) inset,
        0 10px 12px -8px rgba(var(--d3-shadow), .45);
}

.dash3d .viz-share-track::after,
.dash3d .viz-rank > span::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    background: linear-gradient(180deg,
        rgba(255, 255, 255, .58) 0%, rgba(255, 255, 255, .10) 42%,
        rgba(0, 0, 0, 0) 52%, rgba(0, 0, 0, .24) 100%);
}

.dash3d .viz-rank { height: 9px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0, 0, 0, .22) inset; }
.dash3d .viz-rank > span { position: relative; border-radius: 5px; }

/* Legend chips become beads. */
.dash3d .viz-swatch {
    width: 11px;
    height: 11px;
    border-radius: 50%;
    box-shadow:
        1px 1px 2px rgba(255, 255, 255, .55) inset,
        -1px -2px 3px rgba(0, 0, 0, .30) inset;
}

/* ----- Arrival ------------------------------------------------------------
   Panels rise into place once, in order. `backwards` only: a finished animation
   must let go of `transform`, or it would pin the tilt. */
@keyframes d3-rise {
    from { opacity: 0; transform: translateY(22px) rotateX(-14deg); }
    to   { opacity: 1; transform: none; }
}

@keyframes d3-grow {
    from { transform: scaleY(0); }
    to   { transform: scaleY(1); }
}

@media (prefers-reduced-motion: no-preference) {
    .d3-hero, .d3-grid > .d3-tilt { animation: d3-rise 620ms cubic-bezier(.2, .8, .2, 1) backwards; transform-origin: 50% 100%; }
    .d3-grid > .d3-tilt:nth-child(2) { animation-delay: 70ms; }
    .d3-grid > .d3-tilt:nth-child(3) { animation-delay: 140ms; }
    .d3-grid > .d3-tilt:nth-child(4) { animation-delay: 210ms; }
    .d3-grid > .d3-tilt:nth-child(5) { animation-delay: 280ms; }
    .d3-grid.d3-grid-4 > .d3-tilt { animation-duration: 700ms; }

    /* Blocks grow out of the floor, left to right. */
    .viz-bar3d {
        transform-box: fill-box;
        transform-origin: 50% 100%;
        animation: d3-grow 700ms cubic-bezier(.2, .8, .2, 1) backwards;
        animation-delay: calc(var(--i, 0) * 22ms);
    }
}

@media (prefers-reduced-motion: reduce) {
    .d3-tilt-body { transform: none !important; transition: none; }
    .dash3d .app-card:hover { transform: none; }
}

/* ----- Phone ------------------------------------------------------------- */
@media (max-width: 599.98px) {
    .d3-hero-body { flex-direction: column; align-items: stretch; gap: 10px; padding: 20px 18px 14px; border-radius: 20px; min-height: 0; }
    .d3-hero-copy { flex: 0 0 auto; }
    .d3-hero-title { font-size: 21px; padding-inline-end: 96px; }
    .d3-hero-eyebrow { padding-inline-end: 96px; }
    .d3-hero-value { font-size: 31px; }
    .d3-hero-art { flex: 0 0 auto; }
    .d3-hero .d3-hero-refresh { top: 12px; inset-inline-end: 12px; min-width: 0; padding: 3px 12px; font-size: 12px; }

    .d3-grid { gap: 12px; margin-bottom: 16px; }
    .d3-tile { min-height: 116px; padding: 12px 12px 14px; border-radius: 16px; }
    .d3-tile-head { gap: 8px; }
    .d3-gem { width: 34px; height: 34px; border-radius: 11px; }
    .d3-gem .mud-icon-root { font-size: 18px; }
    .d3-tile .kpi-label { font-size: 12px; }

    .dash3d .app-card-header { padding: 12px 14px; }
    .dash3d .viz-share-track { height: 18px; }
}
