/* SHOWRO — Arabic RTL business UI.

   This is a working tool, not a brochure. A showroom clerk keeps it open all day and reads
   numbers off it while a customer waits, so the design is built around density, hierarchy and
   speed of scanning rather than around decoration.

   Three decisions carry the whole identity:

   1. The navigation is a dark teal column on the right. It is the one heavy element on screen,
      which fixes the page in place and lets everything else be light. It is also the only place
      the interface says "this is an application" rather than "this is a document".
   2. The work surface is a warm near-white (#F7F8F6) with white cards on top. Two greys, not one,
      so a card reads as an object without needing a heavy border.
   3. One accent — deep teal — for what is actionable and what is currently active. Green, amber
      and red stay semantic, so "this went through" never reads as branding.

   Type is IBM Plex Sans Arabic throughout: it holds its shape at 13px inside a dense grid, which
   is where this application actually lives. */

/* Self-hosted Arabic webfonts — no CDN dependency and no layout shift (ARCHITECTURE.md §H).
   Cairo and Tajawal remain in wwwroot/fonts but are no longer referenced: one family used at two
   weights reads as more deliberate than two families competing for the same headline. */
@font-face {
    font-family: 'IBM Plex Sans Arabic';
    src: url('../fonts/IBMPlexSansArabic-400.woff2') format('woff2');
    font-weight: 400;
    font-display: swap;
}

@font-face {
    font-family: 'IBM Plex Sans Arabic';
    src: url('../fonts/IBMPlexSansArabic-600.woff2') format('woff2');
    font-weight: 600;
    font-display: swap;
}

:root {
    --app-font: 'IBM Plex Sans Arabic', 'Segoe UI', Tahoma, sans-serif;
    /* Kept as a token because views reference it; it now resolves to the same family, which is
       the point — the hierarchy comes from size and weight, not from a second typeface. */
    --display-font: var(--app-font);

    /* ---- brand ---- */
    --accent: #176B63;
    --accent-dark: #155E57;
    --accent-soft: #E8F1EF;
    --accent-ink: #0F4F49;

    /* ---- the navigation column ---- */
    --sidebar-bg: #10403B;
    --sidebar-deep: #0C332F;
    --sidebar-text: #C9DEDA;
    --sidebar-dim: #7CA49E;
    --sidebar-hover: rgba(255, 255, 255, .06);
    --sidebar-line: rgba(255, 255, 255, .08);

    /* ---- text ---- */
    --ink: #1F2937;
    --ink-soft: #374151;
    --ink-muted: #6B7280;

    /* ---- surfaces and rules ---- */
    --surface: #FFFFFF;
    --canvas: #F7F8F6;
    --canvas-alt: #FAFBFA;
    --line: #E5E7EB;
    --line-soft: #F0F1F2;
    --line-strong: #D1D5DB;

    /* Semantic colours, deliberately separate from the accent. */
    --danger: #B42318;
    --danger-soft: #FEF3F2;
    --success: #067647;
    --success-soft: #ECFDF3;
    --warn: #B54708;
    --warn-soft: #FFFAEB;

    /* ---- spacing scale: everything on the page is a multiple of these ---- */
    --s1: 4px;
    --s2: 8px;
    --s3: 12px;
    --s4: 16px;
    --s5: 20px;
    --s6: 24px;
    --s7: 32px;

    /* ---- type scale ---- */
    --t-xs: 11px;
    --t-sm: 12px;
    --t-base: 13.5px;
    --t-md: 15px;
    --t-lg: 18px;
    --t-xl: 22px;
    --t-2xl: 28px;

    --shadow-sm: 0 1px 2px rgba(16, 24, 40, .05);
    --shadow: 0 1px 3px rgba(16, 24, 40, .06), 0 8px 24px rgba(16, 24, 40, .06);
    --shadow-lg: 0 16px 40px rgba(16, 24, 40, .14);

    --radius: 8px;
    --radius-sm: 6px;
    --radius-lg: 12px;

    --sidebar-width: 260px;
    --sidebar-rail: 68px;
    --topbar-height: 58px;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: var(--app-font);
    background: var(--canvas);
    color: var(--ink);
    font-size: 14px;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
}

/* Western digits inside Arabic text — the standard on Egyptian commercial documents. */
.kpi-value, code, .org-item-name, input[dir="ltr"] {
    font-variant-numeric: lining-nums tabular-nums;
}

/* Keyboard focus must always be visible: this application is driven at speed, often by someone
   who never takes their hand off the keyboard between lines. */
:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* ==========================================================================
   Application shell
   ========================================================================== */

.app-shell {
    display: flex;
    min-height: 100vh;
}

/* The sidebar is the first child of an RTL flex row, so it sits on the right without any
   positioning trickery — and it stays put while the work area scrolls under it. */
.app-sidebar {
    width: var(--sidebar-width);
    flex-shrink: 0;
    background: var(--sidebar-bg);
    color: var(--sidebar-text);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    z-index: 30;
    transition: width .16s ease;
}

/* ---- brand ---- */

.brand {
    display: flex;
    align-items: center;
    gap: var(--s3);
    height: var(--topbar-height);
    flex-shrink: 0;
    padding: 0 var(--s5);
    border-bottom: 1px solid var(--sidebar-line);
    text-decoration: none;
    color: inherit;
    overflow: hidden;
}

/* A wordmark, not an image: it scales, it prints, and there is no asset to go missing. */
.brand-mark {
    font-size: var(--t-lg);
    font-weight: 600;
    letter-spacing: 2px;
    direction: ltr;
    color: var(--accent-dark);
    white-space: nowrap;
}

.app-sidebar .brand-mark {
    color: #FFFFFF;
}

.brand-tagline {
    font-size: var(--t-sm);
    color: var(--ink-muted);
}

/* The column is narrow and the wordmark says enough; the tagline belongs on the sign-in card. */
.app-sidebar .brand-tagline {
    display: none;
}

/* ---- menu ---- */

.nav-menu {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: var(--s3) var(--s3) var(--s5);
    display: flex;
    flex-direction: column;
    gap: var(--s1);
    /* A thin, dark scrollbar: the menu is long, but the bar should not become a design element. */
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, .16) transparent;
}

.nav-menu::-webkit-scrollbar {
    width: 6px;
}

.nav-menu::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, .16);
    border-radius: 3px;
}

/* Named groups, because a flat list of twenty destinations is a list nobody reads — they hunt
   through it. The heading tells you which third of the menu to look in. */
.nav-group + .nav-group {
    margin-top: var(--s4);
}

.nav-group-label {
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: .4px;
    color: var(--sidebar-dim);
    padding: 0 var(--s3) var(--s2);
}

.nav-item {
    display: flex;
    align-items: center;
    gap: var(--s3);
    padding: 7px var(--s3);
    border-radius: var(--radius-sm);
    color: var(--sidebar-text);
    text-decoration: none;
    font-size: var(--t-base);
    white-space: nowrap;
    transition: background .12s, color .12s;
}

.nav-item:hover {
    background: var(--sidebar-hover);
    color: #FFFFFF;
}

/* Active is a filled block, not a tint: at a glance you should know where you are without
   comparing two shades of the same colour. */
.nav-item.active {
    background: var(--accent);
    color: #FFFFFF;
    font-weight: 600;
}

.nav-item.disabled {
    color: var(--sidebar-dim);
    opacity: .5;
    pointer-events: none;
}

.nav-icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    color: var(--sidebar-dim);
    transition: color .12s;
}

.nav-item:hover .nav-icon,
.nav-item.active .nav-icon {
    color: currentColor;
}

