/* ===========================================================================
   Kashmir Soil CRM — design system
   ---------------------------------------------------------------------------
   Replaces the ~200 line <style> block that was pasted into index.php,
   view.php, follow_ups.php, create.php, edit.php and manage_users.php. Change
   a token here and every page follows.

   Tailwind's CDN utilities are still loaded for layout; this file owns the
   components (sidebar, cards, tables, badges, buttons, forms, charts).
   =========================================================================== */

:root {
    /* Brand ------------------------------------------------------------- */
    --brand:            #d86c30;
    --brand-dark:       #b85520;
    --brand-darker:     #93411a;
    --brand-tint:       #fdf0e8;
    --brand-tint-2:     #f9d5bd;

    /* Surfaces ---------------------------------------------------------- */
    --page:             #f4f5f7;
    --surface:          #ffffff;
    --surface-2:        #f8fafc;
    --surface-3:        #f1f5f9;

    /* Ink --------------------------------------------------------------- */
    --ink:              #0f172a;
    --ink-2:            #475569;
    --ink-muted:        #64748b;
    --ink-on-brand:     #ffffff;

    /* Lines ------------------------------------------------------------- */
    --border:           #e2e8f0;
    --border-strong:    #cbd5e1;

    /* Chart palette — validated with the dataviz validator against the
       #ffffff card surface. Order is the CVD-safety mechanism: do not
       reshuffle without re-running the validator.
         series-1 orange  #d86c30  (brand)
         series-2 blue    #2a78d6
         series-3 aqua    #1baf7a
         series-null      #475569  achromatic on purpose — the "no data" class
       series-3 (2.82:1) and series-null (2.55:1) sit under 3:1 on white, so
       every chart using them ships visible direct labels and a table of the
       same numbers. That relief is required, not optional.               */
    --series-1:         #d86c30;
    --series-2:         #2a78d6;
    --series-3:         #1baf7a;
    --series-null:      #475569;

    --grid:             #e8ebf0;
    --axis:             #cbd5e1;

    /* Status (UI feedback, not chart series) ----------------------------- */
    --ok:               #0f7c39;
    --ok-bg:            #e7f6ec;
    --warn:             #9a5b00;
    --warn-bg:          #fdf3e2;
    --danger:           #b42318;
    --danger-bg:        #fdeceb;
    --info:             #1c5cab;
    --info-bg:          #eaf2fd;

    /* Shape ------------------------------------------------------------- */
    --r-sm:             .5rem;
    --r:                .75rem;
    --r-lg:             1rem;
    --shadow-sm:        0 1px 2px rgba(15, 23, 42, .06);
    --shadow:           0 1px 3px rgba(15, 23, 42, .08), 0 1px 2px rgba(15, 23, 42, .04);
    --shadow-lg:        0 10px 25px rgba(15, 23, 42, .08), 0 4px 10px rgba(15, 23, 42, .04);

    --sidebar-w:        272px;
    --topbar-h:         64px;
}

/* ===========================================================================
   Base
   =========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    min-height: 100vh;
    font-family: 'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
    font-size: 14px;
    line-height: 1.5;
    color: var(--ink);
    background: var(--page);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -.01em; }

a { color: inherit; text-decoration: none; }

.text-muted { color: var(--ink-muted); }
.text-secondary { color: var(--ink-2); }
.nums { font-variant-numeric: tabular-nums; }

/* Keyboard focus is visible everywhere — it was missing entirely before. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
    border-radius: 4px;
}

/* ===========================================================================
   App shell
   =========================================================================== */

.app { min-height: 100vh; }

.app-main {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

@media (min-width: 1024px) {
    .app-main { margin-left: var(--sidebar-w); }
}

.page {
    flex: 1;
    padding: 1.25rem;
    padding-bottom: 5rem;
}

@media (min-width: 768px) {
    .page { padding: 1.75rem 2rem 5rem; }
}

.page-inner { max-width: 1600px; margin: 0 auto; }

/* --- Sidebar ------------------------------------------------------------- */

.sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--sidebar-w);
    z-index: 60;
    display: flex;
    flex-direction: column;
    background: linear-gradient(175deg, var(--brand) 0%, var(--brand-dark) 55%, var(--brand-darker) 100%);
    color: var(--ink-on-brand);
    overflow-y: auto;
    overscroll-behavior: contain;
    box-shadow: var(--shadow-lg);
    transform: translateX(-100%);
    transition: transform .3s cubic-bezier(.4, 0, .2, 1);
}

.sidebar.is-open { transform: translateX(0); }

@media (min-width: 1024px) {
    .sidebar { transform: translateX(0); }
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: 1.25rem 1.25rem 1rem;
    border-bottom: 1px solid rgba(255, 255, 255, .16);
}

.sidebar-mark {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    flex: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, .18);
    font-weight: 700;
    font-size: .8rem;
    letter-spacing: .02em;
}

.sidebar-title { font-size: .95rem; font-weight: 600; line-height: 1.2; }
.sidebar-sub { font-size: .7rem; opacity: .8; }

.sidebar-nav { padding: .875rem .75rem; flex: 1; }

.sidebar-section {
    padding: .875rem .5rem .375rem;
    font-size: .66rem;
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
    opacity: .65;
}

.nav-link {
    display: flex;
    align-items: center;
    gap: .8rem;
    padding: .625rem .75rem;
    margin-bottom: .125rem;
    border-radius: var(--r-sm);
    font-size: .875rem;
    font-weight: 500;
    color: rgba(255, 255, 255, .92);
    transition: background .15s, color .15s;
}

