/* =============================================================================
   Prestige Properties — Design System
   -----------------------------------------------------------------------------
   Single source of truth for the visual language of the public site and the
   client / agent / admin workspaces.

   Cascade layers, in ascending order of priority:

     ds-base       element resets and defaults. Deliberately the WEAKEST layer:
                   a reset like `img { height: auto }` must never beat a legacy
                   component rule like `.site-header .site-logo { height: 64px }`.
     vendor        third-party CSS (Font Awesome), imported into a layer so it
                   cannot outrank the application's own rules.
     legacy        the pre-existing stylesheets, wrapped in place. Rules are
                   deleted from them as this file grows to cover them.
     ds-tokens     the token definitions, so they win over the four conflicting
                   `:root` blocks still present in the legacy files.
     ds-components the new component layer, which wins over legacy outright.

   Because the order is declared explicitly below, it does not depend on the
   order the stylesheets happen to be linked in.
   ============================================================================ */

@layer ds-base, vendor, legacy, ds-tokens, ds-components;

/* Font Awesome is pulled in here rather than via its own <link> so it lands in
   a layer. Left unlayered it outranks every layered rule in the cascade, and
   `.fa-solid { display: ... }` would beat `.stat-card > i { display: grid }`,
   knocking every icon out of the centre of its tile. */
@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css") layer(vendor);

@layer ds-tokens {

    /* =============================================================================
       1. TOKENS
       ============================================================================ */

    :root {
        /* --- Brand -------------------------------------------------------------
           A deep, muted forest green. Not the saturated #0F7A3B the legacy token
           blocks declared: that value was overridden everywhere in practice and
           never actually rendered. */
        --pp-green-050: #edf3ee;
        --pp-green-100: #dce8de;
        --pp-green-200: #b9cfbd;
        --pp-green-400: #4f8069;
        --pp-green-500: #235b48;  /* primary */
        --pp-green-600: #1c4b3b;
        --pp-green-700: #173e32;  /* sidebar, footer */
        --pp-green-800: #102e25;
        --pp-green-900: #0a2018;

        /* Accent — warm brass, used sparingly for emphasis on dark grounds. */
        --pp-accent-100: #f4ead2;
        --pp-accent-200: #e1d7b9;
        --pp-accent-500: #b48b42;
        --pp-accent-700: #8a6a32;

        /* --- Neutrals ---------------------------------------------------------- */
        --pp-ink:        #20382e;  /* primary text */
        --pp-ink-2:      #3d5147;  /* secondary text */
        --pp-muted:      #6d776f;  /* tertiary text, labels */
        --pp-muted-2:    #8b948c;  /* placeholder, disabled */
        --pp-line:       #e1e5dc;  /* default border */
        --pp-line-2:     #edf0e8;  /* subtle divider */
        --pp-surface:    #ffffff;  /* cards, panels */
        --pp-surface-2:  #f7f9f4;  /* inset / hover surface */
        --pp-canvas:     #f5f5ef;  /* page background */

        /* --- Status ------------------------------------------------------------ */
        --pp-success-050: #e9f6ee;  --pp-success-500: #1f7a4d;  --pp-success-700: #125836;
        --pp-warning-050: #fdf4e3;  --pp-warning-500: #a15c07;  --pp-warning-700: #7a4505;
        --pp-danger-050:  #fdecec;  --pp-danger-500:  #b42318;  --pp-danger-700:  #8c1a12;
        --pp-info-050:    #eaf1f7;  --pp-info-500:    #2c5f8a;  --pp-info-700:    #1f4666;

        /* --- Typography --------------------------------------------------------
           Two families only. Georgia carries the brand voice in headlines; the
           system sans stack carries all UI and body copy. Plus Jakarta Sans was
           being downloaded but never referenced — the link has been removed. */
        --pp-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                        "Helvetica Neue", Arial, sans-serif;
        --pp-font-serif: Georgia, "Times New Roman", Times, serif;
        --pp-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
                        "Liberation Mono", monospace;

        /* Type scale — 1.200 minor third, 13px base for dense UI. */
        --pp-text-3xs: 0.625rem;  /* 10px  eyebrows, table headers */
        --pp-text-2xs: 0.6875rem; /* 11px  meta, captions */
        --pp-text-xs:  0.75rem;   /* 12px  labels, badges */
        --pp-text-sm:  0.8125rem; /* 13px  UI default */
        --pp-text-md:  0.875rem;  /* 14px  body */
        --pp-text-lg:  1rem;      /* 16px  lead */
        --pp-text-xl:  1.1875rem; /* 19px  card titles */
        --pp-text-2xl: 1.375rem;  /* 22px  page titles */
        --pp-text-3xl: 1.75rem;   /* 28px  section titles */
        --pp-text-4xl: 2.25rem;   /* 36px  display */

        --pp-leading-tight: 1.2;
        --pp-leading-snug:  1.45;
        --pp-leading-normal: 1.6;
        --pp-leading-relaxed: 1.75;

        --pp-tracking-eyebrow: 0.16em;
        --pp-tracking-display: -0.035em;

        /* --- Space — 4px base ---------------------------------------------------
           Replaces the ad-hoc 5/7/9/11/13/17/22/25/26/30px values scattered
           through the legacy files. */
        --pp-space-1:  0.25rem;  /*  4px */
        --pp-space-2:  0.5rem;   /*  8px */
        --pp-space-3:  0.75rem;  /* 12px */
        --pp-space-4:  1rem;     /* 16px */
        --pp-space-5:  1.25rem;  /* 20px */
        --pp-space-6:  1.5rem;   /* 24px */
        --pp-space-8:  2rem;     /* 32px */
        --pp-space-10: 2.5rem;   /* 40px */
        --pp-space-12: 3rem;     /* 48px */
        --pp-space-16: 4rem;     /* 64px */
        --pp-space-20: 5rem;     /* 80px */

        /* --- Radius — 5 steps, down from ten ad-hoc values ---------------------- */
        --pp-radius-sm:   6px;
        --pp-radius-md:   10px;
        --pp-radius-lg:   14px;
        --pp-radius-xl:   20px;
        --pp-radius-full: 999px;

        /* --- Elevation ---------------------------------------------------------
           Green-tinted rather than neutral grey, so shadows sit in the palette. */
        --pp-shadow-xs: 0 1px 2px rgba(32, 56, 46, 0.05);
        --pp-shadow-sm: 0 2px 8px rgba(32, 56, 46, 0.05);
        --pp-shadow-md: 0 4px 16px rgba(32, 56, 46, 0.07);
        --pp-shadow-lg: 0 12px 32px rgba(32, 56, 46, 0.10);
        --pp-shadow-xl: 0 18px 65px rgba(21, 51, 41, 0.15);
        --pp-ring: 0 0 0 3px rgba(35, 91, 72, 0.18);

        /* --- Motion ------------------------------------------------------------ */
        --pp-ease: cubic-bezier(0.4, 0, 0.2, 1);
        --pp-duration-fast: 120ms;
        --pp-duration-base: 200ms;
        --pp-duration-slow: 320ms;

        /* --- Layout ------------------------------------------------------------ */
        --pp-sidebar-w: 264px;
        --pp-topbar-h: 92px;
        /* Drives both the header's own height and the offset of everything
           that sticks below it, so the two can never drift apart. */
        --pp-header-h: 96px;
        --pp-container: 1200px;
        --pp-container-wide: 1360px;
        --pp-content-max: 1600px;

        /* --- Control sizing ----------------------------------------------------
           44px is the minimum comfortable touch target. */
        --pp-control-h: 44px;
        --pp-control-h-sm: 36px;
        --pp-control-h-lg: 52px;

        /* --- Z-index scale ----------------------------------------------------- */
        --pp-z-sticky:   100;  /* topbar, site header */
        --pp-z-backdrop: 200;  /* dimmer behind a drawer - must sit BELOW it */
        --pp-z-drawer:   300;  /* sidebar drawer, mobile menu */
        --pp-z-popover:  400;  /* notification panel */
        --pp-z-modal:    500;
        --pp-z-toast:    600;
    }

    /* -----------------------------------------------------------------------------
       Legacy token aliases.

       The legacy stylesheets reference three parallel naming schemes for the same
       concepts (--green / --pp-green / --primary-green). Rather than find-and-replace
       across 6,000 lines up front, every alias is pointed at the canonical token
       here. Legacy rules therefore render in the correct palette immediately, and
       the aliases can be deleted once the rules that use them are gone.
       -------------------------------------------------------------------------- */
    :root {
        --green:         var(--pp-green-500);
        --green-600:     var(--pp-green-600);
        --green-700:     var(--pp-green-700);
        --green-050:     var(--pp-green-050);
        --primary-green: var(--pp-green-500);
        --dark-green:    var(--pp-green-700);
        --light-green:   var(--pp-green-050);
        --pp-green:      var(--pp-green-500);
        --pp-dark:       var(--pp-green-700);

        --ink:    var(--pp-ink);
        --ink-2:  var(--pp-ink-2);
        --muted:  var(--pp-muted);
        --line:   var(--pp-line);
        --line-2: var(--pp-line-2);
        --border: var(--pp-line);
        --surface: var(--pp-surface);
        --canvas:  var(--pp-canvas);
        --page-bg: var(--pp-canvas);
        --black:   var(--pp-ink);
        --white:   var(--pp-surface);

        --sidebar-1: var(--pp-green-700);
        --sidebar-2: var(--pp-green-900);
        --sidebar-w: var(--pp-sidebar-w);

        --danger:      var(--pp-danger-500);
        --danger-050:  var(--pp-danger-050);
        --amber:       var(--pp-warning-500);
        --amber-050:   var(--pp-warning-050);
        --warning:     var(--pp-warning-500);

        --radius:    var(--pp-radius-lg);
        --radius-sm: var(--pp-radius-md);
        --radius-md: var(--pp-radius-md);
        --radius-lg: var(--pp-radius-lg);

        --shadow:      var(--pp-shadow-lg);
        --shadow-sm:   var(--pp-shadow-xs);
        --shadow-1:    var(--pp-shadow-xs);
        --shadow-2:    var(--pp-shadow-md);
        --shadow-card: var(--pp-shadow-sm);
        --shadow-pop:  var(--pp-shadow-xl);
        --ring:        var(--pp-ring);

        --font:    var(--pp-font-sans);
        --pp-font: var(--pp-font-sans);
    }

}