.nav-text {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---- collapsed rail ----

   Collapsing is for the screens where the work is wide — a sales order with ten line items, an
   import preview — not a decoration. The labels go, the icons and the active marker stay. */

/* The icon-rail is a DESKTOP affordance only. On a small screen the sidebar is an off-canvas
   drawer instead (see the max-width: 900px block), so these rail rules must not reach it. */
@media (min-width: 901px) {
    .nav-collapsed .app-sidebar {
        width: var(--sidebar-rail);
    }

    .nav-collapsed .nav-text,
    .nav-collapsed .nav-group-label,
    .nav-collapsed .brand-mark {
        display: none;
    }

    .nav-collapsed .brand,
    .nav-collapsed .nav-item {
        justify-content: center;
        padding-left: 0;
        padding-right: 0;
    }

    .nav-collapsed .nav-group + .nav-group {
        margin-top: var(--s3);
        padding-top: var(--s3);
        border-top: 1px solid var(--sidebar-line);
    }
}

/* ---- the person, parked at the bottom of the column ---- */

.sidebar-foot {
    flex-shrink: 0;
    border-top: 1px solid var(--sidebar-line);
    padding: var(--s3);
    display: flex;
    align-items: center;
    gap: var(--s3);
    background: var(--sidebar-deep);
}

.sidebar-user {
    min-width: 0;
    flex: 1;
    display: flex;
    flex-direction: column;
    line-height: 1.35;
}

.user-name {
    color: #FFFFFF;
    font-size: var(--t-base);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.user-org {
    color: var(--sidebar-dim);
    font-size: var(--t-xs);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Initials rather than a photograph: there are no avatars in this system and a grey silhouette
   is worse than nothing. */
.avatar {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--accent);
    color: #FFFFFF;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--t-sm);
    font-weight: 600;
}

.btn-signout {
    background: none;
    border: 0;
    padding: var(--s2);
    color: var(--sidebar-dim);
    cursor: pointer;
    display: flex;
    border-radius: var(--radius-sm);
}

.btn-signout:hover {
    color: #FFFFFF;
    background: var(--sidebar-hover);
}

@media (min-width: 901px) {
    .nav-collapsed .sidebar-user,
    .nav-collapsed .btn-signout {
        display: none;
    }

    .nav-collapsed .sidebar-foot {
        justify-content: center;
    }
}

/* The drawer backdrop exists only on small screens; on desktop it never renders. */
.nav-scrim {
    display: none;
}

/* ==========================================================================
   Topbar — a rail for finding things, not a second navigation
   ========================================================================== */

.app-main {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.app-topbar {
    height: var(--topbar-height);
    flex-shrink: 0;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: center;
    gap: var(--s4);
    padding: 0 var(--s6);
    position: sticky;
    top: 0;
    z-index: 20;
}

.nav-toggle {
    background: none;
    border: 0;
    padding: var(--s2);
    margin-right: calc(var(--s3) * -1);
    color: var(--ink-muted);
    cursor: pointer;
    display: flex;
    border-radius: var(--radius-sm);
}

.nav-toggle:hover {
    background: var(--canvas);
    color: var(--ink);
}

/* Search is the fastest route to a product, so it gets the middle of the bar and a real width. */
.topbar-search {
    position: relative;
    flex: 1;
    max-width: 460px;
}

.topbar-search .search-icon {
    position: absolute;
    top: 50%;
    right: var(--s3);
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    color: var(--ink-muted);
    pointer-events: none;
}

.topbar-search input {
    width: 100%;
    height: 36px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--canvas);
    padding: 0 var(--s7) 0 var(--s3);
    font-family: inherit;
    font-size: var(--t-base);
    color: var(--ink);
}

.topbar-search input::placeholder {
    color: var(--ink-muted);
}

.topbar-search input:focus {
    outline: none;
    background: var(--surface);
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.topbar-right {
    display: flex;
    align-items: center;
    gap: var(--s3);
    margin-right: auto;
}

.badge-admin {
    background: var(--accent-soft);
    border: 1px solid transparent;
    color: var(--accent-ink);
    border-radius: 999px;
    padding: 2px 10px;
    font-size: var(--t-xs);
    font-weight: 600;
    white-space: nowrap;
}

.app-content {
    padding: var(--s6);
    flex: 1;
    min-width: 0;
}

/* ==========================================================================
   Page furniture
   ========================================================================== */

.page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--s4);
    margin-bottom: var(--s5);
    flex-wrap: wrap;
}

.page-title {
    font-size: var(--t-xl);
    font-weight: 600;
    letter-spacing: -.2px;
    margin: 0;
    line-height: 1.3;
}

.page-subtitle {
    margin: 2px 0 0;
    color: var(--ink-muted);
    font-size: var(--t-base);
}

.scope-chip {
    background: var(--surface);
    border: 1px solid var(--line);
    color: var(--ink-soft);
    border-radius: 999px;
    padding: 4px var(--s3);
    font-size: var(--t-sm);
    white-space: nowrap;
}

.section-heading {
    font-size: var(--t-sm);
    font-weight: 600;
    letter-spacing: .3px;
    color: var(--ink-muted);
    margin: var(--s6) 0 var(--s3);
}

.section-heading:first-of-type {
    margin-top: 0;
}

/* A section heading that carries a link to the right of it (e.g. "position → full report"). */
.section-head-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s3);
    flex-wrap: wrap;
}

.section-head-row .section-heading {
    margin-bottom: var(--s3);
}

/* ---- the card, which is most of the interface ---- */

.panel {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 0;
    box-shadow: var(--shadow-sm);
}

.panel-title {
    font-size: var(--t-md);
    font-weight: 600;
    margin: 0;
    padding: var(--s4) var(--s5);
    border-bottom: 1px solid var(--line-soft);
}

.panel-body {
    margin: 0;
    padding: var(--s5);
    color: var(--ink-soft);
    font-size: var(--t-base);
}

/* ---- KPI tiles ---- */

.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--s4);
    margin-bottom: var(--s6);
}

.kpi-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: var(--s5);
    display: flex;
    flex-direction: column;
    gap: var(--s1);
}

.kpi-label {
    color: var(--ink-muted);
    font-size: var(--t-sm);
    font-weight: 600;
}

.kpi-value {
    font-size: var(--t-2xl);
    font-weight: 600;
    color: var(--ink);
    line-height: 1.2;
}

/* On a phone the auto-fit grid drops to one very tall card per row and buries the content below.
   Two compact tiles per row keep the snapshot readable without a long scroll. */
@media (max-width: 560px) {
    .kpi-grid {
        grid-template-columns: 1fr 1fr;
        gap: var(--s3);
    }

    .kpi-card {
        padding: var(--s4);
    }

    .kpi-value {
        font-size: var(--t-xl);
    }
}

/* The unit or the qualifier under the figure — currency, margin — never louder than the number. */
.kpi-note {
    font-size: var(--t-xs);
    color: var(--ink-muted);
}

/* A tile that answers its own question: click it and the report behind the number opens. */
.kpi-link {
    text-decoration: none;
    color: inherit;
}

.kpi-link:hover {
    border-color: var(--accent);
}

/* Reserved for tiles that only appear when there IS something to do, so the colour keeps meaning
   something. A permanent amber tile is a tile people stop seeing. */
.kpi-warn {
    background: var(--warn-soft);
    border-color: #F5D9A8;
}

/* ---- empty states ----

   An empty list is a normal state in a system that starts with no data, so it is designed rather
   than left as a bare sentence in the middle of a box. */
.empty-state {
    text-align: center;
    color: var(--ink-muted);
    padding: var(--s7) var(--s5);
    font-size: var(--t-base);
}

/* ---- initials block, for a product or partner with no image ----

   Product images are optional in this system and most rows will never have one. A generic grey
   photo icon repeated down a list is worse than no image at all: it draws the eye to the one
   thing on the row carrying no information. Initials at least identify the row. */