.nav-link i { width: 1.15rem; text-align: center; font-size: .9rem; opacity: .9; }
.nav-link:hover { background: rgba(255, 255, 255, .13); color: #fff; }

.nav-link.is-active {
    background: #fff;
    color: var(--brand-dark);
    font-weight: 600;
    box-shadow: var(--shadow-sm);
}

.nav-link.is-active i { opacity: 1; }

.nav-link.is-danger:hover { background: rgba(180, 35, 24, .55); }

.sidebar-foot {
    padding: .75rem;
    border-top: 1px solid rgba(255, 255, 255, .16);
}

.sidebar-overlay {
    position: fixed;
    inset: 0;
    z-index: 55;
    background: rgba(15, 23, 42, .55);
    backdrop-filter: blur(2px);
    opacity: 0;
    pointer-events: none;
    transition: opacity .25s;
}

.sidebar-overlay.is-open { opacity: 1; pointer-events: auto; }

@media (min-width: 1024px) {
    .sidebar-overlay { display: none; }
}

/* --- Top bar ------------------------------------------------------------- */

.topbar {
    position: sticky;
    top: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 1rem;
    height: var(--topbar-h);
    padding: 0 1rem;
    background: rgba(255, 255, 255, .88);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--border);
}

@media (min-width: 768px) {
    .topbar { padding: 0 2rem; }
}

.topbar-toggle {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    flex: none;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--ink-2);
    cursor: pointer;
}

.topbar-toggle:hover { background: var(--surface-3); }

@media (min-width: 1024px) {
    .topbar-toggle { display: none; }
}

.topbar-heading { min-width: 0; flex: 1; }
.topbar-heading h1 { font-size: 1.0625rem; }
.topbar-heading p { margin: 0; font-size: .75rem; color: var(--ink-muted); }

.topbar-user {
    display: flex;
    align-items: center;
    gap: .625rem;
    padding: .3rem .3rem .3rem .75rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
}

.topbar-user-name { font-size: .8rem; font-weight: 500; line-height: 1.15; }
.topbar-user-role { font-size: .68rem; color: var(--ink-muted); text-transform: capitalize; }

.avatar {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    flex: none;
    border-radius: 999px;
    background: var(--brand);
    color: #fff;
    font-size: .75rem;
    font-weight: 600;
}

/* --- Top bar on a phone ---------------------------------------------------
   The bar is a single row of fixed height, and on a narrow screen the toggle,
   heading, subtitle, action button and user chip cannot all fit: the subtitle
   wrapped onto three lines, spilling out of the 64px bar and pushing the button
   across the title. Everything below trims the bar to what a phone can show. */
@media (max-width: 767px) {
    .topbar { gap: .5rem; padding: 0 .75rem; }

    /* One line, cut with an ellipsis rather than wrapped. */
    .topbar-heading h1 {
        font-size: 1rem;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* The counts are repeated in the card head just below, so the bar can
       drop them rather than wrap them. */
    .topbar-heading p { display: none; }

    /* The action keeps its place; it must not wrap or be squeezed. */
    .page-actions { flex: none; flex-wrap: nowrap; }
    .page-actions .btn { padding: .5rem .7rem; white-space: nowrap; }

    /* Avatar only — the name and role are already on the account page, and the
       chip's frame is what was forcing the row over the edge. */
    .topbar-user {
        flex: none;
        gap: 0;
        padding: 0;
        border: 0;
        background: transparent;
    }

    .topbar-user > div:first-child { display: none; }
}

/* ===========================================================================
   Page furniture
   =========================================================================== */

.page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.page-head h2 { font-size: 1.375rem; }
.page-head p { margin: .2rem 0 0; font-size: .8rem; color: var(--ink-muted); }
.page-actions { display: flex; flex-wrap: wrap; gap: .5rem; }

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
    box-shadow: var(--shadow-sm);
}

.card-pad { padding: 1.125rem 1.25rem; }

.card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--border);
}

.card-head h3 { font-size: .9375rem; }
.card-head p { margin: .15rem 0 0; font-size: .72rem; color: var(--ink-muted); }

.card-body { padding: 1.25rem; }

/* --- Flash messages ------------------------------------------------------ */

.alert {
    display: flex;
    align-items: flex-start;
    gap: .625rem;
    padding: .75rem .875rem;
    margin-bottom: 1rem;
    border: 1px solid transparent;
    border-radius: var(--r-sm);
    font-size: .8125rem;
}