@layer ds-base {

    /* =============================================================================
       2. BASE
       ============================================================================ */

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

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

    html, body { max-width: 100%; }

    body {
        margin: 0;
        background: var(--pp-canvas);
        color: var(--pp-ink);
        font-family: var(--pp-font-sans);
        font-size: var(--pp-text-md);
        line-height: var(--pp-leading-normal);
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
    }

    /* Deliberately NOT `overflow-x: hidden` on body. It hides sideways overflow
       instead of fixing it: the offending element is still there, just clipped
       off-screen and unreachable, and it makes the breakage invisible to
       automated checks because documentElement.scrollWidth stops growing. */

    /* Headings carry the serif brand voice. Sizes are set per-context rather than
       globally, so only the shared characteristics live here. */
    h1, h2, h3, h4, h5, h6 {
        margin: 0;
        font-family: var(--pp-font-serif);
        font-weight: 400;
        line-height: var(--pp-leading-tight);
        letter-spacing: var(--pp-tracking-display);
        color: var(--pp-ink);
    }

    /* Small headings read better in the sans stack — at these sizes the serif
       looks like a mistake rather than a choice. */
    h4, h5, h6 {
        font-family: var(--pp-font-sans);
        font-weight: 600;
        letter-spacing: 0;
        line-height: var(--pp-leading-snug);
    }

    p { margin: 0 0 var(--pp-space-4); }
    p:last-child { margin-bottom: 0; }

    a { color: var(--pp-green-500); text-decoration: none; }
    a:hover { color: var(--pp-green-700); }

    img, video, iframe, svg { max-width: 100%; }
    img, video { height: auto; }
    img { border-style: none; }

    ul, ol { margin: 0 0 var(--pp-space-4); padding-left: var(--pp-space-5); }
    ul:last-child, ol:last-child { margin-bottom: 0; }

    hr {
        border: 0;
        border-top: 1px solid var(--pp-line);
        margin: var(--pp-space-6) 0;
    }

    code, pre, kbd, samp { font-family: var(--pp-font-mono); font-size: 0.9em; }

    table { border-collapse: collapse; border-spacing: 0; }

    /* Form controls do not inherit typography by default. */
    button, input, select, textarea { font: inherit; color: inherit; margin: 0; }
    button { background: none; border: 0; cursor: pointer; }
    textarea { resize: vertical; }

    /* Remove the grey flash on tap without removing the focus ring. */
    button, a, input, select, textarea, [role="button"] {
        -webkit-tap-highlight-color: transparent;
    }

    /* A single, consistent focus treatment. Brass reads clearly on both the light
       canvas and the dark sidebar. */
    :focus { outline: none; }
    :focus-visible {
        outline: 3px solid var(--pp-accent-500);
        outline-offset: 3px;
        border-radius: var(--pp-radius-sm);
    }

    ::selection { background: var(--pp-green-100); color: var(--pp-green-900); }

    [hidden] { display: none !important; }

    /* Skip link — visually hidden until focused. */
    .skip-link {
        position: fixed;
        left: var(--pp-space-4);
        top: -100px;
        z-index: var(--pp-z-toast);
        padding: var(--pp-space-3) var(--pp-space-5);
        background: var(--pp-surface);
        color: var(--pp-green-700);
        font-size: var(--pp-text-sm);
        font-weight: 600;
        border-radius: var(--pp-radius-md);
        box-shadow: var(--pp-shadow-lg);
        transition: top var(--pp-duration-base) var(--pp-ease);
    }
    .skip-link:focus { top: var(--pp-space-3); }

    /* Thin, palette-matched scrollbars for scroll regions inside the UI. */
    .pp-scroll, .app-nav, .notification-list, .table-wrap {
        scrollbar-width: thin;
        scrollbar-color: var(--pp-green-200) transparent;
    }
    .pp-scroll::-webkit-scrollbar,
    .app-nav::-webkit-scrollbar,
    .notification-list::-webkit-scrollbar,
    .table-wrap::-webkit-scrollbar { width: 8px; height: 8px; }
    .pp-scroll::-webkit-scrollbar-thumb,
    .app-nav::-webkit-scrollbar-thumb,
    .notification-list::-webkit-scrollbar-thumb,
    .table-wrap::-webkit-scrollbar-thumb {
        background: var(--pp-green-200);
        border-radius: var(--pp-radius-full);
    }

    @media (prefers-reduced-motion: reduce) {
        html { scroll-behavior: auto; }
        *, *::before, *::after {
            animation-duration: 0.01ms !important;
            animation-iteration-count: 1 !important;
            transition-duration: 0.01ms !important;
        }
    }

}

@layer ds-components {

    /* =========================================================================
       DATA TABLE
       -------------------------------------------------------------------------
       Wide tables are unreadable on a phone. Below the breakpoint each row
       becomes a self-contained card: the first cell is the card heading, every
       other cell becomes a label/value pair, and the action cell moves to the
       foot of the card.

       Labels come from the matching <th>, copied onto each <td> as data-label
       by prestige-ui.js. Tables that opt out carry .data-table--keep.
       ====================================================================== */

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

    .data-table {
        width: 100%;
        border-collapse: separate;
        border-spacing: 0;
        font-size: var(--pp-text-sm);
    }

    .data-table th {
        padding: var(--pp-space-3) var(--pp-space-4);
        background: var(--pp-surface-2);
        color: var(--pp-muted);
        font-family: var(--pp-font-sans);
        font-size: var(--pp-text-3xs);
        font-weight: 700;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        text-align: left;
        white-space: nowrap;
        border-bottom: 1px solid var(--pp-line);
    }
    .data-table th:first-child { border-top-left-radius: var(--pp-radius-md); }
    .data-table th:last-child  { border-top-right-radius: var(--pp-radius-md); }

    .data-table td {
        /* 16px each side left too little room in a five-column panel: short
           words like "Physical" no longer fit and wrapped mid-word. */
        padding: var(--pp-space-3) var(--pp-space-4);
        border-bottom: 1px solid var(--pp-line-2);
        vertical-align: middle;
        overflow-wrap: break-word;
    }
    /* Machine strings (references, emails, file names) have no natural break
       point, so those cells keep `anywhere`. */
    .data-table td .ref, .data-table td code, .data-table td .muted-text { overflow-wrap: anywhere; }
    .data-table tbody tr:last-child td { border-bottom: 0; }
    .data-table tbody tr { transition: background var(--pp-duration-fast) var(--pp-ease); }
    .data-table tbody tr:hover { background: var(--pp-surface-2); }

    .data-table .table-actions { text-align: right; white-space: nowrap; }

    @media (max-width: 860px) {
        .table-wrap:has(.data-table:not(.data-table--keep)) { overflow-x: visible; }

        /* The legacy responsive partial pins tables to min-width:680px so they
           scroll sideways. That is exactly what the card layout replaces. */
        .data-table:not(.data-table--keep) {
            display: block;
            min-width: 0;
            font-size: var(--pp-text-md);
        }
        .data-table:not(.data-table--keep) tbody { display: block; }

        /* Header labels are reproduced per cell, so hide the row without
           removing it from the accessibility tree. */
        .data-table:not(.data-table--keep) thead {
            position: absolute;
            width: 1px; height: 1px;
            margin: -1px; padding: 0;
            overflow: hidden;
            clip-path: inset(50%);
            white-space: nowrap;
        }

        .data-table:not(.data-table--keep) tbody tr {
            display: block;
            margin-bottom: var(--pp-space-3);
            padding: var(--pp-space-2) var(--pp-space-4);
            background: var(--pp-surface);
            border: 1px solid var(--pp-line);
            border-radius: var(--pp-radius-lg);
            box-shadow: var(--pp-shadow-xs);
        }
        .data-table:not(.data-table--keep) tbody tr:last-child { margin-bottom: 0; }
        .data-table:not(.data-table--keep) tbody tr:hover { background: var(--pp-surface); }

        .data-table:not(.data-table--keep) td {
            display: grid;
            grid-template-columns: minmax(0, 8.5rem) minmax(0, 1fr);
            gap: var(--pp-space-4);
            align-items: baseline;
            /* Grid items are blockified, which would stretch a pill-shaped
               badge across the whole value column. */
            justify-items: start;
            padding: var(--pp-space-3) 0;
            border-bottom: 1px solid var(--pp-line-2);
            text-align: left;
        }
        .data-table:not(.data-table--keep) td::before {
            content: attr(data-label);
            color: var(--pp-muted);
            font-size: var(--pp-text-2xs);
            font-weight: 700;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            line-height: var(--pp-leading-snug);
        }
        /* Cells with no label span the full width rather than leaving a gap. */
        .data-table:not(.data-table--keep) td:not([data-label]),
        .data-table:not(.data-table--keep) td[data-label=""] { display: block; }
        .data-table:not(.data-table--keep) td:not([data-label])::before,
        .data-table:not(.data-table--keep) td[data-label=""]::before { content: none; }

        /* First cell is the card heading. */
        .data-table:not(.data-table--keep) td:first-child {
            display: block;
            padding-top: var(--pp-space-3);
            font-size: var(--pp-text-md);
        }
        .data-table:not(.data-table--keep) td:first-child::before { content: none; }

        /* Action cell sits at the foot, full width, no divider. Not every table
           marks it with .table-actions, so any trailing cell holding controls
           is treated the same way. */
        .data-table:not(.data-table--keep) td:last-child {
            border-bottom: 0;
            padding-bottom: var(--pp-space-3);
        }
        .data-table:not(.data-table--keep) td.table-actions,
        .data-table:not(.data-table--keep) td:has(> .btn),
        .data-table:not(.data-table--keep) td:has(> form),
        .data-table:not(.data-table--keep) td:has(> .action-row),
        .data-table:not(.data-table--keep) td:has(> .table-actions) {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            gap: var(--pp-space-2);
            text-align: left;
            white-space: normal;
            padding-top: var(--pp-space-4);
        }
        .data-table:not(.data-table--keep) td.table-actions::before,
        .data-table:not(.data-table--keep) td:has(> .btn)::before,
        .data-table:not(.data-table--keep) td:has(> form)::before,
        .data-table:not(.data-table--keep) td:has(> .action-row)::before,
        .data-table:not(.data-table--keep) td:has(> .table-actions)::before { content: none; }

        /* Controls share the row and wrap rather than running off the edge. */
        .data-table:not(.data-table--keep) td.table-actions > *,
        .data-table:not(.data-table--keep) td:has(> .btn) > * { flex: 0 1 auto; min-width: 0; }
        .data-table:not(.data-table--keep) td .btn { white-space: nowrap; }

        /* Nested action wrappers must not impose their own desktop widths. */
        .data-table:not(.data-table--keep) td .action-row,
        .data-table:not(.data-table--keep) td .table-actions {
            display: flex;
            flex-wrap: wrap;
            gap: var(--pp-space-2);
            width: 100%;
        }

        /* An empty-state row must not be dressed up as a record card. */
        .data-table:not(.data-table--keep) tbody tr:has(td[colspan]) {
            border: 0; box-shadow: none; background: transparent; padding: 0;
        }
        .data-table:not(.data-table--keep) td[colspan] {
            display: block; border-bottom: 0; padding: 0;
        }
        .data-table:not(.data-table--keep) td[colspan]::before { content: none; }
    }

}