.monogram {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    border-radius: var(--radius-sm);
    background: var(--accent-soft);
    color: var(--accent-ink);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--t-sm);
    font-weight: 600;
    line-height: 1;
}

/* ---------- Tables (the workhorse of a business application) ---------- */

.table {
    width: 100%;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    /* Separate, not collapse: a collapsed table cannot round its own corners, and the header
       cannot stay put while the body scrolls. */
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--t-base);
    box-shadow: var(--shadow-sm);
}

/* The corners have to be drawn on the corner cells, because the radius on a table element does
   not clip the cells inside it. Logical properties keep this correct in RTL. */
.table thead th:first-child {
    border-start-start-radius: var(--radius-lg);
}

.table thead th:last-child {
    border-start-end-radius: var(--radius-lg);
}

.table tbody tr:last-child td:first-child {
    border-end-start-radius: var(--radius-lg);
}

.table tbody tr:last-child td:last-child {
    border-end-end-radius: var(--radius-lg);
}

/* A long list is read by scrolling, and a column of figures with no header above it is unreadable.
   The header parks itself directly under the topbar instead of scrolling away. */
.table thead th {
    position: sticky;
    top: var(--topbar-height);
    z-index: 5;
    background: var(--canvas-alt);
    border-bottom: 1px solid var(--line);
    color: var(--ink-muted);
    font-weight: 600;
    font-size: var(--t-sm);
    letter-spacing: .2px;
    text-align: right;
    padding: var(--s3) var(--s4);
    white-space: nowrap;
}

/* A table inside its OWN scroll box — a report grid, a document's lines, the movement ledger —
   makes that box the sticky header's scroll context, not the page. The page-topbar offset above
   (top: --topbar-height) then pushes the header DOWN into the box; being opaque and above the rows
   (z-index 5), it paints over the first data row(s) — which is exactly why those rows were present
   in the HTML but invisible on screen. Inside a scroll box the header sticks to the box's own top. */
.table-scroll .table thead th {
    top: 0;
}

.table tbody td {
    border-bottom: 1px solid var(--line-soft);
    padding: var(--s3) var(--s4);
    vertical-align: middle;
}

.table tbody tr:last-child td {
    border-bottom: none;
}

.table tbody tr:hover {
    background: var(--canvas-alt);
}

/* The first column of a list is what the row IS; everything after it describes that. */
.table tbody td:first-child {
    font-weight: 600;
}

/* Wide grids scroll inside themselves rather than pushing the page sideways. */
.table-wrap {
    overflow-x: auto;
    border-radius: var(--radius-lg);
}

/* Money and quantity columns align on the digits, which is how they get scanned. */
.table .num {
    text-align: left;
    direction: ltr;
    font-variant-numeric: lining-nums tabular-nums;
}

/* ---------- Authentication screens ---------- */

.auth-body {
    background: var(--canvas);
}

/* Two panels on a desktop, one on a phone. The grid is the whole layout: no absolute positioning,
   so the panels stay level whatever length the Arabic text runs to. */
.auth-shell {
    min-height: 100vh;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.auth-aside {
    background: linear-gradient(160deg, var(--sidebar-bg) 0%, var(--sidebar-deep) 100%);
    color: var(--sidebar-text);
    padding: var(--s7) clamp(var(--s6), 6vw, 64px);
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--s6);
}

.auth-aside-brand {
    display: flex;
    flex-direction: column;
    gap: var(--s2);
}

.auth-aside .brand-mark {
    color: #FFFFFF;
    font-size: var(--t-2xl);
    /* The body's 1.65 leading is for paragraphs; on a 28px wordmark it opens a gap wide enough
       that the name and the tagline stop reading as one block. */
    line-height: 1.2;
}

.auth-aside-tagline {
    font-size: var(--t-md);
    line-height: 1.5;
    color: var(--sidebar-text);
    max-width: 30ch;
}

.auth-points {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s3);
    max-width: 42ch;
}

.auth-points li {
    position: relative;
    padding-inline-start: var(--s5);
    font-size: var(--t-base);
    color: var(--sidebar-text);
    line-height: 1.7;
}

/* A rule rather than a bullet glyph: a disc before Arabic text sits at the wrong height in most
   of the fonts this ships with. */
.auth-points li::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    top: 0.75em;
    width: 10px;
    height: 2px;
    background: var(--accent);
    border-radius: 2px;
}

.auth-aside-foot {
    margin: 0;
    font-size: var(--t-sm);
    color: var(--sidebar-dim);
}

.auth-main {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--s7) var(--s5);
}

.auth-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    padding: clamp(var(--s6), 5vw, 40px);
    width: 100%;
    max-width: 420px;
}

/* The wordmark only appears inside the card when the brand panel is not on screen. */
.auth-brand-compact {
    display: none;
    margin-bottom: var(--s5);
    padding-bottom: var(--s5);
    border-bottom: 1px solid var(--line-soft);
}

.auth-brand-compact .brand-mark {
    font-size: var(--t-xl);
}

.auth-head {
    margin-bottom: var(--s6);
}

.auth-title {
    font-size: var(--t-xl);
    font-weight: 600;
    margin: 0 0 var(--s2);
    color: var(--ink);
}

.auth-subtitle {
    margin: 0;
    font-size: var(--t-base);
    color: var(--ink-muted);
}

.auth-form {
    display: flex;
    flex-direction: column;
    gap: var(--s5);
}

.auth-form .field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* An input with a control on its end.

   Composed as a flex row rather than an absolutely-positioned overlay: the password input is
   dir="ltr" while the page is rtl, so an overlay positioned by the wrapper's direction lands on
   the opposite side from the padding the input reserves — the button then sits on top of the
   typing. A row has no two directions to disagree about.
   
   The border moves to the wrapper so the pair still reads as one control. */
.input-affix {
    display: flex;
    align-items: stretch;
    direction: ltr;
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    overflow: hidden;
}

.input-affix:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.input-affix .form-control {
    flex: 1;
    min-width: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
}

/* The wrapper owns the focus ring now, so the input must not draw a second one inside it. */
.input-affix .form-control:focus {
    box-shadow: none;
    border-color: transparent;
    outline: none;
}

.input-affix-btn {
    flex: none;
    padding: 0 var(--s4);
    border: 0;
    border-inline-start: 1px solid var(--line);
    background: transparent;
    color: var(--ink-muted);
    font-family: inherit;
    font-size: var(--t-sm);
    font-weight: 600;
    cursor: pointer;
}

.input-affix-btn:hover {
    background: var(--canvas);
    color: var(--accent-dark);
}

/* The checkbox and its consequence, which is the part people actually need told: a remembered
   session on a showroom's shared terminal is an unlocked till. */
.remember {
    display: flex;
    align-items: flex-start;
    gap: var(--s3);
    cursor: pointer;
    margin: 0;
}

.remember .form-check-input {
    margin: 3px 0 0;
    flex: none;
}

.remember-label {
    display: block;
    font-size: var(--t-base);
    font-weight: 600;
    color: var(--ink-soft);
}

.remember-hint {
    display: block;
    font-size: var(--t-sm);
    color: var(--ink-muted);
    line-height: 1.55;
}

.btn-block {
    width: 100%;
    justify-content: center;
}

.auth-aside-action {
    margin-top: var(--s6);
    padding-top: var(--s5);
    border-top: 1px solid var(--line-soft);
}

.auth-note {
    margin: var(--s2) 0 0;
    font-size: var(--t-sm);
    color: var(--ink-muted);
    text-align: center;
}

.auth-foot {
    margin-top: var(--s6);
    text-align: center;
}