.alert i { margin-top: .1rem; flex: none; }
.alert-success { color: var(--ok);     background: var(--ok-bg);     border-color: #bfe4cc; }
.alert-error   { color: var(--danger); background: var(--danger-bg); border-color: #f6cbc7; }
.alert-warning { color: var(--warn);   background: var(--warn-bg);   border-color: #f5ddb4; }
.alert-info    { color: var(--info);   background: var(--info-bg);   border-color: #c6dcf8; }

.alert-close {
    margin-left: auto;
    border: 0;
    background: none;
    color: inherit;
    opacity: .6;
    cursor: pointer;
    font-size: .9rem;
}

.alert-close:hover { opacity: 1; }

/* ===========================================================================
   Buttons
   =========================================================================== */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    padding: .5625rem .9375rem;
    border: 1px solid transparent;
    border-radius: var(--r-sm);
    font: inherit;
    font-size: .8125rem;
    font-weight: 500;
    line-height: 1.2;
    white-space: nowrap;
    cursor: pointer;
    transition: background .15s, border-color .15s, color .15s, box-shadow .15s;
}

.btn:disabled { opacity: .55; cursor: not-allowed; }

.btn-primary { background: var(--brand); color: #fff; box-shadow: var(--shadow-sm); }
.btn-primary:hover:not(:disabled) { background: var(--brand-dark); }

.btn-secondary { background: var(--surface); border-color: var(--border-strong); color: var(--ink-2); }
.btn-secondary:hover:not(:disabled) { background: var(--surface-3); color: var(--ink); }

.btn-danger { background: var(--danger); color: #fff; }
.btn-danger:hover:not(:disabled) { background: #96190f; }

.btn-success { background: var(--ok); color: #fff; }
.btn-success:hover:not(:disabled) { background: #0b5f2c; }

.btn-ghost { background: transparent; color: var(--ink-2); }
.btn-ghost:hover:not(:disabled) { background: var(--surface-3); }

.btn-sm { padding: .375rem .625rem; font-size: .75rem; }
.btn-block { width: 100%; }

/* Square icon-only action button used in table rows. */
.icon-btn {
    display: inline-grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border: 1px solid transparent;
    border-radius: var(--r-sm);
    font-size: .8rem;
    cursor: pointer;
    transition: filter .15s, background .15s;
}

.icon-btn:hover { filter: brightness(.92); }
.icon-btn-edit   { background: var(--warn-bg);   color: var(--warn); }
.icon-btn-view   { background: var(--info-bg);   color: var(--info); }
.icon-btn-pdf    { background: #f3e8fd;          color: #6b21a8; }
.icon-btn-delete { background: var(--danger-bg); color: var(--danger); }
.icon-btn-share  { background: var(--ok-bg);     color: var(--ok); }
.icon-btn-replace{ background: var(--brand-tint); color: var(--brand-darker); }

/* Replace and delete are submit buttons inside their own small form, so they
   need the button defaults flattened to match the anchors beside them. */
button.icon-btn { padding: 0; font-family: inherit; }
button.icon-btn:disabled { filter: none; }
.action-group form { display: inline-flex; margin: 0; }

.action-group { display: inline-flex; gap: .3rem; }

/* ===========================================================================
   Badges
   =========================================================================== */

.badge {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .2rem .5rem;
    border-radius: 999px;
    font-size: .6875rem;
    font-weight: 600;
    line-height: 1.35;
    white-space: nowrap;
}

.badge-pending { color: var(--warn);   background: var(--warn-bg); }
.badge-waiting { color: var(--info);   background: var(--info-bg); }
.badge-closed  { color: var(--ok);     background: var(--ok-bg); }
.badge-muted   { color: var(--ink-muted); background: var(--surface-3); }
.badge-brand   { color: var(--brand-darker); background: var(--brand-tint); }
.badge-count   { color: var(--ink-2); background: var(--surface-3); font-variant-numeric: tabular-nums; }

/* Version history: which version the original was replaced with. Without these
   the page shows an ordinary edit and a replaced quotation identically, which
   is the one thing the reader needs to tell apart. */
.badge-inuse    { color: var(--ok);   background: var(--ok-bg); }
.badge-replaced { color: var(--warn); background: var(--warn-bg); }

/* Badges stack under the version number rather than widening the column. */
.badge-stack { display: flex; flex-direction: column; align-items: flex-start; gap: .25rem; }

/* A label inside a badge that may be shortened when the badge runs out of room.
   min-width: 0 is the part that matters — without it the flex item keeps its
   full width and the pill overflows its cell instead. */
.badge-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ===========================================================================
   Forms
   =========================================================================== */

.field { margin-bottom: .875rem; }

.label {
    display: block;
    margin-bottom: .3rem;
    font-size: .75rem;
    font-weight: 600;
    color: var(--ink-2);
}

.input, .select, .textarea {
    display: block;
    width: 100%;
    padding: .5625rem .75rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--r-sm);
    background: var(--surface);
    font: inherit;
    font-size: .8125rem;
    color: var(--ink);
    transition: border-color .15s, box-shadow .15s;
}

.input:focus, .select:focus, .textarea:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: 0 0 0 3px rgba(216, 108, 48, .16);
}

.input::placeholder { color: #9aa3af; }
.textarea { min-height: 5rem; resize: vertical; }

.field-error { margin-top: .25rem; font-size: .7rem; color: var(--danger); }

.checkbox {
    width: 1.05rem;
    height: 1.05rem;
    accent-color: var(--brand);
    cursor: pointer;
    vertical-align: middle;
}

/* Filter bar sitting above a table. */
.filter-bar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: .75rem;
    align-items: end;
    padding: 1rem 1.125rem;
    margin-bottom: 1.125rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
}

.filter-actions { display: flex; gap: .5rem; }

/* ===========================================================================
   Tables (incl. DataTables overrides)
   =========================================================================== */

.table-wrap {
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

table.dt {
    width: 100% !important;
    border-collapse: collapse;
    font-size: .8125rem;
}

table.dt thead th {
    position: relative;
    padding: .6875rem .75rem !important;
    background: var(--surface-3);
    border-bottom: 1px solid var(--border) !important;
    color: var(--ink-2);
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    text-align: left;
    white-space: nowrap;
}

table.dt tbody td {
    padding: .6875rem .75rem;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}

table.dt tbody tr:hover { background: var(--surface-2); }
table.dt tbody tr.is-selected { background: var(--brand-tint); }
table.dt tbody tr:last-child td { border-bottom: 0; }

.cell-strong { font-weight: 600; color: var(--ink); }
.cell-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cell-truncate { max-width: 15rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* IDs, dates and action groups must never wrap — the table scrolls instead. */
.cell-nowrap { white-space: nowrap; }

/* Secondary line under a cell's main value (a follow-up note under its badge).
   The max-width is the cap on how wide the note may push its column when the
   table is free to size itself to its content. */
.cell-sub { display: block; max-width: 14rem; font-size: .7rem; line-height: 1.35; }

/* Two lines, then an ellipsis. Declared after .cell-sub so the box display wins
   when a note carries both. */
.cell-clamp {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* The actions column pins to the right edge. A wide CRM table scrolls
   horizontally, and the row's actions must stay reachable without scrolling
   to find them. */
table.dt td.cell-actions,
table.dt thead th.th-actions {
    position: sticky;
    right: 0;
    z-index: 2;
    white-space: nowrap;
    background: var(--surface);
    box-shadow: -7px 0 9px -7px rgba(15, 23, 42, .22);
}

table.dt thead th.th-actions { background: var(--surface-3); z-index: 3; }
table.dt tbody tr:hover td.cell-actions { background: var(--surface-2); }
table.dt tbody tr.is-selected td.cell-actions { background: var(--brand-tint); }

/* On a phone the pinning has to stop. With every action inline the cell is
   ~350px wide, which on a 390px screen would sit over the whole row and hide
   the customer it belongs to. Unpinned, the table scrolls normally: the data
   reads first and the actions are a swipe to the right. */
@media (max-width: 767px) {
    table.dt td.cell-actions,
    table.dt thead th.th-actions {
        position: static;
        box-shadow: none;
    }
}

/* --- Fit-to-width tables -------------------------------------------------
   Opt in with `.table-wrap.is-fit` on the wrapper and `.dt-fit` on the table.

   The default table is as wide as its widest row, so the wrapper scrolls. A
   fit table is as wide as the page instead: a <colgroup> declares what share
   each column gets, and content that does not fit wraps onto a second line
   rather than pushing the row sideways. The quotations list needed this — nine
   columns plus nine action icons come to 1270px of table, which with the
   sidebar wants a 1600px window, so every smaller screen scrolled sideways and
   the scrollbar hid half of every row.

   The column widths live with the markup (the page that knows which columns it
   renders), not here. This block only makes the wrapping work. */

/* Everything here is behind the tablet breakpoint on purpose. Below it there is
   no width left to divide — nine columns in ~350px is a few broken characters
   each — so a phone keeps the default table and swipes sideways, which is the
   readable answer at that size. The <colgroup> has to be neutralised there too,
   or its percentages fight the auto layout. */

@media (max-width: 767px) {
    table.dt.dt-fit col { width: auto !important; }
}

@media (min-width: 768px) {

    table.dt.dt-fit { table-layout: fixed; }

    /* The table is exactly as wide as its wrapper, so the wrapper stops being a
       scroll container at all: a rounding error must not put the scrollbar back. */
    .table-wrap.is-fit { overflow-x: visible; }

    /* Fixed layout only assigns the widths — the cells still have to be allowed
       a second line. `break-word` and not `anywhere`: a word is broken only when
       it cannot fit a line of its own, so ordinary text wraps at its spaces. */
    table.dt.dt-fit thead th,
    table.dt.dt-fit tbody td {
        white-space: normal;
        overflow-wrap: break-word;
    }

    /* Numbers are the exception: never broken inside the number itself. A price
       split after the comma reads as a different price, and half a phone number
       is not a phone number. They wrap at a space if they have one and otherwise
       run into the gutter — which the column widths are set wide enough to
       avoid. These selectors carry three classes on purpose; the rule above has
       two, and would otherwise win. */
    table.dt.dt-fit tbody .nums,
    table.dt.dt-fit tbody .cell-num { overflow-wrap: normal; }

    /* Headers break at their spaces only — "Shared with" over two lines, never
       "Shar/ed with". They are short enough that a space is always enough. */
    table.dt.dt-fit thead th { overflow-wrap: normal; }

    /* And dates do not wrap at all — they are one short token with no good
       break in it. */
    table.dt.dt-fit tbody .cell-nowrap { white-space: nowrap; }

    /* A truncating cell keeps truncating: one line and an ellipsis, with the
       column deciding where that falls instead of the 15rem cap. */
    table.dt.dt-fit tbody .cell-truncate {
        max-width: none;
        white-space: nowrap;
    }

    /* A badge is a nowrap pill by design, which in a fixed column would push past
       its edge and over the next one. Capping it is not enough on its own: the
       pill is a flex box, so its icon and text refuse to shrink below their own
       width. The text has to be a flex item that may shrink — .badge-text — for
       the cap to bite. */
    table.dt.dt-fit .badge { max-width: 100%; }

    /* Narrower gutters: at nine columns every .25rem trimmed here is ~4.5rem of
       row width handed back to the content. */
    table.dt.dt-fit thead th { padding: .6875rem .5rem !important; }
    table.dt.dt-fit tbody td { padding: .625rem .5rem; }

    /* The select column is a checkbox wide and nothing more, so it gives its
       gutters back rather than crowding the checkbox out of its own cell. */
    table.dt.dt-fit .cell-select {
        padding-left: .25rem !important;
        padding-right: .25rem !important;
        text-align: center;
    }

    /* DataTables draws its sort arrows absolutely at `right: 10px` and expects
       the 30px of padding that our own padding rule overrides. Wrapped headers
       would run underneath them. */
    table.dt.dt-fit thead th.sorting,
    table.dt.dt-fit thead th.sorting_asc,
    table.dt.dt-fit thead th.sorting_desc { padding-right: 1.4rem !important; }

    /* Nothing scrolls, so the actions column has nothing to pin against — and a
       sticky shadow on a static table just draws a line through every row. */
    table.dt.dt-fit td.cell-actions,
    table.dt.dt-fit thead th.th-actions {
        position: static;
        box-shadow: none;
        white-space: normal;
    }

    /* The icons wrap into lines inside the column they are given, instead of the
       column having to be as wide as all of them in a row.

       26px and a 3px gap are not cosmetic: they are what puts five icons on a
       line in the ~165px the actions column gets on a 1280px screen. At the
       default 32px/.3rem only four fit, which costs a third line of icons on
       every row of the table. */
    table.dt.dt-fit .action-group {
        display: flex;
        flex-wrap: wrap;
        gap: 3px;
    }

    table.dt.dt-fit .icon-btn {
        width: 26px;
        height: 26px;
        font-size: .7rem;
    }
}

/* --- Row actions menu ---------------------------------------------------
   The list carried nine action icons per row, which overflowed the column.
   Four stay inline; the rest live behind this menu. */

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

/* Moved to <body> and positioned by JS while open — see initMenus().
   In the row it is unreachable: .table-wrap scrolls (so clips on both axes),
   and `right: 0` resolved against the sticky cell put the list at the right
   edge of the table's *scroll width*, i.e. far off-screen. Parenting it to the
   body escapes both, so these coordinates are plain viewport coordinates. */
.menu-list {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1000;
    display: none;
    min-width: 12rem;
    max-height: calc(100vh - 16px);
    overflow-y: auto;
    padding: .3rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow-lg);
    text-align: left;
}

/* On the list itself, not `.menu.is-open .menu-list` — while open the list is
   parented to <body>, so it is no longer a descendant of .menu. */
.menu-list.is-open { display: block; }

.menu-item {
    display: flex;
    align-items: center;
    gap: .55rem;
    width: 100%;
    padding: .4rem .5rem;
    border: 0;
    border-radius: 6px;
    background: none;
    font: inherit;
    font-size: .78rem;
    color: var(--ink-2);
    text-align: left;
    white-space: nowrap;
    cursor: pointer;
}

.menu-item i { width: 1rem; text-align: center; font-size: .75rem; opacity: .8; }
.menu-item:hover { background: var(--surface-3); color: var(--ink); }
.menu-item.is-danger { color: var(--danger); }
.menu-item.is-danger:hover { background: var(--danger-bg); }
.menu-sep { height: 1px; margin: .3rem .25rem; background: var(--border); }

/* Expandable master/detail row */
.row-expand { cursor: pointer; }
.row-expand .toggle-icon { transition: transform .2s; color: var(--ink-muted); }
.row-expand.is-expanded .toggle-icon { transform: rotate(90deg); }

.subtable-cell { padding: 0 !important; background: var(--surface-2); }
.subtable-wrap { padding: .875rem 1.25rem; }

table.subtable { width: 100%; border-collapse: collapse; font-size: .75rem; }

table.subtable th {
    padding: .5rem .625rem;
    background: var(--surface-3);
    border-bottom: 1px solid var(--border);
    color: var(--ink-2);
    font-size: .65rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    text-align: left;
}

table.subtable td { padding: .5rem .625rem; border-bottom: 1px solid var(--border); }
table.subtable tr:last-child td { border-bottom: 0; }

/* --- Version history: what changed between a version and the next ---------
   Old value struck through in red, new value in green, so a row can be read at
   a glance without comparing two documents. */
.chg { display: flex; flex-wrap: wrap; align-items: baseline; gap: .3rem; margin-bottom: .25rem; }
.chg:last-child { margin-bottom: 0; }

.chg-label { font-weight: 700; color: var(--ink); }

.chg-from,
.chg-to {
    padding: .05rem .3rem;
    border-radius: 3px;
    font-size: .7rem;
    word-break: break-word;
}

.chg-from { background: var(--danger-bg); color: var(--danger); text-decoration: line-through; }
.chg-to   { background: var(--ok-bg);     color: var(--ok);     font-weight: 600; }

.chg-arrow { color: var(--ink-muted); font-size: .58rem; }
.chg-more  { color: var(--ink-muted); font-size: .68rem; font-style: italic; }

/* "The original was replaced with this version", and its counterpart on the
   row that was replaced. */
.chg-note {
    margin-bottom: .3rem;
    padding: .15rem .35rem;
    border-radius: 3px;
    background: var(--warn-bg);
    color: var(--warn);
    font-size: .68rem;
    font-weight: 600;
}

.chg-note-ok { background: var(--ok-bg); color: var(--ok); }

.empty-state { padding: 2.5rem 1rem; text-align: center; color: var(--ink-muted); }
.empty-state i { font-size: 1.75rem; opacity: .35; display: block; margin-bottom: .625rem; }

/* DataTables chrome, restyled to match the rest of the UI. */
.dataTables_wrapper { padding: 0; }

/* Wrappers created by the custom dom string in app.js. */
.dt-top, .dt-bottom {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
}

.dt-top { border-bottom: 1px solid var(--border); }
.dt-bottom { border-top: 1px solid var(--border); }

.dt-top .dataTables_length,
.dt-top .dataTables_filter { padding: .75rem 1.125rem; }

.dt-bottom .dataTables_info { padding: .75rem 1.125rem; }
.dt-bottom .dataTables_paginate { padding: .5rem 1.125rem; }

.dataTables_wrapper .dataTables_filter { text-align: left !important; }
.dataTables_wrapper .dataTables_filter label { display: flex; align-items: center; gap: .4rem; }
.dataTables_wrapper .dataTables_filter input { margin: 0 !important; min-width: 12rem; }
.dataTables_wrapper .dataTables_length label { display: flex; align-items: center; gap: .4rem; }
.dataTables_wrapper .dataTables_length select { margin: 0 !important; }

.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter,
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_paginate {
    font-size: .75rem !important;
    color: var(--ink-2) !important;
}

.dataTables_wrapper .dataTables_length { padding: .875rem 1.125rem 0; }
.dataTables_wrapper .dataTables_filter { padding: .875rem 1.125rem 0; }
.dataTables_wrapper .dataTables_info { padding: .875rem 1.125rem; }
.dataTables_wrapper .dataTables_paginate { padding: .625rem 1.125rem .875rem; }

.dataTables_wrapper .dataTables_length select,
.dataTables_wrapper .dataTables_filter input {
    padding: .375rem .5rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--r-sm);
    background: var(--surface);
    font-size: .75rem;
}

.dataTables_wrapper .dataTables_filter input:focus,
.dataTables_wrapper .dataTables_length select:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: 0 0 0 3px rgba(216, 108, 48, .16);
}

.dataTables_wrapper .dataTables_paginate .paginate_button {
    padding: .3rem .55rem !important;
    margin: 0 .1rem !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--r-sm) !important;
    background: var(--surface) !important;
    color: var(--ink-2) !important;
}

.dataTables_wrapper .dataTables_paginate .paginate_button.current,
.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
    background: var(--brand) !important;
    border-color: var(--brand) !important;
    color: #fff !important;
}

.dataTables_wrapper .dataTables_paginate .paginate_button:hover {
    background: var(--surface-3) !important;
    color: var(--ink) !important;
}

.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover {
    opacity: .4;
    background: var(--surface) !important;
    color: var(--ink-muted) !important;
}

table.dt thead th.sorting,
table.dt thead th.sorting_asc,
table.dt thead th.sorting_desc { cursor: pointer; }

/* ===========================================================================
   Stat tiles / KPI row
   =========================================================================== */

/* Explicit column counts rather than auto-fit: with six tiles auto-fit lands on
   five across and leaves a single orphan on the second row.

   The count at the widest step is --kpi-cols, because it depends on the reader:
   an admin has seven tiles and a manager three, and the row is meant to stay one
   row. Seven is a prime, so at the two narrower steps it cannot divide evenly —
   the two :last-child rules below hand the leftover tile the rest of its row
   rather than leaving it stranded in the first column. */
.kpi-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .875rem;
    margin-bottom: 1.25rem;
}

/* Two columns: a last tile in an odd position is alone on its row. */
.kpi-row > :last-child:nth-child(odd) { grid-column: 1 / -1; }

@media (min-width: 760px) {
    .kpi-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }

    /* Three columns: the same condition reads "in the first column, and last". */
    .kpi-row > :last-child:nth-child(odd) { grid-column: auto; }
    .kpi-row > :last-child:nth-child(3n + 1) { grid-column: 1 / -1; }
}

@media (min-width: 1560px) {
    .kpi-row { grid-template-columns: repeat(var(--kpi-cols, 6), minmax(0, 1fr)); }

    /* Every tile has a column of its own here, so nothing spans. */
    .kpi-row > :last-child:nth-child(3n + 1) { grid-column: auto; }
}

.stat {
    position: relative;
    padding: 1.125rem 1.25rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

.stat::after {
    content: '';
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: var(--stat-accent, var(--brand));
}

.stat-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    margin-bottom: .5rem;
}

.stat-label {
    font-size: .6875rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-muted);
}

.stat-icon {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    flex: none;
    border-radius: var(--r-sm);
    background: var(--stat-icon-bg, var(--brand-tint));
    color: var(--stat-accent, var(--brand));
    font-size: .8rem;
}

.stat-value {
    font-size: 1.625rem;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -.02em;
    color: var(--ink);
}

.stat-sub { margin-top: .3rem; font-size: .72rem; color: var(--ink-muted); }

/* A tile that is itself a link. The whole tile is the target rather than a
   phrase inside it: the tile is what the reader aims at, and it is twenty times
   the area. Styled on the element, so a page only has to write <a class="stat">. */
a.stat {
    display: block;
    color: inherit;
    transition: border-color .15s, box-shadow .15s, transform .15s;
}

a.stat:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow);
    transform: translateY(-1px);
}