@layer ds-components {

    /* =========================================================================
       BUTTON
       ====================================================================== */

    .btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: var(--pp-space-2);
        min-height: var(--pp-control-h);
        padding: var(--pp-space-2) var(--pp-space-5);
        border: 1px solid transparent;
        border-radius: var(--pp-radius-md);
        background: transparent;
        color: var(--pp-ink);
        font-family: var(--pp-font-sans);
        font-size: var(--pp-text-sm);
        font-weight: 600;
        line-height: 1.2;
        text-align: center;
        text-decoration: none;
        white-space: nowrap;
        cursor: pointer;
        transition: background var(--pp-duration-fast) var(--pp-ease),
                    border-color var(--pp-duration-fast) var(--pp-ease),
                    color var(--pp-duration-fast) var(--pp-ease),
                    box-shadow var(--pp-duration-fast) var(--pp-ease);
    }
    .btn:disabled, .btn[aria-disabled="true"], .btn.is-disabled {
        opacity: 0.55;
        cursor: not-allowed;
        pointer-events: none;
    }

    .btn-primary {
        background: var(--pp-green-500);
        border-color: var(--pp-green-500);
        color: #fff;
    }
    .btn-primary:hover { background: var(--pp-green-600); border-color: var(--pp-green-600); color: #fff; }
    .btn-primary:active { background: var(--pp-green-700); border-color: var(--pp-green-700); }

    .btn-outline {
        background: var(--pp-surface);
        border-color: var(--pp-line);
        color: var(--pp-ink);
    }
    .btn-outline:hover {
        border-color: var(--pp-green-400);
        background: var(--pp-green-050);
        color: var(--pp-green-700);
    }

    .btn-ghost { background: transparent; border-color: transparent; color: var(--pp-ink-2); }
    .btn-ghost:hover { background: var(--pp-green-050); color: var(--pp-green-700); }

    .btn.danger, .btn-danger { color: var(--pp-danger-500); }
    .btn.danger:hover, .btn-danger:hover {
        background: var(--pp-danger-050);
        border-color: var(--pp-danger-500);
        color: var(--pp-danger-700);
    }
    .btn-primary.danger, .btn-danger.btn-primary {
        background: var(--pp-danger-500);
        border-color: var(--pp-danger-500);
        color: #fff;
    }
    .btn-primary.danger:hover, .btn-danger.btn-primary:hover {
        background: var(--pp-danger-700);
        border-color: var(--pp-danger-700);
        color: #fff;
    }

    .btn-sm {
        min-height: var(--pp-control-h-sm);
        padding: var(--pp-space-1) var(--pp-space-3);
        font-size: var(--pp-text-xs);
        border-radius: var(--pp-radius-sm);
    }
    .btn-lg {
        min-height: var(--pp-control-h-lg);
        padding: var(--pp-space-3) var(--pp-space-6);
        font-size: var(--pp-text-md);
    }
    .btn-block { display: flex; width: 100%; }

    /* An icon-only button still needs a square footprint. */
    .btn:has(> i:only-child) { padding-inline: var(--pp-space-3); }

    /* =========================================================================
       BADGE / CHIP / TAG
       ====================================================================== */

    .status-badge, .chip, .type-tag, .purpose-tag, .badge-pill {
        display: inline-flex;
        align-items: center;
        gap: var(--pp-space-2);
        max-width: 100%;
        min-width: 0;
        border-radius: var(--pp-radius-full);
        font-family: var(--pp-font-sans);
        font-weight: 700;
        line-height: 1.3;
        white-space: nowrap;
        overflow-wrap: anywhere;
    }

    .status-badge {
        padding: var(--pp-space-1) var(--pp-space-3);
        font-size: var(--pp-text-2xs);
        background: var(--pp-line-2);
        color: var(--pp-ink-2);
    }
    .status-badge.active, .status-badge.ok, .status-badge.success, .status-badge.approved {
        background: var(--pp-success-050); color: var(--pp-success-700);
    }
    .status-badge.pending, .status-badge.warning {
        background: var(--pp-warning-050); color: var(--pp-warning-700);
    }
    .status-badge.danger, .status-badge.rejected, .status-badge.failed {
        background: var(--pp-danger-050); color: var(--pp-danger-700);
    }
    .status-badge.info { background: var(--pp-info-050); color: var(--pp-info-700); }
    .status-badge.neutral { background: var(--pp-line-2); color: var(--pp-ink-2); }

    .chip {
        padding: var(--pp-space-1) var(--pp-space-3);
        background: var(--pp-line-2);
        color: var(--pp-ink-2);
        font-size: var(--pp-text-xs);
    }

    /* `.type-tag` and `.role-chips` were used in the admin views but had no
       styles defined in any stylesheet, so they rendered as bare text. */
    .type-tag {
        padding: var(--pp-space-1) var(--pp-space-3);
        background: var(--pp-green-050);
        color: var(--pp-green-700);
        font-size: var(--pp-text-xs);
    }
    .role-chips {
        display: flex;
        flex-wrap: wrap;
        gap: var(--pp-space-2);
        align-items: center;
    }

    /* =========================================================================
       TABLE CELL PRIMITIVES
       ====================================================================== */

    .cell-id { display: flex; align-items: center; gap: var(--pp-space-3); min-width: 0; }
    .cell-id > div { min-width: 0; }
    .cell-id strong { display: block; font-weight: 600; color: var(--pp-ink); overflow-wrap: break-word; }

    .cell-avatar {
        flex: none;
        display: grid;
        place-items: center;
        width: 38px; height: 38px;
        border-radius: var(--pp-radius-md);
        background: var(--pp-green-050);
        color: var(--pp-green-700);
        font-size: var(--pp-text-md);
        font-weight: 700;
        overflow: hidden;
    }
    .cell-avatar img { width: 100%; height: 100%; object-fit: cover; }

    .muted-text { color: var(--pp-muted); font-size: var(--pp-text-xs); }

    .action-row {
        display: flex;
        flex-wrap: wrap;
        gap: var(--pp-space-2);
        justify-content: flex-end;
        align-items: center;
    }
    .action-row form { margin: 0; }

    .status-stack { display: flex; flex-direction: column; gap: var(--pp-space-2); align-items: flex-start; }

}

@layer ds-components {

    /* =========================================================================
       PANEL
       ====================================================================== */

    .panel, .card, .surface {
        background: var(--pp-surface);
        border: 1px solid var(--pp-line);
        border-radius: var(--pp-radius-lg);
        box-shadow: var(--pp-shadow-xs);
    }
    .panel { padding: var(--pp-space-6); }
    .panel + .panel,
    .panel + .stats-grid,
    .stats-grid + .panel,
    .panel + .page-grid { margin-top: var(--pp-space-5); }

    .panel-header {
        display: flex;
        align-items: flex-start;
        justify-content: space-between;
        flex-wrap: wrap;
        gap: var(--pp-space-4);
        margin-bottom: var(--pp-space-5);
        padding-bottom: var(--pp-space-4);
        border-bottom: 1px solid var(--pp-line-2);
    }
    .panel-header > * { min-width: 0; }
    .panel-header h2, .panel-header h3 {
        font-size: var(--pp-text-xl);
        margin-bottom: var(--pp-space-1);
    }
    .panel-header p { color: var(--pp-muted); font-size: var(--pp-text-sm); margin: 0; }

    .eyebrow {
        display: inline-block;
        font-family: var(--pp-font-sans);
        font-size: var(--pp-text-3xs);
        font-weight: 700;
        letter-spacing: var(--pp-tracking-eyebrow);
        text-transform: uppercase;
        color: var(--pp-green-500);
    }

    /* =========================================================================
       FORM
       ====================================================================== */

    .form-grid {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--pp-space-4);
    }
    .form-grid > * { min-width: 0; }
    .form-grid.cols-1 { grid-template-columns: minmax(0, 1fr); }
    .form-grid .full, .form-grid .span-2 { grid-column: 1 / -1; }

    .form-group {
        display: flex;
        flex-direction: column;
        gap: var(--pp-space-2);
        margin-bottom: var(--pp-space-4);
        min-width: 0;
    }
    .form-group label {
        font-size: var(--pp-text-xs);
        font-weight: 700;
        color: var(--pp-ink-2);
    }

    .form-group input,
    .form-group select,
    .form-group textarea,
    input[type="text"], input[type="email"], input[type="password"],
    input[type="number"], input[type="tel"], input[type="url"],
    input[type="date"], input[type="datetime-local"], input[type="search"],
    select, textarea {
        width: 100%;
        max-width: 100%;
        min-width: 0;
        min-height: var(--pp-control-h);
        padding: var(--pp-space-2) var(--pp-space-3);
        background: var(--pp-surface);
        border: 1px solid var(--pp-line);
        border-radius: var(--pp-radius-md);
        color: var(--pp-ink);
        font-family: var(--pp-font-sans);
        font-size: var(--pp-text-md);
        line-height: var(--pp-leading-snug);
        transition: border-color var(--pp-duration-fast) var(--pp-ease),
                    box-shadow var(--pp-duration-fast) var(--pp-ease);
    }
    .form-group textarea, textarea { min-height: 96px; padding-block: var(--pp-space-3); }

    .form-group input::placeholder,
    .form-group textarea::placeholder,
    input::placeholder, textarea::placeholder { color: var(--pp-muted-2); }

    .form-group input:focus,
    .form-group select:focus,
    .form-group textarea:focus,
    input:focus, select:focus, textarea:focus {
        outline: none;
        border-color: var(--pp-green-500);
        box-shadow: var(--pp-ring);
    }
    /* Inputs get the ring, not the global brass outline. */
    .form-group input:focus-visible,
    .form-group select:focus-visible,
    .form-group textarea:focus-visible,
    input:focus-visible, select:focus-visible, textarea:focus-visible { outline: none; }

    .form-group input:disabled,
    .form-group select:disabled,
    .form-group textarea:disabled,
    input:disabled, select:disabled, textarea:disabled {
        background: var(--pp-surface-2);
        color: var(--pp-muted);
        cursor: not-allowed;
    }

    /* Error state, driven by the existing .field-error markup. */
    .field-error {
        display: none;
        color: var(--pp-danger-500);
        font-size: var(--pp-text-xs);
        font-weight: 600;
    }
    .field-error.visible { display: block; }
    .form-group:has(.field-error.visible) input,
    .form-group:has(.field-error.visible) select,
    .form-group:has(.field-error.visible) textarea,
    input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] {
        border-color: var(--pp-danger-500);
    }
    .form-group:has(.field-error.visible) input:focus,
    input[aria-invalid="true"]:focus {
        box-shadow: 0 0 0 3px rgba(180, 35, 24, 0.15);
    }

    /* Checkbox and radio: 18px is legible without dwarfing its label. */
    input[type="checkbox"], input[type="radio"] {
        width: 18px; height: 18px;
        min-height: 0;
        flex: none;
        accent-color: var(--pp-green-500);
        cursor: pointer;
    }

    .form-actions {
        display: flex;
        flex-wrap: wrap;
        gap: var(--pp-space-3);
        margin-top: var(--pp-space-2);
        justify-content: flex-end;
    }
    .form-actions.left { justify-content: flex-start; }

    .form-section-title {
        font-family: var(--pp-font-sans);
        font-size: var(--pp-text-xs);
        font-weight: 700;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        color: var(--pp-muted);
        margin: var(--pp-space-6) 0 var(--pp-space-3);
    }

    /* =========================================================================
       ALERT
       -------------------------------------------------------------------------
       Only .alert-info had styles; the other tones fell back to a plain box.
       ====================================================================== */

    .alert {
        display: flex;
        align-items: flex-start;
        gap: var(--pp-space-3);
        padding: var(--pp-space-3) var(--pp-space-4);
        margin-bottom: var(--pp-space-5);
        border: 1px solid var(--pp-line);
        border-radius: var(--pp-radius-md);
        background: var(--pp-surface);
        color: var(--pp-ink-2);
        font-size: var(--pp-text-md);
    }
    .alert-info, .alert-success {
        background: var(--pp-success-050);
        border-color: var(--pp-green-200);
        color: var(--pp-green-700);
    }
    .alert-warning {
        background: var(--pp-warning-050);
        border-color: #e6cf9a;
        color: var(--pp-warning-700);
    }
    .alert-danger, .alert-error {
        background: var(--pp-danger-050);
        border-color: #f0c2c2;
        color: var(--pp-danger-700);
    }

    /* =========================================================================
       EMPTY STATE
       ====================================================================== */

    .empty-state {
        display: flex;
        flex-direction: column;
        align-items: center;
        text-align: center;
        padding: var(--pp-space-12) var(--pp-space-6);
        color: var(--pp-muted);
    }
    .empty-state > i {
        display: grid;
        place-items: center;
        width: 64px; height: 64px;
        margin-bottom: var(--pp-space-4);
        border-radius: var(--pp-radius-full);
        background: var(--pp-green-050);
        color: var(--pp-green-500);
        font-size: 26px;
        opacity: 1;
    }
    .empty-state h2, .empty-state h3 {
        color: var(--pp-ink);
        font-size: var(--pp-text-xl);
        margin-bottom: var(--pp-space-2);
    }
    .empty-state p { font-size: var(--pp-text-md); max-width: 44ch; margin: 0 auto; }
    .empty-state .btn { margin-top: var(--pp-space-5); }
    .empty-state.inline { padding: var(--pp-space-10) var(--pp-space-5); }

    /* =========================================================================
       PAGINATION
       ====================================================================== */

    .pagination-wrap { margin-top: var(--pp-space-5); }
    .pagination-wrap nav { display: flex; flex-wrap: wrap; gap: var(--pp-space-2); }
    .pagination-wrap a, .pagination-wrap span {
        display: inline-grid;
        place-items: center;
        min-width: var(--pp-control-h-sm);
        height: var(--pp-control-h-sm);
        padding: 0 var(--pp-space-3);
        border: 1px solid var(--pp-line);
        border-radius: var(--pp-radius-md);
        background: var(--pp-surface);
        color: var(--pp-ink-2);
        font-size: var(--pp-text-sm);
        font-weight: 600;
    }
    .pagination-wrap a:hover { border-color: var(--pp-green-400); color: var(--pp-green-700); background: var(--pp-green-050); }
    .pagination-wrap [aria-current], .pagination-wrap .active span {
        background: var(--pp-green-500);
        border-color: var(--pp-green-500);
        color: #fff;
    }
    .pagination-wrap .disabled span { opacity: 0.45; }

    /* =========================================================================
       TOOLBAR / FILTER BAR
       ====================================================================== */

    .toolbar {
        display: flex;
        align-items: center;
        justify-content: space-between;
        flex-wrap: wrap;
        gap: var(--pp-space-4);
        margin-bottom: var(--pp-space-5);
    }
    .toolbar > * { min-width: 0; }
    .toolbar h2 {
        font-size: var(--pp-text-2xl);
        margin-top: var(--pp-space-1);
    }

    .filter-bar {
        display: flex;
        flex-wrap: wrap;
        align-items: flex-end;
        gap: var(--pp-space-3);
    }
    .filter-bar > * { min-width: 0; }
    .filter-bar .form-group { margin-bottom: 0; }
    .filter-bar .fb-search { flex: 2 1 240px; position: relative; }
    .filter-bar .fb-field { flex: 1 1 160px; }
    .filter-bar .fb-actions { display: flex; gap: var(--pp-space-2); flex: 0 0 auto; }
    /* The search icon sits inside the input, which needs matching padding. */
    .filter-bar .fb-search > i {
        position: absolute;
        left: var(--pp-space-3);
        top: calc(50% + 10px);
        transform: translateY(-50%);
        color: var(--pp-muted-2);
        pointer-events: none;
    }
    .filter-bar .fb-search input { padding-left: var(--pp-space-8); }

    @media (max-width: 720px) {
        .form-grid { grid-template-columns: minmax(0, 1fr); }
        .filter-bar { flex-direction: column; align-items: stretch; }
        .filter-bar .fb-actions { flex-direction: column; }
        .filter-bar .fb-actions .btn { width: 100%; }
        .form-actions { flex-direction: column-reverse; }
        .form-actions .btn { width: 100%; }
        .pagination-wrap a, .pagination-wrap span {
            min-width: var(--pp-control-h);
            height: var(--pp-control-h);
        }
    }

}