/* Below this the second column costs more than it gives: the form is what the screen is for. */
@media (max-width: 860px) {
    .auth-shell {
        grid-template-columns: 1fr;
    }

    .auth-aside {
        display: none;
    }

    .auth-brand-compact {
        display: block;
    }
}

/* ---------- Forms ---------- */

.form-label {
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--ink-soft);
    margin-bottom: var(--s1);
}

.form-control {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-size: var(--t-base);
    padding: var(--s2) var(--s3);
    color: var(--ink);
    background: var(--surface);
}

.form-control::placeholder {
    color: var(--ink-muted);
}

.form-control:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.form-control:disabled,
.form-control[readonly] {
    background: var(--canvas);
    color: var(--ink-muted);
}

.form-check-input:checked {
    background-color: var(--accent);
    border-color: var(--accent);
}

.form-check-label {
    font-size: 13.5px;
    color: var(--ink-soft);
}

.field-error,
.field-validation-error {
    color: var(--danger);
    font-size: var(--t-sm);
    font-weight: 600;
    display: block;
    margin-top: var(--s1);
}

/* Stamped by the framework on a server-side re-render. Until now the rejected field looked
   exactly like an accepted one, and the only clue was the summary at the top of the form. */
.input-validation-error {
    border-color: var(--danger);
    background: var(--danger-soft);
}

.input-validation-error:focus {
    border-color: var(--danger);
    box-shadow: 0 0 0 3px #FBD3CE;
}

/* ---------- Buttons ---------- */

.btn {
    border-radius: var(--radius);
    font-size: var(--t-base);
    font-weight: 600;
    padding: var(--s2) var(--s4);
    transition: background .12s, border-color .12s, box-shadow .12s;
}

.btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    box-shadow: var(--shadow-sm);
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active {
    background: var(--accent-dark);
    border-color: var(--accent-dark);
}

.btn-secondary {
    background: var(--surface);
    border-color: var(--line);
    color: var(--ink-soft);
}

.btn-secondary:hover,
.btn-secondary:focus,
.btn-secondary:active {
    background: var(--canvas);
    border-color: var(--line-strong);
    color: var(--ink);
}

.btn-link-plain {
    background: none;
    border: none;
    color: var(--ink-muted);
    font-size: var(--t-sm);
    font-weight: 600;
    padding: 0;
    cursor: pointer;
    text-decoration: none;
}

.btn-link-plain:hover {
    color: var(--accent-dark);
    text-decoration: underline;
}

/* ---------- Alerts ---------- */

.alert {
    border-radius: var(--radius);
    font-size: var(--t-base);
    padding: var(--s3) var(--s4);
    border-width: 1px;
    border-style: solid;
}

.alert-danger {
    background: var(--danger-soft);
    border-color: #FBD3CE;
    color: var(--danger);
}

.alert-success {
    background: var(--success-soft);
    border-color: #B9E7CD;
    color: var(--success);
}

/* ---------- Organization picker ---------- */

.org-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.org-item {
    width: 100%;
    text-align: right;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 11px 14px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

.org-item:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.org-item-name {
    font-weight: 600;
    font-size: 14px;
}

.org-item-role {
    font-size: 11.5px;
    color: var(--ink-muted);
}

/* ---------- Errors ---------- */

.error-page {
    text-align: center;
}

.error-code {
    font-size: 40px;
    font-weight: 600;
    color: var(--ink-muted);
    line-height: 1.2;
}

.error-message {
    color: var(--ink);
    margin: 6px 0 16px;
    font-size: 14.5px;
}

.error-correlation {
    color: var(--ink-muted);
    font-size: 12px;
    margin-bottom: 18px;
}

.error-correlation code {
    background: var(--canvas);
    border: 1px solid var(--line-soft);
    border-radius: var(--radius);
    padding: 1px 5px;
    color: var(--ink-soft);
}


/* ---------- Forms ---------- */

.form-panel {
    padding: var(--s5);
}

.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: var(--s4) var(--s5);
}

.form-field {
    display: flex;
    flex-direction: column;
}

.form-field-wide {
    grid-column: 1 / -1;
}

.form-hint {
    margin: var(--s1) 0 0;
    font-size: var(--t-sm);
    color: var(--ink-muted);
    line-height: 1.6;
}

/* A long form is a set of parts, not one wall of fields. The heading names the part it opens
   and leaves enough room above it that the eye can tell where one ends and the next begins. */
.form-section {
    font-size: var(--t-md);
    font-weight: 600;
    color: var(--ink);
    margin: var(--s7) 0 var(--s4);
    padding-bottom: var(--s2);
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s3);
}

/* The bar that saves the thing.

   A product form is three hundred lines of markup, and the button that commits it used to be at
   the bottom of all of it: fill in the field you came for, then scroll past everything else to
   find Save. It now rides the bottom of the viewport while the form is taller than the screen and
   settles into place at the end when it is not, so it is always one click away and never floats
   over nothing. */
.form-actions {
    position: sticky;
    bottom: 0;
    z-index: 10;
    margin-top: var(--s6);
    padding: var(--s3) 0;
    border-top: 1px solid var(--line);
    background: var(--surface);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--s2);
}

/* Inside a form panel it spans the panel's padding, so the bar reaches both edges and can round
   off the panel's bottom corners rather than floating in from them. */
.form-panel > .form-actions {
    margin-left: calc(var(--s5) * -1);
    margin-right: calc(var(--s5) * -1);
    margin-bottom: calc(var(--s5) * -1);
    padding-left: var(--s5);
    padding-right: var(--s5);
    border-end-start-radius: var(--radius-lg);
    border-end-end-radius: var(--radius-lg);
}

/* Checkbox grids for roles, scope and permissions — dense, because these lists are long. */
.check-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 2px 14px;
}

.check-item {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 4px 0;
    font-size: 13.5px;
    cursor: pointer;
}

.check-item small {
    color: var(--ink-muted);
}

.scope-toggle {
    display: flex;
    gap: 18px;
    margin-bottom: 8px;
}

/* ---------- Toolbar and pager ---------- */

.toolbar {
    display: flex;
    align-items: center;
    gap: var(--s2);
    margin-bottom: var(--s4);
    padding: var(--s3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    flex-wrap: wrap;
}

.toolbar-search {
    flex: 1;
    min-width: 200px;
    max-width: 320px;
}

/* The result count belongs with the filters that produced it, pushed to the far end. */
.toolbar-count {
    margin-right: auto;
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--ink-muted);
    white-space: nowrap;
}

.pager {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 14px;
}

.pager-info {
    font-size: 12.5px;
    color: var(--ink-muted);
}

/* ---------- Report index ---------- */

.report-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 14px;
}

.report-card {
    display: block;
    background: var(--surface, #fff);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 14px 16px;
    text-decoration: none;
    color: inherit;
}

.report-card:hover {
    border-color: var(--accent);
}

.report-name {
    display: block;
    font-size: 14.5px;
    font-weight: 600;
    margin-bottom: 3px;
}

.report-note {
    display: block;
    font-size: 12px;
    color: var(--ink-muted);
    line-height: 1.5;
}

.toolbar-label {
    font-size: 12.5px;
    color: var(--ink-muted);
    white-space: nowrap;
}

/* ---------- Approvals badge ---------- */

/* Deliberately quiet: it is a standing count, not an alarm, and it is on screen all day. */
.approvals-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    background: var(--warn-soft);
    border: 1px solid #F5D9A8;
    border-radius: 999px;
    padding: 3px var(--s3);
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--warn);
    text-decoration: none;
    white-space: nowrap;
}

.approvals-badge:hover {
    background: #FDF0D5;
    color: var(--warn);
}