/* The arrow in the sub-line is the affordance — it moves with the hover. */
a.stat .stat-sub i { transition: transform .15s; }
a.stat:hover .stat-sub i { transform: translateX(2px); }

@media (prefers-reduced-motion: reduce) {
    a.stat, a.stat .stat-sub i { transition: none; }
    a.stat:hover { transform: none; }
    a.stat:hover .stat-sub i { transform: none; }
}

/* The one number a page leads with. */
.hero-figure {
    font-size: 3rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -.03em;
}

/* ===========================================================================
   Charts
   ---------------------------------------------------------------------------
   Mark specs from the dataviz reference: thin marks, 2px lines, >=8px
   markers, 2px surface gap between adjacent fills, recessive grid/axes.
   =========================================================================== */

.chart { position: relative; }
.chart svg { display: block; width: 100%; height: auto; overflow: visible; }

.chart-grid line { stroke: var(--grid); stroke-width: 1; }
.chart-axis line, .chart-axis path { stroke: var(--axis); stroke-width: 1; }

.chart-tick {
    font-size: 10px;
    fill: var(--ink-muted);
    font-variant-numeric: tabular-nums;
}

.chart-label { font-size: 10.5px; fill: var(--ink-2); }

.chart-value {
    font-size: 10.5px;
    font-weight: 600;
    fill: var(--ink);
    font-variant-numeric: tabular-nums;
}