@layer ds-components {

    /* =========================================================================
       WORKSPACE SHELL
       ====================================================================== */

    /* A multiple-select sizes itself from its `size` attribute and was rendering
       ~250px tall for two options. Cap it and let it grow only as far as useful. */
    select[multiple], select[size]:not([size="1"]) {
        min-height: 0;
        max-height: 220px;
        padding: var(--pp-space-2);
    }
    select[multiple] option { padding: var(--pp-space-2) var(--pp-space-3); border-radius: var(--pp-radius-sm); }

    .app-sidebar {
        display: flex;
        flex-direction: column;
        min-height: 0;
    }

    /* The nav scrolls when there are more items than height. Previously the
       overflow was silent: the last visible row was sliced in half with no
       scrollbar or fade, which reads as a broken layout rather than a scroll
       region. The mask fades the cut edge, and the padding lets the final item
       clear the fade when scrolled to the end. */
    .app-nav {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
        padding-bottom: var(--pp-space-6);
        mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent 100%);
        -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent 100%);
    }
    /* Once scrolled to the bottom there is nothing below to hint at, so the
       fade is removed to avoid dimming the last item. */
    .app-nav:not(:hover) { scrollbar-color: rgba(255,255,255,0.25) transparent; }
    .app-nav::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.25); }

    .app-sidebar-foot { flex: none; margin-top: var(--pp-space-3); }

    .app-nav-link {
        display: flex;
        align-items: center;
        gap: var(--pp-space-3);
        min-height: var(--pp-control-h);
        padding: var(--pp-space-2) var(--pp-space-3);
        border-radius: var(--pp-radius-md);
        color: rgba(255, 255, 255, 0.82);
        font-size: var(--pp-text-sm);
        font-weight: 500;
        transition: background var(--pp-duration-fast) var(--pp-ease),
                    color var(--pp-duration-fast) var(--pp-ease);
    }
    .app-nav-link > i { flex: none; width: 18px; text-align: center; font-size: var(--pp-text-md); }
    .app-nav-link:hover { background: rgba(255, 255, 255, 0.09); color: #fff; }
    .app-nav-link.is-active {
        background: var(--pp-green-050);
        color: var(--pp-green-700);
        font-weight: 600;
    }
    .app-nav-link.is-active:hover { background: #fff; color: var(--pp-green-700); }

    .app-content {
        width: 100%;
        max-width: var(--pp-content-max);
        margin-inline: auto;
        padding: var(--pp-space-8) var(--pp-space-8) var(--pp-space-12);
    }

    .app-topbar-lead h1 {
        font-family: var(--pp-font-serif);
        font-size: var(--pp-text-2xl);
        font-weight: 400;
    }

    .app-breadcrumb {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        gap: var(--pp-space-2);
        font-size: var(--pp-text-2xs);
        color: var(--pp-muted);
    }
    .app-breadcrumb .current { color: var(--pp-ink-2); font-weight: 600; }
    .app-breadcrumb i { font-size: 9px; opacity: 0.6; }

    .app-iconbtn, .app-menu-toggle, .sidebar-dismiss {
        place-items: center;
        width: var(--pp-control-h);
        height: var(--pp-control-h);
        flex: none;
        border: 1px solid var(--pp-line);
        border-radius: var(--pp-radius-md);
        background: var(--pp-surface);
        color: var(--pp-ink-2);
        cursor: pointer;
        transition: background var(--pp-duration-fast) var(--pp-ease),
                    border-color var(--pp-duration-fast) var(--pp-ease);
    }
    .app-iconbtn { display: inline-grid; }
    .app-iconbtn:hover, .app-menu-toggle:hover {
        background: var(--pp-green-050);
        border-color: var(--pp-green-400);
        color: var(--pp-green-700);
    }

    /* The drawer controls belong to the mobile shell only. Declared after
       .app-iconbtn because the dismiss button carries both classes. */
    .app-menu-toggle, .sidebar-dismiss { display: none; }
    .sidebar-dismiss {
        align-self: flex-end;
        margin-bottom: var(--pp-space-2);
        background: rgba(255, 255, 255, 0.1);
        border-color: rgba(255, 255, 255, 0.18);
        color: #fff;
    }
    .sidebar-dismiss:hover {
        background: rgba(255, 255, 255, 0.2);
        border-color: rgba(255, 255, 255, 0.3);
        color: #fff;
    }

    @media (max-width: 1024px) {
        .app-menu-toggle, .sidebar-dismiss { display: inline-grid; }
    }

    @media (max-width: 768px) {
        .app-content { padding: var(--pp-space-5) var(--pp-space-4) var(--pp-space-10); }
        .panel { padding: var(--pp-space-5); }
        /* iOS zooms the page when a focused control is under 16px. */
        input, select, textarea { font-size: 16px; }
    }

}

@layer ds-components {

    /* =========================================================================
       VIEW PATTERNS
       -------------------------------------------------------------------------
       Previously these lived in per-view @push('styles') blocks. Those blocks
       were unlayered, so they silently outranked the whole design system, and
       .role-chips / .filter-bar / .btn-outline.danger were each duplicated
       across two or three views with slightly different values.
       ====================================================================== */

    /* --- Agent: application under review --------------------------------- */

    .review-hero { text-align: center; padding: var(--pp-space-10) var(--pp-space-6); }
    .review-hero .rh-ic {
        display: grid;
        place-items: center;
        width: 76px; height: 76px;
        margin: 0 auto var(--pp-space-5);
        border-radius: var(--pp-radius-xl);
        background: var(--pp-warning-050);
        color: var(--pp-warning-500);
        font-size: 30px;
    }

    .next-steps {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
        gap: var(--pp-space-4);
    }
    .next-step {
        position: relative;
        padding: var(--pp-space-5);
        border: 1px solid var(--pp-line);
        border-radius: var(--pp-radius-lg);
        background: var(--pp-surface);
        box-shadow: var(--pp-shadow-xs);
    }
    .next-step .ns-ic {
        display: grid;
        place-items: center;
        width: 46px; height: 46px;
        margin-bottom: var(--pp-space-3);
        border-radius: var(--pp-radius-md);
        background: var(--pp-green-050);
        color: var(--pp-green-700);
        font-size: 19px;
    }
    .next-step .ns-num {
        position: absolute;
        top: var(--pp-space-5); right: var(--pp-space-5);
        font-size: var(--pp-text-xs);
        font-weight: 800;
        color: var(--pp-line);
    }
    .next-step h3 { font-size: var(--pp-text-lg); margin-bottom: var(--pp-space-2); }
    .next-step p { color: var(--pp-muted); font-size: var(--pp-text-sm); margin: 0; }

    /* --- Admin: payment verification ------------------------------------- */

    .pv-head { display: flex; align-items: center; gap: var(--pp-space-4); margin-bottom: var(--pp-space-5); }
    .pv-back {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        flex: none;
        width: var(--pp-control-h); height: var(--pp-control-h);
        border: 1px solid var(--pp-line);
        border-radius: var(--pp-radius-md);
        background: var(--pp-surface);
        color: var(--pp-ink);
        transition: background var(--pp-duration-fast) var(--pp-ease),
                    border-color var(--pp-duration-fast) var(--pp-ease);
    }
    .pv-back:hover { background: var(--pp-green-050); border-color: var(--pp-green-400); }
    .pv-head-title { flex: 1; min-width: 0; }
    .pv-head-title .eyebrow { display: block; }
    .pv-head-title h2 { font-size: var(--pp-text-3xl); line-height: var(--pp-leading-tight); margin: var(--pp-space-1) 0; }
    .pv-head-title p { margin: 0; font-size: var(--pp-text-sm); }

    .pv-grid {
        display: grid;
        grid-template-columns: minmax(0, 1.7fr) minmax(300px, 1fr);
        gap: var(--pp-space-5);
        align-items: start;
    }
    .pv-grid > * { min-width: 0; }

    .pv-proof { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
    .pv-proof-bar {
        display: flex;
        align-items: center;
        justify-content: space-between;
        flex-wrap: wrap;
        gap: var(--pp-space-3);
        padding: var(--pp-space-4);
        border-bottom: 1px solid var(--pp-line-2);
    }
    .pv-proof-bar h3 { font-size: var(--pp-text-lg); margin: 0; }
    .pv-proof-bar .muted-text { font-size: var(--pp-text-xs); }
    .pv-proof-actions { display: flex; gap: var(--pp-space-2); flex-wrap: wrap; }
    .pv-proof-view {
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 560px;
        padding: var(--pp-space-5);
        background: var(--pp-canvas);
    }
    .pv-proof-view img {
        max-width: 100%; max-height: 640px;
        border-radius: var(--pp-radius-md);
        box-shadow: var(--pp-shadow-sm);
    }
    .pv-proof-view iframe {
        width: 100%; height: 640px;
        border: 0;
        border-radius: var(--pp-radius-md);
        background: var(--pp-surface);
        box-shadow: var(--pp-shadow-sm);
    }
    .pv-proof-empty { text-align: center; max-width: 34ch; color: var(--pp-muted); }
    .pv-proof-empty i { font-size: 40px; color: var(--pp-green-400); margin-bottom: var(--pp-space-3); }
    .pv-proof-empty p { margin: 0 0 var(--pp-space-3); }

    .pv-side { display: flex; flex-direction: column; gap: var(--pp-space-5); }
    .pv-decision { display: flex; flex-direction: column; gap: var(--pp-space-3); }
    .pv-amount {
        padding: var(--pp-space-3) var(--pp-space-4);
        border: 1px solid var(--pp-green-200);
        border-radius: var(--pp-radius-md);
        background: var(--pp-green-050);
    }
    .pv-amount span {
        display: block;
        color: var(--pp-green-700);
        font-size: var(--pp-text-2xs);
        font-weight: 800;
        letter-spacing: 0.05em;
        text-transform: uppercase;
    }
    .pv-amount strong { font-size: var(--pp-text-3xl); color: var(--pp-green-700); letter-spacing: -0.02em; }
    .pv-decision-note { margin: 0; font-size: var(--pp-text-sm); color: var(--pp-muted); line-height: var(--pp-leading-snug); }
    .pv-decision-note i { color: var(--pp-green-700); margin-right: var(--pp-space-1); }
    .pv-decision-actions { display: flex; flex-direction: column; gap: var(--pp-space-2); }
    .pv-decision-actions .btn { width: 100%; justify-content: center; }

    .pv-outcome {
        display: flex;
        align-items: center;
        gap: var(--pp-space-3);
        padding: var(--pp-space-3) var(--pp-space-4);
        border-radius: var(--pp-radius-md);
    }
    .pv-outcome i { font-size: 24px; flex: none; }
    .pv-outcome strong { display: block; font-size: var(--pp-text-md); }
    .pv-outcome span { font-size: var(--pp-text-xs); color: var(--pp-muted); }
    .pv-outcome.ok { background: var(--pp-green-050); border: 1px solid var(--pp-green-200); }
    .pv-outcome.ok i { color: var(--pp-green-700); }
    .pv-outcome.bad { background: var(--pp-danger-050); border: 1px solid #f0c2c2; }
    .pv-outcome.bad i { color: var(--pp-danger-500); }
    .pv-reason {
        margin: 0;
        padding: var(--pp-space-3);
        border-radius: var(--pp-radius-md);
        background: var(--pp-canvas);
        color: var(--pp-ink);
        font-size: var(--pp-text-sm);
        line-height: var(--pp-leading-snug);
    }
    .pv-details .detail-list dd { display: inline-flex; align-items: center; gap: var(--pp-space-2); }
    .pv-tx-link { margin-top: var(--pp-space-3); width: 100%; justify-content: center; }

    /* --- Admin: payments inside a transaction ---------------------------- */

    .pay-list { display: flex; flex-direction: column; gap: var(--pp-space-3); }
    .pay-item {
        display: flex;
        align-items: center;
        gap: var(--pp-space-3);
        padding: var(--pp-space-3) var(--pp-space-4);
        border: 1px solid var(--pp-line);
        border-radius: var(--pp-radius-lg);
        background: var(--pp-surface);
        box-shadow: var(--pp-shadow-xs);
    }
    .pay-item-ic {
        display: grid;
        place-items: center;
        flex: none;
        width: 44px; height: 44px;
        border-radius: var(--pp-radius-md);
        background: var(--pp-warning-050);
        color: var(--pp-warning-500);
        font-size: 18px;
    }
    .pay-item-ic.ok { background: var(--pp-green-050); color: var(--pp-green-700); }
    .pay-item-ic.bad { background: var(--pp-danger-050); color: var(--pp-danger-500); }
    .pay-item-main { flex: 1; min-width: 0; }
    .pay-item-main h4 { font-size: var(--pp-text-md); margin: 0; }
    .pay-item-main p { margin: var(--pp-space-1) 0 0; font-size: var(--pp-text-xs); }
    .pay-item-reason { color: var(--pp-danger-500); }
    .pay-item-meta { color: var(--pp-green-700); font-weight: 600; }
    .pay-item-side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--pp-space-2); flex: none; }
    .pay-item-actions { display: flex; gap: var(--pp-space-2); flex-wrap: wrap; justify-content: flex-end; }

    @media (max-width: 720px) {
        .pay-item { flex-wrap: wrap; }
        .pay-item-side { width: 100%; align-items: stretch; flex-direction: row; justify-content: space-between; }
        .pay-item-actions { flex: 1; }
    }

    /* --- Admin: permissions matrix --------------------------------------- */

    .perm-groups { display: grid; gap: var(--pp-space-5); }
    .perm-groups .data-table code {
        background: var(--pp-line-2);
        padding: 2px var(--pp-space-2);
        border-radius: var(--pp-radius-sm);
        font-size: var(--pp-text-xs);
    }

    @media (max-width: 980px) {
        .pv-grid { grid-template-columns: minmax(0, 1fr); }
        .pv-proof-view { min-height: 380px; }
        .pv-proof-view iframe { height: 460px; }
    }

}

@layer ds-components {

    /* =========================================================================
       MODAL
       -------------------------------------------------------------------------
       The panel is a flex column: head and foot are fixed, the body takes the
       remaining space and scrolls. The legacy rules sized the body with
       `calc(92dvh - 150px)` — a guess at the combined head and foot height that
       was wrong whenever a title wrapped, so the footer buttons were cut off
       the bottom of the screen on a phone.
       ====================================================================== */

    .modal {
        position: fixed;
        inset: 0;
        z-index: var(--pp-z-modal);
        display: none;
        align-items: center;
        justify-content: center;
        padding: var(--pp-space-5);
        background: rgba(6, 22, 14, 0.5);
        backdrop-filter: blur(3px);
    }
    .modal.is-open { display: flex; }

    .modal-panel {
        display: flex;
        flex-direction: column;
        width: 100%;
        max-width: 560px;
        max-height: calc(100dvh - var(--pp-space-10));
        min-height: 0;
        background: var(--pp-surface);
        border-radius: var(--pp-radius-xl);
        box-shadow: var(--pp-shadow-xl);
        overflow: hidden;
    }
    .modal-panel.lg { max-width: 760px; }

    .modal-head {
        flex: none;
        display: flex;
        align-items: flex-start;
        justify-content: space-between;
        gap: var(--pp-space-4);
        padding: var(--pp-space-5) var(--pp-space-6);
        border-bottom: 1px solid var(--pp-line-2);
    }
    .modal-head > div:first-child { min-width: 0; }
    .modal-head h3 { font-size: var(--pp-text-xl); }
    .modal-head p { color: var(--pp-muted); font-size: var(--pp-text-sm); margin: var(--pp-space-1) 0 0; }

    .modal-close {
        flex: none;
        display: grid;
        place-items: center;
        width: 34px; height: 34px;
        border: 0;
        border-radius: var(--pp-radius-md);
        background: var(--pp-line-2);
        color: var(--pp-ink-2);
        font-size: 18px;
        line-height: 1;
        cursor: pointer;
    }
    .modal-close:hover { background: var(--pp-danger-050); color: var(--pp-danger-500); }

    /* Most modals wrap the body and foot in a <form>, so the panel's only flex
       children are the head and that form. The form has to become a flex column
       itself, or the body never shrinks and the footer buttons are pushed off
       the bottom of the screen. */
    .modal-panel > form,
    .modal-panel > div:has(> .modal-body) {
        display: flex;
        flex-direction: column;
        flex: 1 1 auto;
        min-height: 0;
        margin: 0;
    }

    .modal-body {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
        overscroll-behavior: contain;
        -webkit-overflow-scrolling: touch;
        padding: var(--pp-space-6);
    }

    .modal-foot {
        flex: none;
        display: flex;
        flex-wrap: wrap;
        justify-content: flex-end;
        gap: var(--pp-space-3);
        padding: var(--pp-space-4) var(--pp-space-6);
        border-top: 1px solid var(--pp-line-2);
        background: var(--pp-surface-2);
    }

    /* Below this width the dialog becomes a bottom sheet: it sits against the
       thumb, and the rounded top edge signals it can be dismissed downwards. */
    @media (max-width: 640px) {
        .modal { align-items: flex-end; padding: 0; }
        .modal-panel, .modal-panel.lg {
            max-width: 100%;
            max-height: 92dvh;
            border-radius: var(--pp-radius-xl) var(--pp-radius-xl) 0 0;
        }
        .modal-head, .modal-body, .modal-foot {
            padding-inline: var(--pp-space-5);
        }
        /* Clear the home indicator on iOS. */
        .modal-foot {
            flex-direction: column-reverse;
            padding-bottom: max(var(--pp-space-4), env(safe-area-inset-bottom));
        }
        .modal-foot .btn { width: 100%; }
    }

    body.modal-open { overflow: hidden; }

}

@layer ds-components {

    /* =========================================================================
       STACKING ORDER
       -------------------------------------------------------------------------
       The legacy sheets picked z-index values independently (the topbar sat at
       1000, above the modal's 500), so a dialog opened underneath the header.
       Every layer that stacks is pinned to the token scale here.
       ====================================================================== */

    .app-topbar { z-index: var(--pp-z-sticky); }
    /* Opaque, not translucent.

       A `backdrop-filter` here would blur the page behind the header nicely,
       but it also makes the header a containing block AND a stacking context
       for fixed-position descendants -- and the mobile nav drawer is a fixed
       child of this element. With the filter applied the drawer was trapped
       inside the header's stacking context, so the nav backdrop (a sibling of
       the header) painted over it and the menu appeared behind a grey blur.
       A solid background solves the original text-bleed without that trap.

       The height is pinned to the token rather than left to the inner element's
       min-height plus whatever padding the legacy sheets add, because sticky
       panels below offset themselves by exactly this value.

       It is raised to the drawer level rather than the sticky level: being
       sticky WITH a z-index already makes it a stacking context, so the drawer
       inside it can never out-paint a sibling. Header and drawer move together,
       above the backdrop that dims the page behind them. */
    .site-header {
        display: flex;
        align-items: center;
        min-height: var(--pp-header-h);
        padding-block: 0;
        z-index: var(--pp-z-drawer);
        background: var(--pp-surface);
    }
    .app-sidebar-backdrop, .nav-backdrop { z-index: var(--pp-z-backdrop); }
    .app-sidebar { z-index: var(--pp-z-drawer); }
    /* Sits inside the header's stacking context, so it only has to beat its
       own siblings -- a global value here would achieve nothing. */
    .site-menu { z-index: 1; }
    .notification-panel { z-index: var(--pp-z-popover); }
    .modal { z-index: var(--pp-z-modal); }
    .toast-stack, .skip-link { z-index: var(--pp-z-toast); }

    /* Local stacking inside the notification panel: its head is sticky and must
       stay above the list scrolling under it. */
    .notification-head { z-index: 1; }

}

@layer ds-components {

    /* =========================================================================
       PUBLIC SITE
       ====================================================================== */

    /* The eyebrow is brand green, which all but disappears on the dark photo
       heroes. On those it needs to be light. */
    .page-hero .eyebrow,
    .inner-hero .eyebrow,
    .home-hero .eyebrow,
    .home-final-cta .eyebrow,
    .site-footer .eyebrow { color: var(--pp-accent-200); }

    .page-hero .breadcrumbs,
    .inner-hero .breadcrumbs { color: rgba(255, 255, 255, 0.78); }
    .page-hero .breadcrumbs a,
    .inner-hero .breadcrumbs a { color: #fff; }

    .inner-hero-metrics {
        display: flex;
        flex-wrap: wrap;
        gap: var(--pp-space-3);
    }
    .inner-hero-metrics span {
        display: inline-flex;
        align-items: center;
        gap: var(--pp-space-2);
        padding: var(--pp-space-2) var(--pp-space-4);
        border: 1px solid rgba(255, 255, 255, 0.25);
        border-radius: var(--pp-radius-full);
        background: rgba(255, 255, 255, 0.08);
        color: rgba(255, 255, 255, 0.9);
        font-size: var(--pp-text-xs);
    }
    .inner-hero-metrics strong { color: #fff; font-weight: 700; }

    /* The FAQ aside is far shorter than the question list, leaving a long
       column of empty page. Pinning it keeps it in view while scrolling. */
    @media (min-width: 861px) {
        .faq-aside { position: sticky; top: calc(var(--pp-header-h) + var(--pp-space-4)); }
    }

}

@layer ds-components {

    /* =========================================================================
       SITE FOOTER
       -------------------------------------------------------------------------
       The mobile rules in redesign.css set `display: inline-flex` on footer
       links to give them a 40px touch target. That also made them inline, so
       every column collapsed onto one line -- "Browse properties Create account
       Become an agent". `flex` keeps the touch target and the stacking.
       ====================================================================== */

    .footer-col a,
    .footer-contact a,
    .footer-contact span {
        display: flex;
        align-items: center;
        gap: var(--pp-space-2);
        min-height: 40px;
        margin-bottom: 0;
        color: rgba(255, 255, 255, 0.76);
        font-size: var(--pp-text-md);
    }
    .footer-col a:hover,
    .footer-contact a:hover { color: #fff; }

    .footer-col {
        display: flex;
        flex-direction: column;
        min-width: 0;
    }
    .footer-col h4 {
        margin-bottom: var(--pp-space-3);
        color: #fff;
        font-size: var(--pp-text-xs);
        font-weight: 700;
        letter-spacing: 0.08em;
        text-transform: uppercase;
    }
    .footer-col a, .footer-contact span { overflow-wrap: anywhere; }
    .footer-contact i { flex: none; width: 16px; text-align: center; opacity: 0.7; }

    .footer-social { display: flex; flex-wrap: wrap; gap: var(--pp-space-2); }
    .footer-social a {
        display: grid;
        place-items: center;
        width: var(--pp-control-h); height: var(--pp-control-h);
        border-radius: var(--pp-radius-md);
        background: rgba(255, 255, 255, 0.08);
        color: rgba(255, 255, 255, 0.85);
        transition: background var(--pp-duration-fast) var(--pp-ease);
    }
    .footer-social a:hover { background: rgba(255, 255, 255, 0.18); color: #fff; }

    .footer-bottom .container {
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
        gap: var(--pp-space-3);
        font-size: var(--pp-text-xs);
        color: rgba(255, 255, 255, 0.6);
    }

}

@layer ds-components {

    /* =========================================================================
       PROPERTY DETAIL
       ====================================================================== */

    /* On desktop the summary card is much shorter than the gallery column, so
       it leaves a tall band of empty page. Pinning it keeps the price and the
       primary action in view while the description scrolls. */
    @media (min-width: 861px) {
        /* The site header is sticky, so a bare `top: 24px` parked this card
           83px underneath it. */
        .property-summary { position: sticky; top: calc(var(--pp-header-h) + var(--pp-space-4)); }
    }

    /* Stacked, the summary would otherwise fall below the description and the
       assurance cards, burying the price and the "Show interest" action under
       a full screen of copy. */
    @media (max-width: 860px) {
        .property-detail-layout { display: flex; flex-direction: column; }
        .property-summary { order: -1; }
    }

}

@layer ds-components {

    /* =========================================================================
       ABOUT: STORY CARDS
       -------------------------------------------------------------------------
       The card is a two-column grid (44px icon, 1fr text) holding three
       children: <i>, <strong>, <span>. With only auto-placement the <span>
       wrapped onto row 2 COLUMN 1 -- the 44px icon column -- so the body copy
       rendered one character per line. The icon now spans both rows and the
       text is placed explicitly in column two.
       ====================================================================== */

    .story-card-stack article {
        display: grid;
        grid-template-columns: 44px minmax(0, 1fr);
        grid-template-rows: auto auto;
        align-items: start;
        gap: var(--pp-space-1) var(--pp-space-4);
        padding: var(--pp-space-5);
    }
    .story-card-stack article > i {
        grid-column: 1;
        grid-row: 1 / span 2;
    }
    .story-card-stack article > strong {
        grid-column: 2;
        grid-row: 1;
        font-size: var(--pp-text-md);
        color: var(--pp-ink);
    }
    .story-card-stack article > span {
        grid-column: 2;
        grid-row: 2;
        min-width: 0;
        color: var(--pp-muted);
        font-size: var(--pp-text-sm);
        line-height: var(--pp-leading-normal);
    }

}

@layer ds-components {

    /* =========================================================================
       STANDALONE LINK TARGETS
       -------------------------------------------------------------------------
       WCAG 2.5.8 exempts links sitting inline within a sentence, but these are
       standalone actions rendered on their own line at roughly 20px tall. They
       get a real target without becoming buttons.
       ====================================================================== */

    .auth-links a,
    .auth-small-link,
    .auth-alt a,
    .contact-card a,
    .qa-tile > a,
    .audience-panel > a {
        display: inline-flex;
        align-items: center;
        gap: var(--pp-space-2);
        min-height: var(--pp-control-h);
        padding-block: var(--pp-space-2);
    }

    .auth-links {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        gap: var(--pp-space-2) var(--pp-space-5);
    }

    /* The checkbox row and the "forgot password" link share a line; keep them
       aligned once the link grows a taller box. */
    .form-inline-actions,
    .reset-actions-row {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        justify-content: space-between;
        gap: var(--pp-space-3);
    }

}

@layer ds-components {

    /* =========================================================================
       BUTTONS ON DARK GROUNDS
       -------------------------------------------------------------------------
       The closing CTA band is deep green, so the standard green primary button
       all but vanished against it. On dark sections the roles invert: the
       primary action becomes the light surface, the secondary a light outline.
       ====================================================================== */

    .home-final-cta .btn-primary,
    .home-hero .btn-primary {
        background: var(--pp-surface);
        border-color: var(--pp-surface);
        color: var(--pp-green-700);
    }
    .home-final-cta .btn-primary:hover,
    .home-hero .btn-primary:hover {
        background: var(--pp-accent-100);
        border-color: var(--pp-accent-100);
        color: var(--pp-green-900);
    }

    .home-final-cta .btn-outline,
    .home-hero .btn-outline {
        background: transparent;
        border-color: rgba(255, 255, 255, 0.45);
        color: #fff;
    }
    .home-final-cta .btn-outline:hover,
    .home-hero .btn-outline:hover {
        background: rgba(255, 255, 255, 0.12);
        border-color: #fff;
        color: #fff;
    }

}

@layer ds-components {

    /* =========================================================================
       PROPERTY CARD
       -------------------------------------------------------------------------
       Listing titles are long and unpredictable ("5 Bedroom Semi-Detached
       Duplex Shortlet in Bodija, Ibadan"). At the previous size they ran to
       three lines, so cards in the same row ended up wildly different heights.
       Clamping to two lines keeps the grid even without truncating most titles.
       ====================================================================== */

    .property-card {
        display: flex;
        flex-direction: column;
        overflow: hidden;
    }
    .property-card > a { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }

    .property-card-body { padding: var(--pp-space-5); flex: 1 1 auto; }

    .property-card-body h2 {
        display: -webkit-box;
        -webkit-line-clamp: 2;
        line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
        margin: 0 0 var(--pp-space-2);
        font-size: var(--pp-text-xl);
        line-height: var(--pp-leading-snug);
        color: var(--pp-ink);
    }
    .property-card-body p {
        display: flex;
        align-items: center;
        gap: var(--pp-space-2);
        margin: 0 0 var(--pp-space-3);
        color: var(--pp-muted);
        font-size: var(--pp-text-sm);
    }

    .property-facts {
        display: flex;
        flex-wrap: wrap;
        gap: var(--pp-space-2) var(--pp-space-4);
        color: var(--pp-ink-2);
        font-size: var(--pp-text-xs);
    }
    .property-facts span { display: inline-flex; align-items: center; gap: var(--pp-space-2); }
    .property-facts i { color: var(--pp-muted); }

    /* The two corner badges were overlapping where both appear. */
    .property-media { position: relative; }
    .property-media .purpose-tag,
    .property-media .availability-tag {
        position: absolute;
        right: var(--pp-space-3);
        z-index: 2;
    }
    .property-media .purpose-tag { top: var(--pp-space-3); }
    .property-media .availability-tag { top: calc(var(--pp-space-3) + 30px); }

    /* Even card heights across a row. */
    .property-grid > .property-card { height: 100%; }

}

@layer ds-components {

    /* =========================================================================
       RESPONSIVE: PUBLIC SITE
       -------------------------------------------------------------------------
       Breakpoints
         <= 479   small phone
         <= 767   phone
         <= 1023  tablet
         >  1023  desktop
       ====================================================================== */

    /* ---- Header ---------------------------------------------------------- */

    .site-header-inner {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--pp-space-4);
        width: min(100% - 2rem, var(--pp-container-wide));
        min-height: var(--pp-header-h);
        margin-inline: auto;
    }

    .brand { display: inline-flex; align-items: center; flex: 0 1 auto; min-width: 0; }

    .nav-toggle {
        display: none;
        place-items: center;
        flex: none;
        width: var(--pp-control-h);
        height: var(--pp-control-h);
        border: 1px solid var(--pp-line);
        border-radius: var(--pp-radius-md);
        background: var(--pp-surface);
        color: var(--pp-ink);
    }

    /* ---- Breadcrumbs ------------------------------------------------------ */

    /* These were `white-space: nowrap; overflow: auto`, so a long property
       title ran off the edge inside an invisible scroll strip. */
    .breadcrumbs {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: var(--pp-space-1) var(--pp-space-2);
        overflow: visible;
        white-space: normal;
        font-size: var(--pp-text-xs);
        min-width: 0;
    }
    .breadcrumbs > * { min-width: 0; overflow-wrap: anywhere; }
    .breadcrumbs i { font-size: 9px; opacity: 0.6; }

    /* ---- Hero metrics ----------------------------------------------------- */

    /* Legacy sets flex-direction: column at mobile, which stretched each pill
       to the full width of the page. They are chips: they should wrap. */
    .inner-hero-metrics,
    .hero-meta-row,
    .property-summary-tags {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        gap: var(--pp-space-2);
    }

    /* This is a row of cards, not chips: it needs equal columns that collapse,
       not content-sized flex items. */
    .property-assurance-row {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
        gap: var(--pp-space-3);
        align-items: stretch;
    }
    .property-assurance-row > * { min-width: 0; }
    .inner-hero-metrics > span { width: auto; flex: 0 0 auto; }

    /* ---- Tablet ----------------------------------------------------------- */

    @media (max-width: 1023px) {
        .home-hero-inner,
        .property-detail-layout,
        .story-layout,
        .contact-showcase,
        .faq-layout,
        .legal-wrap,
        .auth-section > .auth-split {
            grid-template-columns: minmax(0, 1fr);
        }
        .section, .home-section { padding-block: var(--pp-space-10); }
    }

    /* ---- Phone ------------------------------------------------------------ */

    @media (max-width: 767px) {
        /* A 165x97 logo turned the header into a 97px-tall band on a 390px
           screen. Cap the height and let the width follow the aspect ratio. */
        .site-logo,
        .site-header .site-logo {
            width: auto;
            max-width: 190px;
            height: 44px;
            max-height: 44px;
            object-fit: contain;
        }
        .site-header-inner {
            padding-block: var(--pp-space-2);
            width: min(100% - 1.5rem, var(--pp-container-wide));
        }
        .nav-toggle { display: grid; }

        .page-hero, .inner-hero {
            padding-block: var(--pp-space-8) var(--pp-space-6);
            min-height: 0;
        }
        .page-hero h1, .inner-hero h1 { font-size: clamp(26px, 7.5vw, 34px); }
        .page-hero p, .inner-hero p { font-size: var(--pp-text-md); }

        .section, .home-section { padding-block: var(--pp-space-8); }
        .home-section h2 { font-size: clamp(24px, 6.5vw, 30px); }

        .inner-actions, .hero-actions {
            display: flex;
            flex-wrap: wrap;
            gap: var(--pp-space-2);
        }
        .inner-actions .btn, .hero-actions .btn { flex: 1 1 auto; justify-content: center; }

        .footer-grid { gap: var(--pp-space-6); }
    }

    @media (max-width: 479px) {
        .site-logo, .site-header .site-logo { height: 38px; max-width: 158px; }
        .page-hero h1, .inner-hero h1 { font-size: clamp(23px, 7.2vw, 28px); }
        .inner-hero-metrics > span { font-size: var(--pp-text-2xs); padding: var(--pp-space-1) var(--pp-space-3); }
        .inner-actions .btn, .hero-actions .btn { flex-basis: 100%; }
    }

}

@layer ds-components {

    /* Specs are short label/value pairs. One per row wasted a whole phone
       screen on four numbers; two columns reads better and scrolls less. */
    .spec-grid {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--pp-space-3);
        margin: var(--pp-space-4) 0;
    }
    .spec-grid > * { min-width: 0; }
    .spec-grid .spec {
        padding: var(--pp-space-3);
        border: 1px solid var(--pp-line);
        border-radius: var(--pp-radius-md);
        background: var(--pp-surface-2);
    }
    .spec-grid .spec span {
        display: block;
        color: var(--pp-muted);
        font-size: var(--pp-text-xs);
        font-weight: 600;
    }
    .spec-grid .spec strong { font-size: var(--pp-text-lg); }

    @media (max-width: 359px) {
        .spec-grid { grid-template-columns: minmax(0, 1fr); }
    }

}

@layer ds-components {

    /* =========================================================================
       RESPONSIVE: TYPE AND DENSITY
       ====================================================================== */

    /* 10px uppercase eyebrows read fine on a desktop monitor but are genuinely
       hard to read on a phone held at arm's length. Nudging the two smallest
       steps up lifts every eyebrow, breadcrumb and badge at once, because they
       are all expressed in these tokens. */
    @media (max-width: 767px) {
        :root {
            --pp-text-3xs: 0.6875rem;  /* 10 -> 11px */
            --pp-text-2xs: 0.75rem;    /* 11 -> 12px */
            --pp-text-xs:  0.8125rem;  /* 12 -> 13px */
        }
    }

    /* Chip rows must wrap rather than push past the edge on a 320px screen. */
    .status-stack,
    .role-chips,
    .property-summary-tags,
    .doc-actions,
    .tabs {
        display: flex;
        flex-wrap: wrap;
        gap: var(--pp-space-2);
        min-width: 0;
        max-width: 100%;
    }
    .status-stack > *,
    .role-chips > * { max-width: 100%; min-width: 0; }

    /* A status word is short and must never be hyphen-less-broken across lines
       ("Complete d"). The containers that hold badges wrap as flex rows, so the
       badge itself can stay on one line. */
    .status-badge, .chip, .type-tag {
        white-space: nowrap;
        overflow-wrap: normal;
    }
    /* Only in the stacked card layout, where a badge has the full card width
       available, is wrapping useful. */
    @media (max-width: 860px) {
        .data-table:not(.data-table--keep) .status-badge,
        .data-table:not(.data-table--keep) .chip,
        .data-table:not(.data-table--keep) .type-tag {
            white-space: normal;
            overflow-wrap: break-word;
        }
    }

}

@layer ds-components {

    /* The workspace label under the brand and the breadcrumb were pinned at
       9-10.5px in the legacy sheets, which is below a comfortable reading size
       on a phone. Both are expressed in tokens now, so they scale with the
       mobile step-up above. */
    .app-brand-text small {
        font-size: var(--pp-text-2xs);
        letter-spacing: 0.12em;
        text-transform: uppercase;
        font-weight: 700;
    }
    .app-breadcrumb,
    .app-breadcrumb .current { font-size: var(--pp-text-2xs); }
    .app-breadcrumb i { font-size: 0.75em; }

}

@layer ds-components {

    /* =========================================================================
       RESPONSIVE: WORKSPACE SHELL
       -------------------------------------------------------------------------
       This replaces the inline responsive partials, which carried 240
       `!important` declarations between them. Because `!important` in a lower
       layer beats a normal declaration in a higher one, that partial was a
       second, competing responsive system that the design system could not
       override -- every fix here had to fight it. The behaviour is reproduced
       below with normal specificity so one system owns the result.

         >  1024  sidebar is a fixed column beside the content
         <= 1024  sidebar becomes an off-canvas drawer with a backdrop
         <=  768  compact topbar, single-column grids, notifications as a sheet
       ====================================================================== */

    .app-shell {
        display: grid;
        grid-template-columns: var(--pp-sidebar-w) minmax(0, 1fr);
        min-height: 100vh;
    }
    .app-main { min-width: 0; display: flex; flex-direction: column; }

    .app-topbar {
        position: sticky;
        top: 0;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--pp-space-5);
        padding: var(--pp-space-4) var(--pp-space-8);
    }
    .app-topbar-lead { min-width: 0; }
    .app-topbar-actions { display: flex; align-items: center; gap: var(--pp-space-3); }
    .app-title-row { display: flex; align-items: center; gap: var(--pp-space-3); min-width: 0; }
    .app-title-row > div { min-width: 0; }
    .app-title-row h1 { overflow-wrap: anywhere; }

    /* ---- Tablet and below: sidebar becomes a drawer ----------------------- */

    @media (max-width: 1024px) {
        .app-shell { display: block; }

        .app-sidebar {
            position: fixed;
            inset: 0 auto 0 0;
            width: min(86vw, 320px);
            max-width: 320px;
            height: 100dvh;
            transform: translateX(-105%);
            transition: transform var(--pp-duration-slow) var(--pp-ease);
            overflow-y: auto;
            overscroll-behavior: contain;
            box-shadow: 18px 0 48px rgba(15, 32, 23, 0.16);
        }
        .app-sidebar.is-open,
        .app-sidebar.open,
        body.sidebar-open .app-sidebar,
        body.is-sidebar-open .app-sidebar,
        .app-shell.sidebar-open .app-sidebar { transform: translateX(0); }

        .app-sidebar-backdrop {
            display: block;
            position: fixed;
            inset: 0;
            border: 0;
            background: rgba(7, 18, 12, 0.44);
            opacity: 0;
            visibility: hidden;
            pointer-events: none;
            transition: opacity var(--pp-duration-base) var(--pp-ease),
                        visibility var(--pp-duration-base) var(--pp-ease);
        }
        body.sidebar-open .app-sidebar-backdrop,
        body.is-sidebar-open .app-sidebar-backdrop,
        .app-shell.sidebar-open .app-sidebar-backdrop,
        .app-sidebar.is-open + .app-sidebar-backdrop,
        .app-sidebar.open + .app-sidebar-backdrop {
            opacity: 1;
            visibility: visible;
            pointer-events: auto;
        }
        body.sidebar-open { overflow: hidden; }

        .app-main { margin-left: 0; width: 100%; }
        .app-topbar { padding-inline: var(--pp-space-6); }
        /* The name and role are already in the drawer; the avatar is enough here. */
        .app-user-meta { display: none; }

        .stats-grid, .qa-grid, .form-grid,
        .doc-grid, .listing-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }

    /* ---- Phone: compact topbar ------------------------------------------- */

    @media (max-width: 768px) {
        .app-content { padding: var(--pp-space-5) var(--pp-space-4) var(--pp-space-8); }

        /* Breadcrumb on its own row, then title and controls share a row. */
        .app-topbar {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto;
            grid-template-areas:
                "crumb crumb"
                "title actions";
            align-items: center;
            gap: var(--pp-space-2) var(--pp-space-3);
            padding: var(--pp-space-3) var(--pp-space-4);
            min-height: 0;
        }
        .app-topbar-lead { display: contents; }
        .app-breadcrumb {
            grid-area: crumb;
            min-width: 0;
            max-width: 100%;
            flex-wrap: nowrap;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
            line-height: 1.25;
            margin: 0;
        }
        .app-breadcrumb span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
        .app-title-row { grid-area: title; min-width: 0; margin: 0; }
        .app-title-row h1 {
            margin: 0;
            font-size: clamp(20px, 5.6vw, 26px);
            line-height: 1.1;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .app-topbar-actions {
            grid-area: actions;
            width: auto;
            min-width: 0;
            flex-wrap: nowrap;
            justify-content: flex-end;
            gap: var(--pp-space-2);
            margin: 0;
        }
        .app-topbar-actions > * { flex: 0 0 auto; }
        .app-user { margin-left: auto; }

        .toolbar, .panel-header, .page-head {
            align-items: stretch;
            gap: var(--pp-space-3);
        }
        .toolbar > *, .panel-header > * { max-width: 100%; }
        .toolbar .btn, .toolbar > a.btn, .toolbar > button.btn { align-self: flex-start; }

        .stats-grid, .qa-grid, .form-grid, .doc-grid, .listing-grid,
        .cx-figures, .detail-hero, .detail-gallery, .page-grid,
        .support-chat-shell, .cx-grid { grid-template-columns: minmax(0, 1fr); }

        /* Notifications become a bottom sheet anchored to the viewport rather
           than a dropdown hanging off a button near the screen edge. */
        .notification-center { position: static; }
        .notification-panel {
            position: fixed;
            top: auto;
            left: var(--pp-space-3);
            right: var(--pp-space-3);
            bottom: max(var(--pp-space-3), env(safe-area-inset-bottom));
            width: auto;
            max-width: none;
            height: min(74dvh, 620px);
            max-height: calc(100dvh - var(--pp-space-6));
            min-height: 0;
            border-radius: var(--pp-radius-xl);
            transform: none;
        }
        .notification-head { position: sticky; top: 0; background: inherit; }
        .notification-head .btn { white-space: nowrap; flex: 0 0 auto; }
    }

    @media (max-width: 479px) {
        .app-content { padding: var(--pp-space-4) var(--pp-space-3) var(--pp-space-8); }
        .panel { padding: var(--pp-space-4); }
        .stats-grid { grid-template-columns: minmax(0, 1fr); }
    }

}

@layer ds-components {

    /* =========================================================================
       RESPONSIVE: PUBLIC NAVIGATION
       -------------------------------------------------------------------------
       Ported from the inline public partial for the same reason as the
       workspace shell: its `!important` declarations outranked this file.
       ====================================================================== */

    @media (max-width: 920px) {
        .site-header { position: sticky; top: 0; }
        .site-header-inner { position: relative; }
        .nav-toggle { display: grid; }

        /* Drawer hangs below the header, which stays visible and tappable. */
        .site-menu {
            position: fixed;
            inset: var(--pp-header-h, 68px) 0 auto;
            width: 100%;
            max-height: calc(100dvh - var(--pp-header-h, 68px));
            overflow-y: auto;
            overscroll-behavior: contain;
            display: none;
            flex-direction: column;
            align-items: stretch;
            gap: var(--pp-space-4);
            padding: var(--pp-space-5) var(--pp-space-4) var(--pp-space-6);
            background: var(--pp-surface);
            border-top: 1px solid var(--pp-line);
            box-shadow: var(--pp-shadow-lg);
        }
        .site-menu.is-open,
        .site-menu.open,
        body.nav-open .site-menu,
        body.menu-open .site-menu { display: flex; }

        .site-nav {
            display: flex;
            flex-direction: column;
            align-items: stretch;
            gap: var(--pp-space-1);
            width: 100%;
        }
        .site-nav a {
            display: flex;
            align-items: center;
            min-height: var(--pp-control-h);
            width: 100%;
            padding-inline: var(--pp-space-2);
            border-radius: var(--pp-radius-md);
        }
        .site-nav a:hover,
        .site-nav a[aria-current] { background: var(--pp-green-050); text-decoration: none; }

        .nav-actions {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            width: 100%;
            gap: var(--pp-space-2);
        }
        .nav-actions .btn { width: 100%; justify-content: center; }

        .nav-backdrop {
            position: fixed;
            inset: var(--pp-header-h, 68px) 0 0;
            background: rgba(5, 18, 10, 0.42);
        }
        .nav-backdrop:not([hidden]) { display: block; }
        body.nav-open { overflow: hidden; }

        .home-hero-inner { grid-template-columns: minmax(0, 1fr); }
        .home-hero-content { max-width: 720px; }
        .hero-search-panel { width: 100%; max-width: none; }

        .home-type-grid,
        .journey-grid,
        .testi-grid,
        .contact-methods { grid-template-columns: repeat(2, minmax(0, 1fr)); }
        .audience-grid { grid-template-columns: minmax(0, 1fr); }
        .legal-toc { position: static; top: auto; }

        .auth-section {
            grid-template-columns: minmax(0, 1fr);
            width: min(100% - 2rem, 720px);
            margin-inline: auto;
        }
        .auth-alt { min-height: auto; }
        .auth-card, .auth-card-wide { width: 100%; max-width: 100%; }
    }

    /* The drawer and every sticky offset follow the header as it shrinks. */
    @media (max-width: 920px) { :root { --pp-header-h: 72px; } }
    @media (max-width: 767px) { :root { --pp-header-h: 64px; } }
    @media (max-width: 479px) { :root { --pp-header-h: 58px; } }

    @media (max-width: 560px) {
        .home-type-grid,
        .journey-grid,
        .testi-grid,
        .contact-methods { grid-template-columns: minmax(0, 1fr); }
    }

}

@layer ds-components {

    /* =========================================================================
       PROPERTY ACTION BAR (small screens)
       -------------------------------------------------------------------------
       prestige.css pins `.property-summary` with `position: sticky` at every
       width. On a phone, where the card is the full width of the screen and
       roughly half its height, that meant the card sat over the page and
       covered the content scrolling underneath it.

       So: the card scrolls normally on small screens, and the price plus the
       primary action are lifted into a compact bar docked to the bottom.
       ====================================================================== */

    .property-action-bar { display: none; }

    @media (max-width: 860px) {
        /* Cancel the unconditional sticky from the legacy sheet. */
        .property-summary { position: static; top: auto; }

        .property-action-bar {
            position: fixed;
            left: 0;
            right: 0;
            bottom: 0;
            z-index: var(--pp-z-sticky);
            display: flex;
            align-items: center;
            gap: var(--pp-space-4);
            padding: var(--pp-space-3) var(--pp-space-4);
            padding-bottom: max(var(--pp-space-3), env(safe-area-inset-bottom));
            background: var(--pp-surface);
            border-top: 1px solid var(--pp-line);
            box-shadow: 0 -6px 24px rgba(32, 56, 46, 0.10);
        }
        .pab-price { display: flex; flex-direction: column; min-width: 0; }
        .pab-price span {
            font-size: var(--pp-text-3xs);
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--pp-muted);
        }
        .pab-price strong {
            font-size: var(--pp-text-xl);
            color: var(--pp-green-700);
            line-height: 1.15;
            overflow-wrap: anywhere;
        }
        .property-action-bar .btn { flex: 0 0 auto; margin-left: auto; }
        .pab-unavailable {
            margin-left: auto;
            font-size: var(--pp-text-sm);
            font-weight: 700;
            color: var(--pp-muted);
        }

        /* Leave room so the bar never sits on top of the footer or the last
           element on the page. */
        body:has(.property-action-bar) .site-footer { padding-bottom: 88px; }
    }

}

@layer ds-components {

    /* =========================================================================
       TOAST
       -------------------------------------------------------------------------
       Toasts were pinned to `top: 20px`, above the sticky header in the z-order,
       so on a phone a validation message covered the logo and the menu button
       -- the two controls you most want after an error. They now clear whatever
       header is above them, and span the width on small screens.
       ====================================================================== */

    .toast-stack {
        position: fixed;
        top: calc(var(--pp-toast-offset, var(--pp-header-h)) + var(--pp-space-3));
        right: var(--pp-space-4);
        left: auto;
        display: flex;
        flex-direction: column;
        gap: var(--pp-space-2);
        pointer-events: none;
    }
    /* In the workspace the sticky bar is the topbar, not the public header. */
    .app-body { --pp-toast-offset: var(--pp-topbar-h); }

    .toast-message {
        pointer-events: auto;
        min-width: 240px;
        max-width: min(420px, calc(100vw - 2rem));
        padding: var(--pp-space-3) var(--pp-space-4);
        border: 1px solid var(--pp-line);
        border-left: 4px solid var(--pp-muted);
        border-radius: var(--pp-radius-md);
        background: var(--pp-surface);
        box-shadow: var(--pp-shadow-lg);
        color: var(--pp-ink);
        font-size: var(--pp-text-sm);
        font-weight: 600;
        overflow-wrap: anywhere;
    }
    .toast-message.success { border-left-color: var(--pp-success-500); }
    .toast-message.error   { border-left-color: var(--pp-danger-500); }
    .toast-message.info    { border-left-color: var(--pp-info-500); }

    @media (max-width: 560px) {
        .toast-stack {
            left: var(--pp-space-3);
            right: var(--pp-space-3);
        }
        .toast-message { min-width: 0; max-width: none; }
    }

}

@layer ds-components {

    /* =========================================================================
       TOPBAR ON VERY SMALL SCREENS
       -------------------------------------------------------------------------
       At 320px the control cluster (menu, notifications, avatar, logout) left
       the page title 59px of room, truncating "Commissions" to "Comm...". The
       avatar is dropped -- the same identity is already at the top of the
       drawer -- and the remaining controls shrink, which gives the title back
       roughly 90px.
       ====================================================================== */

    @media (max-width: 479px) {
        .app-topbar { padding-inline: var(--pp-space-3); gap: var(--pp-space-2); }

        .app-topbar-actions .app-avatar { display: none; }

        .app-iconbtn,
        .app-menu-toggle {
            width: 40px;
            height: 40px;
        }

        .app-title-row { gap: var(--pp-space-2); }
        .app-title-row h1 { font-size: clamp(17px, 5.4vw, 22px); }
    }

}

@layer ds-components {

    /* =========================================================================
       NO BACKDROP-FILTER ON STICKY BARS
       -------------------------------------------------------------------------
       `backdrop-filter` makes an element a containing block for fixed-position
       descendants. Both bars contain one:

         .site-header  holds the mobile nav drawer
         .app-topbar   holds the notification panel

       With the filter applied, `position: fixed` on those children resolved
       against the 92px bar instead of the viewport, so the notification sheet's
       `bottom: 12px` placed it at 80px and pushed its top to -531px -- entirely
       off-screen. Both bars are opaque surfaces instead.
       ====================================================================== */

    .app-topbar {
        background: var(--pp-surface);
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        border-bottom: 1px solid var(--pp-line);
    }

}

@layer ds-components {

    /* =========================================================================
       NOTIFICATION PANEL
       ====================================================================== */

    .notification-panel.is-open { display: flex; flex-direction: column; }
    .notification-head, .notification-filters, .notification-permission { flex: none; }

    /* The list takes whatever height is left and scrolls inside it, so the
       sheet never ends in a band of empty white below the last item. */
    .notification-list {
        flex: 1 1 auto;
        min-height: 0;
        /* app.css caps this at a flat 360px, which left a band of empty white
           below the last item once the panel became a full-height sheet. */
        max-height: none;
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    .notification-filters {
        display: flex;
        gap: var(--pp-space-2);
        padding: 0 var(--pp-space-5) var(--pp-space-3);
        border-bottom: 1px solid var(--pp-line);
    }
    .notification-filters button {
        display: inline-flex;
        align-items: center;
        gap: var(--pp-space-2);
        min-height: var(--pp-control-h-sm);
        padding: var(--pp-space-2) var(--pp-space-3);
        border: 0;
        border-radius: var(--pp-radius-md);
        background: transparent;
        color: var(--pp-muted);
        font-size: var(--pp-text-sm);
        font-weight: 600;
        cursor: pointer;
    }
    .notification-filters button:hover { background: var(--pp-surface-2); color: var(--pp-ink); }
    .notification-filters button.is-active {
        background: var(--pp-green-050);
        color: var(--pp-green-700);
    }
    /* The count is a badge on the label, not a separate word floating beside it. */
    .notification-filters button span {
        display: inline-grid;
        place-items: center;
        min-width: 20px;
        height: 20px;
        margin: 0;
        padding: 0 var(--pp-space-1);
        border-radius: var(--pp-radius-full);
        background: var(--pp-green-500);
        color: #fff;
        font-size: var(--pp-text-3xs);
        font-weight: 700;
        line-height: 1;
    }
    .notification-filters button:not(.is-active) span {
        background: var(--pp-line);
        color: var(--pp-ink-2);
    }

}

@layer ds-components {

    /* =========================================================================
       STAGE TIMELINE
       -------------------------------------------------------------------------
       app.css defines .timeline-wrap twice; the later rule wins and makes it a
       520px scroll region. The script scrolls it to the active stage, so it
       opens part-way down with an item sliced off at the top edge and no hint
       that anything is above -- it just looks broken. The mask fades both cut
       edges, and the padding lets the first and last items clear the fade.
       ====================================================================== */

    .timeline-wrap {
        position: relative;
        max-height: 520px;
        overflow-y: auto;
        padding-block: var(--pp-space-2);
        mask-image: linear-gradient(to bottom, transparent 0, #000 24px,
                                    #000 calc(100% - 24px), transparent 100%);
        -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 24px,
                                            #000 calc(100% - 24px), transparent 100%);
    }
    /* Expanded, nothing is clipped, so neither cue is wanted. */
    .timeline-wrap.is-expanded {
        max-height: none;
        overflow: visible;
        mask-image: none;
        -webkit-mask-image: none;
    }

    /* The separate gradient element is redundant now and double-darkens the
       bottom edge against the mask. */
    .timeline-fade { display: none; }

    @media (max-width: 900px) {
        .timeline-wrap {
            max-height: none;
            overflow: visible;
            mask-image: none;
            -webkit-mask-image: none;
        }
    }

}