/* The count is the part that is read; the words around it only say what it counts. */
.approvals-badge strong {
    background: var(--warn);
    color: #FFFFFF;
    border-radius: 999px;
    min-width: 18px;
    padding: 0 5px;
    text-align: center;
    font-variant-numeric: lining-nums tabular-nums;
}

/* ---------- Document totals ---------- */

/* The strip a salesperson actually reads before saying a number out loud, so the grand total is
   the one thing that is visually louder than everything around it. */
.totals-strip {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 26px;
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--line-soft);
}

.totals-strip > div {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    min-width: 110px;
}

.totals-strip span {
    font-size: 12px;
    color: var(--ink-muted);
}

.totals-strip strong {
    font-size: 15px;
    font-variant-numeric: tabular-nums;
    direction: ltr;
}

.totals-grand strong {
    font-size: 19px;
    color: var(--ink);
}

/* A field that is being shown rather than edited. It still reads as a value, so a view screen
   does not look like a form somebody forgot to enable. */
.form-value {
    margin: 2px 0 0;
    font-size: var(--t-base);
    font-weight: 600;
    color: var(--ink);
    min-height: 20px;
}

.checkbox-line {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13.5px;
    margin: 4px 0 12px;
}

.muted {
    color: var(--ink-muted);
    font-size: 12px;
    margin-right: 6px;
}

/* ---------- Table extras ---------- */

.row-actions {
    display: flex;
    gap: 12px;
    white-space: nowrap;
}

.row-sub {
    font-size: 12px;
    color: var(--ink-muted);
    margin-top: 1px;
}

.tag {
    display: inline-block;
    margin-right: 6px;
    background: var(--canvas);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 0 6px;
    font-size: 11px;
    color: var(--ink-muted);
}

.status-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border-radius: 999px;
    padding: 2px 10px;
    font-size: var(--t-xs);
    font-weight: 600;
    border: 1px solid var(--line);
    white-space: nowrap;
}

.status-pill::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

.status-pill.is-on {
    background: var(--success-soft);
    border-color: #B9E7CD;
    color: var(--success);
}

.status-pill.is-off {
    background: var(--canvas);
    color: var(--ink-muted);
}

.btn-link-danger {
    background: none;
    border: none;
    color: var(--danger);
    font-size: var(--t-sm);
    font-weight: 600;
    padding: 0;
    cursor: pointer;
}

.btn-link-danger:hover {
    text-decoration: underline;
}

.mt-3 {
    margin-top: 16px;
}

.text-muted {
    color: var(--ink-muted);
}

/* The product unit grid: compact, because it is a spreadsheet more than a form. */
.unit-table {
    margin-top: 10px;
}

.unit-table td {
    padding: 5px 8px;
    vertical-align: middle;
}

.unit-table .form-control {
    padding: 4px 8px;
    font-size: 13.5px;
}

.image-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 12px;
}

.image-card {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--canvas-alt);
}

.image-card.is-primary {
    border-color: var(--accent);
}

.image-card img {
    width: 100%;
    height: 130px;
    object-fit: cover;
    display: block;
    background: var(--canvas);
}

/* Import preview: a rejected row must be obvious at a glance in a 2,000-row file. */
.row-error {
    background: var(--danger-soft);
}

.row-error-text {
    color: var(--danger);
    font-size: 12.5px;
    line-height: 1.6;
    min-width: 240px;
}

/* A product at or below its reorder level, so it is spotted while scanning a long list. */
.row-low {
    background: #fffaf0;
}

.tag-warn {
    background: #fff4e0;
    border-color: #e8d5b0;
    color: #8a5a00;
}

.tag-danger {
    background: var(--danger-soft);
    border-color: #f3c4bf;
    color: var(--danger);
}

.tag-info {
    background: var(--accent-soft);
    border-color: #cfe4e0;
    color: var(--accent-ink);
}

/* ---------- Notifications (bell + alerts list) ---------- */

.notif-bell {
    position: relative;
    display: inline-flex;
    align-items: center;
    color: var(--ink-soft);
    padding: 6px;
    border-radius: var(--radius);
}

.notif-bell:hover {
    color: var(--accent-ink);
    background: var(--accent-soft);
}

.notif-badge {
    position: absolute;
    top: 0;
    inset-inline-start: 0;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--danger);
    color: #fff;
    font-size: 10px;
    line-height: 16px;
    text-align: center;
    font-weight: 700;
}

.notif-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.notif-item {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3, 1rem);
    padding: var(--space-3, 1rem) 0;
    border-bottom: 1px solid var(--line-soft);
}

.notif-item:last-child {
    border-bottom: 0;
}

.notif-body {
    flex: 1 1 auto;
}

.notif-head {
    display: flex;
    align-items: center;
    gap: var(--space-2, .5rem);
    margin-bottom: 4px;
}

.notif-message {
    margin: 0 0 4px;
    color: var(--ink-soft);
}

.notif-dismiss {
    flex: 0 0 auto;
}

.column-spec-title {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--ink-soft);
    margin: 0 0 8px;
}

.image-card-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    padding: 6px 8px;
    border-top: 1px solid var(--line-soft);
    background: var(--surface);
}

/* ---------- Responsive ---------- */

/* Below this width the column becomes the icon rail whatever the stored preference says: 260px
   of navigation on a 700px screen leaves nothing for the work the navigation leads to. */
@media (max-width: 900px) {
    /* The sidebar becomes an off-canvas drawer — full width WITH its labels, slid in from the
       inline-end (the right, in RTL) over a scrim. The desktop icon-rail (nav-collapsed) is a
       min-width rule, so none of it reaches here: the drawer keeps every label legible. */
    .app-sidebar {
        position: fixed;
        top: 0;
        bottom: 0;
        right: 0;
        width: min(var(--sidebar-width), 84vw);
        transform: translateX(100%);
        transition: transform .18s ease;
        overflow-y: auto;
        box-shadow: -8px 0 28px rgba(16, 64, 59, .28);
    }

    /* Physical right:0 + translateX are used on purpose: the sidebar lives on the right in this
       RTL app, and a logical inset-inline-end would resolve to the left. +100% parks it off-screen. */
    :root.nav-open .app-sidebar {
        transform: translateX(0);
    }

    /* The hamburger is the only way into the menu on a small screen, so it must show here. */
    .nav-toggle {
        display: inline-flex;
    }

    /* Backdrop behind the open drawer; a tap on it closes (showro.js). Present but inert until open. */
    .nav-scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 25;
        background: rgba(15, 23, 32, .45);
        opacity: 0;
        visibility: hidden;
        transition: opacity .18s ease, visibility .18s ease;
    }

    :root.nav-open .nav-scrim {
        opacity: 1;
        visibility: visible;
    }

    .app-topbar {
        padding: 0 var(--s4);
    }

    .topbar-search {
        max-width: none;
    }

    .app-content {
        padding: var(--s4);
    }

    /* A wide grid stops pushing the page sideways and scrolls inside itself instead. */
    .table {
        display: block;
        overflow-x: auto;
        white-space: nowrap;
    }

    /* Turning the table into a scroll container takes the header out of the table layout, and a
       sticky header then floats over the first row and hides it. Inside its own scroller the
       header has nothing to stick to anyway. */
    .table thead th {
        position: static;
    }
}

/* ==========================================================================
   Document line grids  (showro.js)

   Every document is a header plus an arbitrary number of lines. The grid grows
   and shrinks in the browser, so nothing here may assume a fixed row count.
   ========================================================================== */

.line-grid {
    margin-bottom: 18px;
}