/* 4px rounded data-end anchored to the baseline. */
.bar { fill: var(--series-1); transition: opacity .15s; }
.bar:hover { opacity: .82; }

.line-mark {
    fill: none;
    stroke: var(--series-1);
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.area-mark { fill: var(--series-1); opacity: .1; }

.dot-mark {
    fill: var(--surface);
    stroke: var(--series-1);
    stroke-width: 2;
}

.chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: .375rem 1rem;
    margin-top: .875rem;
}

.legend-item {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    font-size: .72rem;
    color: var(--ink-2);
}

.legend-swatch {
    width: 10px;
    height: 10px;
    flex: none;
    border-radius: 3px;
}

.legend-value { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }

/* Horizontal stacked bar used for the follow-up mix. */
.stackbar {
    display: flex;
    width: 100%;
    height: 30px;
    gap: 2px;                    /* the required 2px surface gap */
    border-radius: 6px;
    overflow: hidden;
}

.stackbar-seg {
    display: grid;
    place-items: center;
    min-width: 2px;
    font-size: .68rem;
    font-weight: 600;
    color: #fff;
    transition: filter .15s;
}

.stackbar-seg:hover { filter: brightness(1.08); }

/* Ranked horizontal bars (top performers). */
.rank-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: .5rem .75rem;
    align-items: center;
    padding: .5rem 0;
    border-bottom: 1px solid var(--border);
}