.line-grid-scroll {
    overflow: auto;
    /* A short document never sees a scrollbar; a long one — a receipt or an adjustment with thirty
       lines — scrolls inside its own frame, with the column headers held in place, instead of
       running down the page and pushing the totals and the save button out of reach. */
    max-height: min(62vh, 640px);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
}

/* The grid draws its own frame, so the table inside it must not draw a second one. */
.line-grid-scroll .line-table {
    margin: 0;
    border: 0;
    border-radius: 0;
}

/* Held to the top of the grid's OWN scroller (not the page topbar the wider .table uses), so
   scrolling thirty lines never loses which column is which. Self-contained — position and
   background are set here rather than inherited, because the page-width rule turns .table headers
   static on a narrow screen and the grid still has its own bounded scroller to stick inside. */
.line-table thead th {
    white-space: nowrap;
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--canvas-alt);
}

/* Numeric cells must not be squeezed to nothing.

   Sharing the row with the summary panel costs the grid about 340px, and a table left to fit
   whatever is left will happily shrink a quantity box until its own value has scrolled out of
   sight — which is what happened: the figures were right and completely unreadable. Giving the
   inputs a floor forces the table past its container instead, and .line-grid-scroll then does
   what it is there for. */
.line-table td .form-control {
    min-width: 88px;
}

.line-table td .product-box {
    min-width: 200px;
}

.line-table .line-num {
    width: 38px;
    text-align: center;
    color: var(--ink-muted);
    font-variant-numeric: lining-nums tabular-nums;
}

.line-table .line-actions {
    width: 44px;
    text-align: center;
}

.line-table .line-total {
    font-variant-numeric: lining-nums tabular-nums;
    color: var(--ink-soft);
    white-space: nowrap;
}

/* A line that is fully priced reads as settled; one still waiting on a price stays quiet. The
   class is set by showro.js, because CSS cannot select on a cell's text content. */
.line-table .line-total.is-priced {
    color: var(--ink);
    font-weight: 600;
}

.product-box {
    min-width: 220px;
}

/* Typed text that matches no catalogue entry posts NO product, so say so before the save does. */
.product-box.is-unmatched {
    border-color: var(--warn);
    background: var(--warn-soft);
}

/* The product's balance in the chosen warehouse, filled by showro.js under the product box, so a
   line about to move stock shows what is on the shelf without leaving the document. */
.line-onhand {
    display: block;
    margin-top: 4px;
    font-size: 12px;
    color: var(--ink-muted);
    font-variant-numeric: lining-nums tabular-nums;
}

/* An empty shelf where a line is about to draw from earns a warning colour. */
.line-onhand.is-empty {
    color: var(--warn);
    font-weight: 600;
}

/* Filled by showro.js under the price box when the chosen product+unit has no price on file, so a
   blank price reads as a stated fact rather than an oversight. Warning-tinted like an empty shelf. */
.line-price-hint {
    display: block;
    margin-top: 4px;
    font-size: 12px;
    font-weight: 600;
    color: var(--warn);
}

.btn-line-remove {
    border: 1px solid transparent;
    background: none;
    color: var(--ink-muted);
    font-size: 18px;
    line-height: 1;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background .12s, color .12s, border-color .12s;
}

.btn-line-remove:hover:not(:disabled) {
    background: var(--danger-soft);
    border-color: var(--danger);
    color: var(--danger);
}

.btn-line-remove:disabled {
    opacity: .3;
    cursor: default;
}

.line-grid-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 10px;
}

.btn-add-line {
    background: var(--accent-soft);
    color: var(--accent-ink);
    border: 1px dashed var(--accent);
    font-weight: 600;
}

.btn-add-line:hover,
.btn-add-line:focus {
    background: var(--accent);
    border-style: solid;
    color: #fff;
}

.line-add-hint {
    display: inline-block;
    margin: 0 10px 0 0;
}

/* The preview is explicitly not the invoice total: the server prorates the document discount and
   rounds at four decimals (D-24), so this figure guides, it does not promise. */
.line-preview {
    display: flex;
    align-items: baseline;
    gap: 18px;
    font-size: 13px;
    color: var(--ink-muted);
}

.line-preview strong {
    color: var(--ink);
    font-variant-numeric: lining-nums tabular-nums;
}

.line-preview-total strong {
    font-family: var(--display-font);
    font-size: 18px;
    color: var(--accent-ink);
    margin-right: 4px;
}

/* Visible to a screen reader, not on screen — for a column that is only an action button. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ==========================================================================
   Typography — the display face earns its place on titles and figures only
   ========================================================================== */

.page-title,
.section-heading,
.kpi-value,
.brand-mark {
    font-family: var(--display-font);
}

.page-title {
    letter-spacing: -.2px;
}

/* Figures are the product here: give every column of them the same width per digit so a column
   of prices lines up on the decimal instead of drifting. */
.table .num,
.kpi-value,
.totals-strip strong {
    font-variant-numeric: lining-nums tabular-nums;
}

/* ==========================================================================
   Depth

   Borders alone make every surface read as a form field. A single soft shadow
   lifts the things that are actually objects — a card, a grid, a panel — off
   the page without turning the interface into a pile of floating boxes.
   ========================================================================== */

.kpi-card,
.line-grid-scroll {
    box-shadow: var(--shadow-sm);
}

.kpi-card {
    transition: box-shadow .15s, border-color .15s;
}

.kpi-card:hover {
    box-shadow: var(--shadow);
    border-color: var(--line-strong);
}

/* The figure the salesperson is actually waiting for. */
.line-preview-total strong {
    font-size: 21px;
}

/* ==========================================================================
   Dashboard — context, not just figures

   A number on its own cannot be read. Every headline figure carries what it is
   being compared against, the window it covers is chosen rather than assumed,
   and the shape of the business is drawn so it is visible without opening a
   report.
   ========================================================================== */

/* ---------- the filter ----------

   Every figure on the screen answers "over which period, in which branch?", so
   the controls that decide it sit above them all, on their own surface. */

.filter-bar {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--s4);
    flex-wrap: wrap;
    margin-bottom: var(--s5);
    padding: var(--s3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

/* The presets read as one segmented control, because they are one choice. */
.range-tabs {
    display: inline-flex;
    background: var(--canvas);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 2px;
    gap: 2px;
    flex-wrap: wrap;
}

.range-tab {
    background: none;
    border: 0;
    border-radius: var(--radius-sm);
    padding: 5px var(--s3);
    font-family: inherit;
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--ink-muted);
    cursor: pointer;
    white-space: nowrap;
}

.range-tab:hover {
    color: var(--ink);
    background: var(--surface);
}

.range-tab.is-active {
    background: var(--surface);
    color: var(--accent-ink);
    box-shadow: var(--shadow-sm);
}

.filter-fields {
    display: flex;
    align-items: flex-end;
    gap: var(--s2);
    flex-wrap: wrap;
}