.rank-row:last-child { border-bottom: 0; }
.rank-name { font-size: .8125rem; font-weight: 500; }
.rank-meta { font-size: .7rem; color: var(--ink-muted); }

.rank-track {
    grid-column: 1 / -1;
    height: 6px;
    border-radius: 999px;
    background: var(--surface-3);
    overflow: hidden;
}

.rank-fill { height: 100%; border-radius: 999px; background: var(--series-1); }

/* Tooltip shared by every chart. */
.chart-tip {
    position: fixed;
    z-index: 90;
    display: none;
    max-width: 220px;
    padding: .5rem .625rem;
    border-radius: var(--r-sm);
    background: #0f172a;
    color: #fff;
    font-size: .72rem;
    line-height: 1.4;
    box-shadow: var(--shadow-lg);
    pointer-events: none;
}

.chart-tip.is-visible { display: block; }
.chart-tip b { font-weight: 600; }
.chart-tip .tip-val { font-variant-numeric: tabular-nums; }

/* The table view that fulfils the sub-3:1 relief obligation. */
.chart-table-toggle {
    margin-top: .625rem;
    border: 0;
    background: none;
    padding: 0;
    color: var(--ink-muted);
    font: inherit;
    font-size: .7rem;
    text-decoration: underline;
    cursor: pointer;
}