.filter-field {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.filter-label {
    font-size: var(--t-xs);
    font-weight: 600;
    color: var(--ink-muted);
}

.filter-field .form-control {
    height: 34px;
    padding: 0 var(--s2);
    font-size: var(--t-sm);
}

/* ---------- headline figures ---------- */

/* Revenue is what the owner opens the screen for; it gets the weight. */
.kpi-hero {
    border-color: var(--accent);
    background: linear-gradient(180deg, var(--accent-soft) 0%, var(--surface) 58%);
}

.kpi-hero .kpi-value {
    font-size: 34px;
    color: var(--accent-ink);
}

/* Direction is carried by the arrow AND the colour, never by colour alone. */
.delta {
    font-weight: 600;
    font-variant-numeric: lining-nums tabular-nums;
    margin-left: var(--s1);
}

.delta-up {
    color: var(--success);
}

.delta-down {
    color: var(--danger);
}

.delta-flat {
    color: var(--ink-muted);
}

/* ---------- the two charts, side by side ---------- */

.chart-row {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: var(--s4);
    margin-bottom: var(--s6);
    align-items: start;
}

@media (max-width: 1100px) {
    .chart-row {
        grid-template-columns: 1fr;
    }
}

.panel-note {
    font-size: var(--t-xs);
    font-weight: 400;
    color: var(--ink-muted);
    margin-right: var(--s2);
}

.trend-panel {
    padding-bottom: var(--s3);
}

.trend-chart {
    padding: var(--s5) var(--s5) 0;
}

.trend-chart svg {
    width: 100%;
    height: 150px;
    display: block;
}

.trend-baseline {
    stroke: var(--line);
    stroke-width: 2;
}

.trend-bar {
    fill: var(--accent);
    opacity: .28;
    transition: opacity .12s;
}

.trend-bar:hover {
    opacity: .6;
}

/* The most recent bucket is the one being asked about; the rest is context. */
.trend-bar-today {
    opacity: 1;
}

.trend-legend {
    display: flex;
    justify-content: space-between;
    padding: var(--s2) var(--s5) 0;
    font-size: var(--t-xs);
    color: var(--ink-muted);
}

/* ---------- where the money came from ----------

   A ring drawn as one stroked circle per slice: no charting library, it prints,
   and each arc carries its own <title> so hovering names it. Identity is never
   colour alone — the legend spells out every slice with its share. */

.donut {
    display: flex;
    align-items: center;
    gap: var(--s4);
    padding: var(--s5);
    flex-wrap: wrap;
}

.donut svg {
    width: 132px;
    height: 132px;
    flex-shrink: 0;
}

.donut-slice {
    fill: none;
    stroke-width: 16;
    transition: stroke-width .12s;
}

.donut-slice:hover {
    stroke-width: 19;
}

.donut-legend {
    list-style: none;
    margin: 0;
    padding: 0;
    flex: 1;
    min-width: 150px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.donut-legend li {
    display: flex;
    align-items: center;
    gap: var(--s2);
    font-size: var(--t-sm);
}

.donut-key {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    flex-shrink: 0;
}

.donut-name {
    color: var(--ink-soft);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.donut-share {
    margin-right: auto;
    font-weight: 600;
    color: var(--ink);
    font-variant-numeric: lining-nums tabular-nums;
}

/* The categorical palette. Six hues, in this fixed order, checked for lightness
   band, chroma, adjacent-pair separation under protanopia/deuteranopia/tritanopia
   and contrast against the surface. A seventh category folds into the remainder
   slice rather than getting a generated colour. */
.slice-0 { stroke: #00897B; background: #00897B; }
.slice-1 { stroke: #D4380D; background: #D4380D; }
.slice-2 { stroke: #1D4ED8; background: #1D4ED8; }
.slice-3 { stroke: #B45309; background: #B45309; }
.slice-4 { stroke: #C026D3; background: #C026D3; }
.slice-5 { stroke: #4D7C0F; background: #4D7C0F; }

/* ---------- who and what carried the period ---------- */

.rank-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.rank-list li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s3);
    padding: var(--s3) var(--s5);
    border-bottom: 1px solid var(--line-soft);
}

.rank-list li:last-child {
    border-bottom: none;
}

.rank-name {
    display: flex;
    flex-direction: column;
    min-width: 0;
    font-weight: 600;
    color: var(--ink);
}

.rank-name small {
    font-weight: 400;
    font-size: var(--t-xs);
    color: var(--ink-muted);
}

.rank-figure {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
    white-space: nowrap;
    font-weight: 600;
    font-variant-numeric: lining-nums tabular-nums;
}

.rank-figure small {
    font-weight: 400;
    font-size: var(--t-xs);
    color: var(--ink-muted);
}


/* ==========================================================================
   List rows — identity, stock, and the row menu
   ========================================================================== */

/* The name and the code identify the same thing, and a showroom reads one or the other depending
   on who is asking, so they travel together in the first column. */
.cell-identity {
    display: flex;
    align-items: center;
    gap: var(--s3);
    min-width: 0;
}

.cell-identity-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.35;
}

.cell-title {
    font-weight: 600;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
}

.cell-identity-text small {
    font-weight: 400;
    font-size: var(--t-xs);
    color: var(--ink-muted);
}

/* The identity column carries its own weight, so the blanket rule for first cells stands down. */
.table tbody td:first-child .cell-identity {
    font-weight: 400;
}

/* A quantity at or below its reorder level, so it is spotted while scanning rather than hunted
   for. The word is carried for a screen reader too; the colour is not the only signal. */
.stock-low {
    color: var(--warn);
    font-weight: 600;
}

/* ---------- the row menu ----------

   One button per row rather than a row of competing links. The actions are rare next to the
   reading, and a delete link sitting permanently beside every line is an accident waiting to be
   clicked. */

.row-menu-cell {
    width: 44px;
    text-align: center;
}

/* Some rows offer nothing: every action on them is behind a permission this viewer lacks, or
   behind a status the row is not in. Without this they show a three-dot button that opens an
   empty menu. Done in CSS rather than as a condition per list, because a condition repeated in
   twenty views is a condition that drifts in one of them. */
.row-menu:not(:has(li)) {
    display: none;
}

.row-menu-button {
    background: none;
    border: 0;
    border-radius: var(--radius-sm);
    padding: var(--s1) 6px;
    color: var(--ink-muted);
    cursor: pointer;
    line-height: 0;
}

.row-menu-button:hover,
.row-menu-button[aria-expanded="true"] {
    background: var(--canvas);
    color: var(--ink);
}

.row-menu-icon {
    width: 18px;
    height: 18px;
}

.row-menu .dropdown-menu {
    min-width: 168px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: var(--s1);
    font-size: var(--t-base);
}

/* The delete entry is also a submit button inside a form, so it has to be talked back into
   looking like the link above it. */
.row-menu .dropdown-item {
    border-radius: var(--radius-sm);
    padding: 6px var(--s3);
    width: 100%;
    text-align: right;
    background: none;
    border: 0;
    font-family: inherit;
    font-size: inherit;
    color: var(--ink-soft);
    cursor: pointer;
}

.row-menu .dropdown-item:hover,
.row-menu .dropdown-item:focus {
    background: var(--canvas);
    color: var(--ink);
}

.row-menu .dropdown-item.is-danger {
    color: var(--danger);
}

.row-menu .dropdown-item.is-danger:hover,
.row-menu .dropdown-item.is-danger:focus {
    background: var(--danger-soft);
    color: var(--danger);
}


/* ==========================================================================
   The sales workspace

   A sales order is not a form somebody fills in and submits — it is a task
   somebody performs while a customer stands in front of them. The lines are
   the work and take the width; the figure the sale turns on, and the button
   that ends it, stay on screen while the lines scroll past.
   ========================================================================== */

.workspace {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: var(--s4);
    align-items: start;
}

.workspace-main {
    min-width: 0;
}

/* First child of an RTL grid row, so the work sits on the right and the panel on the left. */
.workspace-side {
    position: sticky;
    top: calc(var(--topbar-height) + var(--s5));
}

/* .panel draws no padding of its own, because most of what goes in it is a table. */
.panel-pad {
    padding: var(--s5);
}

.summary-card {
    display: flex;
    flex-direction: column;
}

.summary-live,
.summary-saved,
.summary-field,
.summary-actions {
    padding: var(--s4) var(--s5);
}

.summary-live + .summary-field,
.summary-field + .summary-field,
.summary-saved,
.summary-actions {
    border-top: 1px solid var(--line-soft);
}

.summary-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s3);
    font-size: var(--t-base);
    color: var(--ink-muted);
    padding: 3px 0;
}

.summary-row strong {
    color: var(--ink);
    font-variant-numeric: lining-nums tabular-nums;
}

/* The number said out loud to the customer. Everything else on the panel is working out. */
.summary-grand {
    margin-top: var(--s2);
    padding-top: var(--s3);
    border-top: 1px solid var(--line);
    font-size: var(--t-md);
    color: var(--ink);
}

.summary-grand strong {
    font-size: 24px;
    font-weight: 600;
    color: var(--accent-ink);
}

.summary-field .form-hint {
    margin-bottom: 0;
}

.summary-actions {
    display: flex;
    flex-direction: column;
    gap: var(--s2);
    align-items: stretch;
    text-align: center;
}

.summary-actions .btn {
    padding: var(--s3) var(--s4);
}

.summary-note {
    padding: 0 var(--s5) var(--s4);
    margin: 0;
}

/* Below this the panel has nowhere useful to stick, so it becomes the last section of the page. */
@media (max-width: 1180px) {
    .workspace {
        grid-template-columns: 1fr;
    }

    .workspace-side {
        position: static;
    }
}

/* ---------- Report filter bar and grids ---------- */

/*
    The filter bar wraps rather than scrolls: eight dimensions on a narrow screen become three rows
    of controls, all of them reachable, instead of one row with half of it off the edge.
*/
.report-filters {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px 14px;
    margin-bottom: 14px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 8px;
}

.report-filters-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 10px 14px;
}

.filter-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 150px;
}

.filter-field .form-control {
    min-width: 150px;
}

.filter-check {
    justify-content: flex-end;
}

.filter-check .checkbox-line {
    margin: 0 0 6px;
    white-space: nowrap;
}

.filter-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-inline-start: auto;
}

.report-exports {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding-top: 10px;
    border-top: 1px solid var(--line-soft);
}

/* What the figures were narrowed by, on screen as well as on paper — so the person reading the
   table knows it is not the whole month. */
.report-criteria {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 8px;
    margin-bottom: 12px;
}

.report-criterion {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    padding: 3px 10px;
    font-size: 12.5px;
    background: var(--canvas-alt);
    border: 1px solid var(--line);
    border-radius: 999px;
}

.report-criterion-label {
    color: var(--ink-muted);
}

.report-criterion-value {
    font-weight: 600;
}

/* A wide report scrolls inside its own box; the page itself never scrolls sideways. */
.table-scroll {
    overflow-x: auto;
}

.report-table {
    min-width: 100%;
}

.report-total-row td {
    font-weight: 700;
    border-top: 2px solid var(--line);
    background: var(--canvas-alt);
}

/* ---------- Report chart (grouped reports) ---------- */

/* A single-measure horizontal bar chart, inline SVG so it needs no client library. One accent
   colour — a single series carries no legend; text stays in ink tokens, never the bar colour. */
.report-chart {
    display: block;
    max-width: 100%;
    font-family: var(--app-font);
}

.report-chart-axis {
    stroke: var(--line-strong);
    stroke-width: 1;
}

.report-chart-bar {
    fill: var(--accent);
}

.report-chart-cat {
    fill: var(--ink-soft);
    font-size: 12px;
}

.report-chart-val {
    fill: var(--ink);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
}

.report-chart-toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-2, .5rem);
    margin-bottom: var(--space-2, .5rem);
    flex-wrap: wrap;
}