.chart-table-toggle:hover { color: var(--ink-2); }
.chart-table { margin-top: .625rem; }
.chart-table[hidden] { display: none; }

.chart-table table { width: 100%; border-collapse: collapse; font-size: .72rem; }
.chart-table th, .chart-table td { padding: .3rem .5rem; border-bottom: 1px solid var(--border); text-align: left; }
.chart-table th { color: var(--ink-muted); font-weight: 600; }
.chart-table td:last-child, .chart-table th:last-child { text-align: right; font-variant-numeric: tabular-nums; }

/* ===========================================================================
   Modal
   =========================================================================== */

.modal {
    position: fixed;
    inset: 0;
    z-index: 80;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: rgba(15, 23, 42, .55);
    backdrop-filter: blur(2px);
}

.modal.is-open { display: flex; }

.modal-panel {
    width: 100%;
    max-width: 30rem;
    max-height: 90vh;
    overflow-y: auto;
    background: var(--surface);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
}

.modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--border);
}

.modal-head h3 { font-size: 1rem; }
.modal-body { padding: 1.25rem; }

.modal-foot {
    display: flex;
    justify-content: flex-end;
    gap: .5rem;
    padding: .875rem 1.25rem;
    border-top: 1px solid var(--border);
    background: var(--surface-2);
    border-radius: 0 0 var(--r-lg) var(--r-lg);
}

.modal-row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: .4rem 0;
    font-size: .8125rem;
    border-bottom: 1px solid var(--border);
}

.modal-row:last-of-type { border-bottom: 0; }
.modal-row dt { color: var(--ink-muted); }
.modal-row dd { margin: 0; font-weight: 500; text-align: right; }

/* ===========================================================================
   Quotation form (create.php / edit.php)
   ---------------------------------------------------------------------------
   Both pages defined these same class names with slightly different values.
   Unified here so the two forms finally look identical.
   =========================================================================== */

.form-container {
    max-width: 68rem;
    margin: 0 auto;
    padding: 1.5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
}

.section {
    padding: 1.25rem;
    margin-bottom: 1.25rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
    box-shadow: var(--shadow-sm);
}

.itinerary-card {
    padding: 1.125rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
    box-shadow: var(--shadow-sm);
    transition: box-shadow .2s, transform .2s;
}

.itinerary-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

.error-text {
    margin-top: .25rem;
    font-size: .75rem;
    color: var(--danger);
}

.dynamic-section {
    padding: 1rem;
    margin-top: 1rem;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
}

.remove-btn {
    display: inline-grid;
    place-items: center;
    width: 32px;
    height: 32px;
    flex: none;
    border: 0;
    border-radius: 999px;
    background: var(--danger-bg);
    color: var(--danger);
    font-weight: 700;
    cursor: pointer;
    transition: background .15s, color .15s;
}