/* ---------- Products list ---------- */

/* The low-stock toggle sits inline in the filter toolbar, aligned with the controls beside it
   rather than floating a line above them. */
.toolbar-check {
    margin: 0;
    white-space: nowrap;
    align-self: center;
}

/* The product name doubles as the link to its record: it reads as a heading until hovered, so the
   row stays calm while still being one tap from editing. */
.cell-title-link {
    color: inherit;
    text-decoration: none;
}

.cell-title-link:hover {
    color: var(--accent-dark);
    text-decoration: underline;
}

/* Quantity then a small badge beneath, so the number is read first and the warning second rather
   than competing for the same line. */
.stock-figure {
    display: inline-block;
    font-variant-numeric: lining-nums tabular-nums;
}

.price-figure {
    font-variant-numeric: lining-nums tabular-nums;
}

.stock-badge {
    display: block;
    margin-top: 2px;
    font-size: var(--t-xs);
    font-weight: 600;
    line-height: 1.4;
}

.stock-badge.is-low {
    color: var(--warn);
}

.stock-badge.is-out {
    color: var(--danger);
}

/* ---------------------------------------------------------------------------
   Document actions — progressive disclosure.

   A sales document carries several one-off actions (confirm, post, take a
   deposit, collect, apply credit, cancel). Rendered all at once they became a
   wall of open forms stacked down the page; here each is a collapsible row, so
   the screen shows a short scannable list and only the action in use is open.
   Native <details>, so no script is needed; the shared name= makes them an
   exclusive accordion in the browsers that support it and independent rows in
   those that do not, which is a fine fallback.
   --------------------------------------------------------------------------- */
.doc-actions {
    display: flex;
    flex-direction: column;
    gap: var(--s3);
    margin-top: var(--s6);
}

.doc-actions-title {
    font-size: var(--t-md);
    font-weight: 600;
    color: var(--ink);
    margin: 0 0 var(--s1);
}

.doc-action {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

.doc-action > summary {
    display: flex;
    align-items: center;
    gap: var(--s3);
    padding: var(--s4) var(--s5);
    font-size: var(--t-base);
    font-weight: 600;
    color: var(--ink);
    cursor: pointer;
    list-style: none;
    user-select: none;
}

.doc-action > summary::-webkit-details-marker {
    display: none;
}

/* A chevron on the trailing edge that turns as the row opens. */
.doc-action > summary::after {
    content: "";
    width: 8px;
    height: 8px;
    margin-inline-start: auto;
    border-inline-end: 2px solid var(--ink-muted);
    border-bottom: 2px solid var(--ink-muted);
    transform: rotate(45deg);
    transition: transform .15s ease;
    flex: 0 0 auto;
}

.doc-action[open] > summary::after {
    transform: rotate(225deg);
}

.doc-action > summary:hover {
    background: var(--canvas-alt);
}

.doc-action > summary:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

/* The open row is accented so it is obvious which action is expanded. */
.doc-action[open] {
    border-color: var(--accent);
}

.doc-action[open] > summary {
    border-bottom: 1px solid var(--line-soft);
}

.doc-action.is-danger[open] {
    border-color: var(--danger);
}

.doc-action-body {
    padding: var(--s5);
}

/* The action's own button row — plain, unlike the sticky bar of the main form. */
.doc-action-actions {
    margin-top: var(--s5);
    display: flex;
    align-items: center;
    gap: var(--s2);
}

/* ---------- reconciliation alerts ---------- */
/* The healthy state is the common one, so a clean check reads as a clear "all good", not a blank
   page: a success-tinted panel with a tick, sized to its content. */
.reconcile-ok {
    display: flex;
    align-items: center;
    gap: var(--s4);
    border-color: var(--success);
    background: var(--success-soft);
}

.reconcile-ok-mark {
    flex: none;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--success);
    color: #fff;
    font-weight: 700;
    font-size: 1.2rem;
}

.reconcile-ok-title {
    margin: 0;
    font-weight: 600;
    color: var(--success);
}

/* Count of discrepancies beside a section title — a warning-tinted pill, so the size of the
   problem reads at a glance. */
.count-badge {
    display: inline-block;
    min-width: 1.4em;
    padding: 0 var(--s2);
    border-radius: 999px;
    background: var(--warn-soft);
    color: var(--warn);
    font-size: .8rem;
    font-weight: 700;
    text-align: center;
    vertical-align: middle;
}