.remove-btn:hover { background: var(--danger); color: #fff; }

.image-preview {
    max-width: 120px;
    max-height: 120px;
    margin-top: .5rem;
    object-fit: cover;
    border: 1px solid var(--border-strong);
    border-radius: var(--r-sm);
}

/* The two form pages were written against Tailwind form classes rather than
   the design system's .input/.select. Style them by element so they match the
   rest of the CRM without touching thousands of lines of markup. */
.form-container input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
.form-container select,
.form-container textarea,
.section input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
.section select,
.section textarea {
    font-family: inherit;
    font-size: .8125rem;
    color: var(--ink);
    border-color: var(--border-strong) !important;
    border-radius: var(--r-sm) !important;
}

.form-container input:focus,
.form-container select:focus,
.form-container textarea:focus,
.section input:focus,
.section select:focus,
.section textarea:focus {
    outline: none;
    border-color: var(--brand) !important;
    box-shadow: 0 0 0 3px rgba(216, 108, 48, .16);
}

/* ===========================================================================
   Auth pages (login / register / password reset)
   =========================================================================== */

.auth-shell {
    display: grid;
    place-items: center;
    min-height: 100vh;
    padding: 1.25rem;
    background:
        linear-gradient(135deg, rgba(216, 108, 48, .92), rgba(147, 65, 26, .92)),
        var(--page);
}

.auth-card {
    width: 100%;
    max-width: 25rem;
    padding: 1.75rem;
    background: var(--surface);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
}

.auth-brand { text-align: center; margin-bottom: 1.5rem; }

.auth-mark {
    display: grid;
    place-items: center;
    width: 48px;
    height: 48px;
    margin: 0 auto .75rem;
    border-radius: 14px;
    background: var(--brand);
    color: #fff;
    font-weight: 700;
    font-size: .9rem;
}

.auth-brand h1 { font-size: 1.125rem; }
.auth-brand p { margin: .2rem 0 0; font-size: .78rem; color: var(--ink-muted); }

.auth-foot {
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border);
    text-align: center;
    font-size: .78rem;
    color: var(--ink-muted);
}

.auth-foot a { color: var(--brand-dark); font-weight: 500; }
.auth-foot a:hover { text-decoration: underline; }

/* Login has its own calm, professional treatment. It intentionally does not
   inherit the application orange so the sign-in experience stays neutral. */
.auth-shell--login {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    background:
        radial-gradient(circle at 12% 15%, rgba(59, 130, 246, .34), transparent 31rem),
        radial-gradient(circle at 90% 85%, rgba(20, 184, 166, .18), transparent 28rem),
        linear-gradient(135deg, #0b1220 0%, #111e36 52%, #172554 100%);
}

.auth-shell--login::before,
.auth-shell--login::after {
    content: '';
    position: absolute;
    z-index: -1;
    width: 26rem;
    height: 26rem;
    border: 1px solid rgba(191, 219, 254, .13);
    border-radius: 50%;
}

.auth-shell--login::before { top: -14rem; right: -8rem; }
.auth-shell--login::after { bottom: -17rem; left: -10rem; width: 34rem; height: 34rem; }

.auth-shell--login .auth-card {
    max-width: 26rem;
    padding: 2.25rem;
    border: 1px solid rgba(255, 255, 255, .72);
    border-radius: 1.25rem;
    box-shadow: 0 24px 60px rgba(2, 6, 23, .34);
}

.auth-shell--login .auth-brand { margin-bottom: 1.85rem; }

.auth-shell--login .auth-mark {
    width: 54px;
    height: 54px;
    margin-bottom: .9rem;
    border-radius: 16px;
    background: linear-gradient(135deg, #2563eb, #1e40af);
    box-shadow: 0 10px 22px rgba(37, 99, 235, .28);
    letter-spacing: .04em;
}

.auth-shell--login .auth-brand h1 { color: #0f172a; font-size: 1.35rem; letter-spacing: -.025em; }
.auth-shell--login .auth-brand p { color: #64748b; font-size: .82rem; }
.auth-shell--login .label { color: #334155; font-size: .8rem; font-weight: 600; }

.auth-shell--login .input,
.auth-shell--login .select {
    min-height: 2.8rem;
    border-color: #cbd5e1;
    border-radius: .65rem;
    background: #f8fafc;
}

.auth-shell--login .input:focus,
.auth-shell--login .select:focus {
    border-color: #2563eb !important;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, .14) !important;
}

.auth-shell--login .btn-primary {
    min-height: 2.9rem;
    border: 0;
    border-radius: .65rem;
    background: #1d4ed8;
    box-shadow: 0 8px 16px rgba(29, 78, 216, .22);
}

.auth-shell--login .btn-primary:hover { background: #1e40af; }
.auth-shell--login .auth-foot { margin-top: 1.5rem; border-color: #e2e8f0; }
.auth-shell--login .auth-foot a { color: #1d4ed8; }

@media (max-width: 480px) {
    .auth-shell--login { padding: 1rem; }
    .auth-shell--login .auth-card { padding: 1.6rem; }
}

/* ===========================================================================
   Utilities
   =========================================================================== */

.grid-2 { display: grid; grid-template-columns: 1fr; gap: 1rem; }

/* align-items: start so a short card keeps its natural height instead of being
   stretched to match a taller neighbour and showing a block of dead space. */
.grid-3 { display: grid; grid-template-columns: 1fr; gap: 1rem; align-items: start; }

@media (min-width: 900px) {
    .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1200px) {
    .grid-3 { grid-template-columns: 5fr 3fr; }
}

.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;
}

@media print {
    .sidebar, .topbar, .sidebar-overlay, .page-actions, .filter-bar { display: none !important; }
    .app-main { margin-left: 0 !important; }
    .card { box-shadow: none; border-color: #ccc; }
}
