/* =============================================================================
   DrivePlan — site.css
   Porsche brand palette + admin chrome + Bootstrap 5.3 overrides
   Font files must be placed in /wwwroot/fonts/ (copy from Events Manager assets)
   ============================================================================= */

/* ---------------------------------------------------------------------------
   Porsche Next typeface — Latin subset (w-la), used for en-ZA content.
   Files: /wwwroot/fonts/porsche-next-w-la-{thin|regular|semi-bold|bold}.{woff2|woff}
   --------------------------------------------------------------------------- */
@font-face {
    font-family: 'PorscheNext';
    src: url('/fonts/porsche-next-w-la-thin.woff2') format('woff2'),
         url('/fonts/porsche-next-w-la-thin.woff') format('woff');
    font-weight: 100;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'PorscheNext';
    src: url('/fonts/porsche-next-w-la-regular.woff2') format('woff2'),
         url('/fonts/porsche-next-w-la-regular.woff') format('woff');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'PorscheNext';
    src: url('/fonts/porsche-next-w-la-semi-bold.woff2') format('woff2'),
         url('/fonts/porsche-next-w-la-semi-bold.woff') format('woff');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'PorscheNext';
    src: url('/fonts/porsche-next-w-la-bold.woff2') format('woff2'),
         url('/fonts/porsche-next-w-la-bold.woff') format('woff');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* ---------------------------------------------------------------------------
   Brand tokens — all brand-specific values live here as CSS custom properties
   --------------------------------------------------------------------------- */
[data-brand="porsche"] {
    --dp-red:             #950014;
    --dp-red-dark:        #6e000f;
    --dp-red-light:       rgba(149, 0, 20, 0.10);
    --dp-charcoal:        #191F22;
    --dp-charcoal-mid:    #2c3539;
    --dp-charcoal-light:  #3d4e54;
    --dp-yellow:          #FEC227;
    --dp-text:            #191F22;
    --dp-text-muted:      #6b7b80;
    --dp-border:          #dee2e6;
    --dp-bg:              #f5f6f7;
    --dp-bg-card:         #ffffff;
    /* Header rule beneath the topbar/portal-header logo — grey, not the brand red. */
    --dp-header-line:     #B5B4BA;

    /* Plain white page background — admin and customer pages carry no photo or gradient. */
    --dp-bg-gradient:     #ffffff;
    --dp-sidebar-width:   240px;
    --dp-topbar-height:   60px;

    /* Frosted-glass effect — single source of truth so every glass surface (login card,
       payment cards, and future reuse) tunes from one place rather than drifting apart.
       -active is the hover/selected firm-up state, still meaningfully more transparent
       than the old values so the background stays genuinely visible through the glass. */
    --dp-glass-blur:            8px;
    --dp-glass-bg:              rgba(255, 255, 255, 0.35);
    --dp-glass-bg-active:       rgba(255, 255, 255, 0.55);

    /* Bootstrap 5 colour overrides via custom properties */
    --bs-primary:         #950014;
    --bs-primary-rgb:     149, 0, 20;
    --bs-link-color:      #950014;
    --bs-link-color-rgb:  149, 0, 20;
    --bs-link-hover-color:#6e000f;
}

/* ---------------------------------------------------------------------------
   Base
   --------------------------------------------------------------------------- */
html {
    font-size: 15px;
    height: 100%;
}

body {
    font-family: 'PorscheNext', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
                 'Helvetica Neue', Arial, sans-serif;
    color: var(--dp-text);
    background: var(--dp-bg-gradient);
    background-attachment: fixed;
    height: 100%;
}

/* ---------------------------------------------------------------------------
   Topbar
   --------------------------------------------------------------------------- */
.dp-topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--dp-topbar-height);
    background-color: var(--dp-charcoal);
    display: flex;
    align-items: center;
    padding: 0 1.25rem;
    z-index: 1030;
    border-bottom: 3px solid var(--dp-header-line);
    gap: 0.75rem;
}

/* Absolutely positioned so the logo sits dead-centre in the topbar regardless of the
   hamburger's and .dp-topbar__meta's own widths — robust against either side changing width
   (e.g. the hamburger only appearing on mobile) without needing a 3-column grid. */
.dp-topbar__logo-link {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
}

.dp-topbar__logo {
    width: 200px;
    height: auto;
    display: block;
    fill: #ffffff;
}

.dp-topbar__meta {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-left: auto;
}

.dp-topbar__user {
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.55);
}

.dp-topbar__logout-btn {
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.7);
    background: none;
    border: none;
    padding: 0;
    text-decoration: underline;
    cursor: pointer;
}

.dp-topbar__logout-btn:hover {
    color: #fff;
}

.dp-version-badge {
    font-size: 0.68rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.45);
    background-color: rgba(255, 255, 255, 0.07);
    padding: 0.2rem 0.5rem;
    border-radius: 3px;
    letter-spacing: 0.04em;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

/* Hamburger (mobile only) */
.dp-topbar__hamburger {
    display: none;
    background: none;
    border: none;
    padding: 0.25rem;
    cursor: pointer;
    flex-direction: column;
    justify-content: space-between;
    width: 28px;
    height: 20px;
    /* Without this, the fixed-width Porsche logo (flex-shrink:0 on its own wrapper) refuses
       to shrink on a narrow viewport, and the flexbox default shrink algorithm crushes this
       button down to a few px wide instead — effectively invisible/unclickable on a real
       phone. This guarantees the hamburger always renders at its full intended size,
       regardless of what else in the topbar row is overflowing. */
    flex-shrink: 0;
}

.dp-topbar__hamburger span {
    display: block;
    height: 2px;
    background-color: rgba(255, 255, 255, 0.75);
    border-radius: 1px;
    transition: all 0.2s;
}

/* ---------------------------------------------------------------------------
   Page wrapper (sidebar + main content flex container)
   --------------------------------------------------------------------------- */
.dp-page {
    display: flex;
    padding-top: var(--dp-topbar-height);
    min-height: 100vh;
}

/* ---------------------------------------------------------------------------
   Sidebar
   --------------------------------------------------------------------------- */
.dp-sidebar {
    position: fixed;
    top: var(--dp-topbar-height);
    left: 0;
    bottom: 0;
    width: var(--dp-sidebar-width);
    background-color: var(--dp-charcoal);
    overflow-y: auto;
    overflow-x: hidden;
    z-index: 1020;
    padding: 1rem 0 2rem;
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
    transition: transform 0.25s ease;
}

.dp-sidebar::-webkit-scrollbar {
    width: 4px;
}

.dp-sidebar::-webkit-scrollbar-thumb {
    background-color: rgba(255, 255, 255, 0.12);
    border-radius: 2px;
}

/* Mobile overlay */
.dp-sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.5);
    z-index: 1015;
}

.dp-sidebar-overlay.is-visible {
    display: block;
}

/* ---------------------------------------------------------------------------
   Sidebar navigation
   --------------------------------------------------------------------------- */
.dp-nav-group {
    margin-bottom: 0.25rem;
}

.dp-nav-heading {
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: rgba(255, 255, 255, 0.28);
    padding: 1rem 1.25rem 0.3rem;
}

.dp-nav-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.dp-nav-link {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.45rem 1.25rem 0.45rem 1.35rem;
    color: rgba(255, 255, 255, 0.62);
    text-decoration: none;
    font-size: 0.875rem;
    font-weight: 400;
    border-left: 3px solid transparent;
    transition: color 0.15s, background-color 0.15s, border-color 0.15s;
    line-height: 1.4;
}

.dp-nav-link:hover {
    color: rgba(255, 255, 255, 0.92);
    background-color: rgba(255, 255, 255, 0.05);
    border-left-color: rgba(255, 255, 255, 0.2);
    text-decoration: none;
}

.dp-nav-link.active {
    color: #ffffff;
    background-color: var(--dp-red-light);
    border-left-color: var(--dp-red);
    font-weight: 600;
}

/* Sizing only, for every _AdminIcon.cshtml glyph wherever one appears — colour is left to the
   context that hosts it (see .dp-nav-link and .dp-report-row below), since the same glyph is
   white-on-charcoal in the sidebar and grey-on-white in a panel. flex-shrink: 0 is load-bearing —
   a long label (e.g. "Offers No Longer Eligible") wrapping to a second line would otherwise
   squeeze the icon out of square. */
.dp-icon {
    display: inline-flex;
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

.dp-icon svg {
    width: 100%;
    height: 100%;
    display: block;
}

/* Nav link icons, adopted from the Admin3 design experiment. Dimmer than the label at rest so
   the text still leads the row, tracking the label's own three states. */
.dp-nav-link .dp-icon {
    color: rgba(255, 255, 255, 0.4);
    transition: color 0.15s;
}

.dp-nav-link:hover .dp-icon {
    color: rgba(255, 255, 255, 0.7);
}

.dp-nav-link.active .dp-icon {
    color: #ffffff;
}

/* Collapsible nav groups (Logs, Masters) — heading keeps the exact look of a plain
   .dp-nav-heading (no flex/full-width bar), just a small red chevron inline after the text. */
.dp-nav-heading--toggle {
    display: block;
    width: 100%;
    background: none;
    border: none;
    margin: 0;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

.dp-nav-chevron {
    display: inline-block;
    margin-left: 0.4rem;
    color: var(--dp-red);
    font-size: 1.1rem;
    line-height: 1;
    vertical-align: middle;
    transition: transform 0.15s;
    transform: rotate(0deg);
}

.dp-nav-group[data-collapsed="true"] .dp-nav-chevron {
    transform: rotate(-90deg);
}

/* ---------------------------------------------------------------------------
   Main content area
   --------------------------------------------------------------------------- */
.dp-main {
    margin-left: var(--dp-sidebar-width);
    flex: 1;
    padding: 1.75rem 2rem;
    min-width: 0;
}

/* Page header: title left, action buttons right */
.dp-page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}

.dp-page-title {
    font-size: 1.3rem;
    font-weight: 600;
    color: var(--dp-text);
    margin: 0;
}

/* ---------------------------------------------------------------------------
   Cards
   --------------------------------------------------------------------------- */
.card {
    border: 1px solid var(--dp-border);
    border-radius: 6px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

.card-header {
    background-color: #fff;
    border-bottom: 1px solid var(--dp-border);
    font-weight: 600;
    font-size: 0.9rem;
    padding: 0.85rem 1.25rem;
}

.card-body {
    padding: 1.25rem;
}

/* Report shortcut rows — the Dashboard's Reports panel, adopted from the Admin3 design
   experiment. Replaces a Bootstrap .list-group-item's plain text + trailing arrow with an
   icon-led row and a chevron that nudges on hover. Horizontal padding matches .card-header's
   so a row's label lines up under the panel title. */
.dp-report-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.625rem;
    padding: 0.7rem 1.25rem;
    border-bottom: 1px solid var(--dp-border);
    font-size: 0.875rem;
    color: var(--dp-text);
    text-decoration: none;
}

/* .card is border-radius: 6px with overflow: visible, and this row's hover background is
   full-bleed — without matching corners the last row paints a square block over the card's
   rounded bottom. Bootstrap's list-group-flush used to supply this; the plain <div> does not. */
.dp-report-row:last-child {
    border-bottom: none;
    border-bottom-left-radius: 6px;
    border-bottom-right-radius: 6px;
}

/* :focus-visible carries the same treatment as :hover — the row replaced Bootstrap's
   .list-group-item-action, which styled both, and a keyboard user otherwise gets the browser
   outline and none of the chevron affordance that is the row's whole signal. */
.dp-report-row:hover,
.dp-report-row:focus-visible {
    background-color: var(--dp-red-light);
    color: var(--dp-text);
    text-decoration: none;
}

/* min-width: 0 for the same reason as .dp-kpi-breakdown-row__label: without it this flex item
   refuses to shrink below its label's min-content width and pushes the chevron out of the card.
   Today's three labels are short enough not to reach it; a longer one would. */
.dp-report-row__left {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    min-width: 0;
}

.dp-report-row__left .dp-icon {
    color: var(--dp-text-muted);
}

.dp-report-row__chev {
    color: var(--dp-text-muted);
    flex-shrink: 0;
    transition: transform 0.14s, color 0.14s;
}

.dp-report-row:hover .dp-report-row__chev,
.dp-report-row:focus-visible .dp-report-row__chev {
    color: var(--dp-red);
    transform: translateX(2px);
}

/* F11: the batch's other three new motions are all gated; this one was not. */
@media (prefers-reduced-motion: reduce) {
    .dp-report-row__chev {
        transition: none;
    }
}

/* ---------------------------------------------------------------------------
   Tables
   --------------------------------------------------------------------------- */
.table {
    font-size: 0.875rem;
}

.table thead th {
    background-color: #f8f9fa;
    font-weight: 700;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--dp-text-muted);
    border-bottom: 2px solid var(--dp-border);
    padding: 0.65rem 0.9rem;
    white-space: nowrap;
}

.table tbody td {
    padding: 0.6rem 0.9rem;
    vertical-align: middle;
    border-bottom: 1px solid rgba(0, 0, 0, 0.04);
}

/* A row-header cell (<th scope="row">, e.g. a label column) never picked up the border-bottom
   override above — Bootstrap's border-collapse then let it fall through to the table's own
   border-color, which a contextual row class like .table-warning overrides per-row, mismatching
   every other row's border. Cell-level border always wins the collapse over row-level, so
   matching td's border-bottom here (without also matching its padding, which would fight the
   ps-0 utility class th cells already use) closes both the plain-row and contextual-row cases. */
.table tbody th {
    border-bottom: 1px solid rgba(0, 0, 0, 0.04);
}

.table-hover tbody tr:hover > td {
    background-color: rgba(149, 0, 20, 0.04);
}

/* ---------------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------------- */
.btn-primary {
    --bs-btn-bg:              var(--dp-red);
    --bs-btn-border-color:    var(--dp-red);
    --bs-btn-hover-bg:        var(--dp-red-dark);
    --bs-btn-hover-border-color: var(--dp-red-dark);
    --bs-btn-active-bg:       var(--dp-red-dark);
    --bs-btn-active-border-color: var(--dp-red-dark);
    --bs-btn-focus-shadow-rgb: 149, 0, 20;
    font-weight: 600;
}

.btn-outline-primary {
    --bs-btn-color:              var(--dp-red);
    --bs-btn-border-color:       var(--dp-red);
    --bs-btn-hover-bg:           var(--dp-red);
    --bs-btn-hover-border-color: var(--dp-red);
    --bs-btn-active-bg:          var(--dp-red-dark);
    --bs-btn-active-border-color: var(--dp-red-dark);
    --bs-btn-hover-color:        #fff;
}

.btn {
    font-size: 0.875rem;
    border-radius: 4px;
}

.btn-sm {
    font-size: 0.8rem;
}

/* ---------------------------------------------------------------------------
   Badges
   --------------------------------------------------------------------------- */
.badge.bg-primary {
    background-color: var(--dp-red) !important;
}

.badge.bg-warning {
    background-color: var(--dp-yellow) !important;
    color: var(--dp-charcoal) !important;
}

/* ---------------------------------------------------------------------------
   Forms
   --------------------------------------------------------------------------- */
.form-control:focus,
.form-select:focus {
    border-color: rgba(149, 0, 20, 0.4);
    box-shadow: 0 0 0 0.2rem rgba(149, 0, 20, 0.12);
}

.form-check-input:focus {
    box-shadow: 0 0 0 0.2rem rgba(149, 0, 20, 0.12);
}

.form-label {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--dp-text);
    margin-bottom: 0.35rem;
}

.form-text {
    font-size: 0.8rem;
    color: var(--dp-text-muted);
}

.form-check-input:checked {
    background-color: var(--dp-red);
    border-color: var(--dp-red);
}

/* ---------------------------------------------------------------------------
   Section headings (used in config & masters detail pages)
   --------------------------------------------------------------------------- */
.dp-section-heading {
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--dp-red);
    border-bottom: 2px solid var(--dp-red);
    padding-bottom: 0.35rem;
    margin-bottom: 1.25rem;
    margin-top: 1.75rem;
}

.dp-section-heading:first-child {
    margin-top: 0;
}

/* ---------------------------------------------------------------------------
   Alert / flash messages
   --------------------------------------------------------------------------- */
.alert {
    border-radius: 5px;
    font-size: 0.875rem;
    border-left-width: 4px;
}

.alert-success {
    border-left-color: #198754;
}

.alert-danger {
    border-left-color: var(--dp-red);
}

.alert-warning {
    border-left-color: var(--dp-yellow);
}

/* ---------------------------------------------------------------------------
   Links
   --------------------------------------------------------------------------- */
a {
    color: var(--dp-red);
    text-decoration: none;
}

a:hover {
    color: var(--dp-red-dark);
    text-decoration: underline;
}

/* ---------------------------------------------------------------------------
   Pagination
   --------------------------------------------------------------------------- */
.page-link {
    color: var(--dp-red);
}

.page-item.active .page-link {
    background-color: var(--dp-red);
    border-color: var(--dp-red);
    color: #fff;
}

/* ---------------------------------------------------------------------------
   Breadcrumb
   --------------------------------------------------------------------------- */
.breadcrumb {
    font-size: 0.8rem;
    margin-bottom: 0.5rem;
}

.breadcrumb-item a {
    color: var(--dp-red);
}

/* ---------------------------------------------------------------------------
   Detail definition layout (details pages)
   --------------------------------------------------------------------------- */
.dp-detail-row {
    display: flex;
    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
    padding: 0.55rem 0;
    font-size: 0.875rem;
    gap: 1rem;
}

.dp-detail-row:last-child {
    border-bottom: none;
}

.dp-detail-label {
    min-width: 180px;
    color: var(--dp-text-muted);
    font-weight: 600;
    font-size: 0.8rem;
    flex-shrink: 0;
}

.dp-detail-value {
    color: var(--dp-text);
    flex: 1;
    word-break: break-word;
}

/* A table cell holding a long, space-free string (a token, a URL) must not force the whole
   table wider than the page — table columns otherwise size to their longest unbroken content. */
.dp-wrap-anywhere {
    overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------------------
   Footer
   --------------------------------------------------------------------------- */
/* Light-background footer — same flex-row shape and wording as .dp-auth-footer (the login
   page's dark bar), just recoloured for a white/light context. Shared by the admin layout
   and the customer portal so both stay visually and textually consistent. */
.dp-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
    margin-top: 3rem;
    padding: 1.1rem 0 0.5rem;
    border-top: 1px solid var(--dp-border);
    font-size: 0.8rem;
    color: var(--dp-text-muted);
}

.dp-footer__text p {
    margin: 0;
}

.dp-footer a {
    color: var(--dp-text-muted);
    text-decoration: none;
}

.dp-footer a:hover {
    color: var(--dp-red);
    text-decoration: underline;
}

.dp-footer__logo-link {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
}

.dp-footer__logo-link img {
    height: 26px;
    width: auto;
    opacity: 0.75;
    transition: opacity 0.15s;
}

.dp-footer__logo-link img:hover {
    opacity: 1;
}

.dp-footer__version {
    font-size: 0.72rem;
    opacity: 0.65;
    line-height: 1.3;
}

.dp-footer__legal {
    font-size: 0.72rem;
    opacity: 0.65;
    line-height: 1.3;
    margin-top: 0.15rem;
}

.dp-footer__legal a {
    text-decoration: none;
}

.dp-footer__legal a:hover {
    text-decoration: underline;
}

.dp-footer__legal span {
    margin: 0 0.4em;
    opacity: 0.6;
}

/* ---------------------------------------------------------------------------
   Responsive — mobile
   --------------------------------------------------------------------------- */
@media (max-width: 991.98px) {
    .dp-topbar__hamburger {
        display: flex;
    }

    /* Mobile-only: the Porsche wordmark at its full 200px desktop width leaves almost no
       room for the hamburger/brand text/logout on a phone-width screen — scaled down a
       further 25% here (matching the fixed-width hamburger fix above), on top of the 20%
       reduction already applied to the desktop base above. */
    .dp-topbar__logo {
        width: 150px;
    }

    /* Version badge and username are decorative/already-redundant on a cramped mobile header
       (the sidebar gives full context once opened) — hidden so the functionally essential
       controls (hamburger, centred logo, logout) always fit and stay reachable. */
    .dp-version-badge,
    .dp-topbar__user {
        display: none;
    }

    .dp-sidebar {
        transform: translateX(-100%);
    }

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

    .dp-main {
        margin-left: 0;
        padding: 1.25rem;
    }

    .dp-page-header {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* ---------------------------------------------------------------------------
   Customer portal layout
   --------------------------------------------------------------------------- */

.dp-portal-body {
    background: var(--dp-bg-gradient);
    background-attachment: fixed;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.dp-portal-header {
    background: var(--dp-charcoal);
    border-bottom: 3px solid var(--dp-header-line);
    padding: 0.75rem 0;
}

.dp-portal-header__inner {
    display: flex;
    align-items: center;
    justify-content: center;
    /* Pinned to the logo's own PRE-resize height (22px; 16.5px mobile, overridden below), not
       its current, much smaller rendered size (see .dp-portal-header__logo below) —
       .dp-portal-header's own padding is fixed, so without this the black bar itself shrinks
       along with the logo. min-height keeps the bar the size it always was; align-items centers
       the now-smaller logo inside it. */
    min-height: 22px;
}

.dp-portal-header__logo-link {
    display: flex;
    align-items: center;
    text-decoration: none;
}

/* Sized to match .dp-topbar__logo's own rendered scale exactly, not a percentage off this
   header's own prior 22px — the admin topbar's logo is constrained by WIDTH (200px), this one
   by HEIGHT, so matching either dimension matches both (same artwork, same 4500:300 viewBox
   ratio): 200 / (4500/300) = 13.33px. Deliberately not "20% smaller than before" a second time —
   confirmed live in both Safari and Chrome that the 20%-off value (17.6px) was already rendering
   correctly; it just never looked comparable to admin's, because the two started from different
   absolute sizes before any of this. */
.dp-portal-header__logo {
    height: 13.33px;
    width: auto;
    fill: #fff;
}

@media (max-width: 991.98px) {
    /* Same reasoning as the desktop rule above, matched against .dp-topbar__logo's own mobile
       width (150px): 150 / 15 = 10px exactly. */
    .dp-portal-header__logo {
        height: 10px;
    }

    /* Same fixed-bar-height reasoning as the desktop min-height above, pinned to mobile's own
       pre-resize logo height (16.5px). */
    .dp-portal-header__inner {
        min-height: 16.5px;
    }
}

.dp-portal-main {
    flex: 1;
    padding: 2.5rem 0 3rem;
}

/* Customer-facing action buttons are black, not red — scoped to .dp-portal-body only (two
   classes beats the base .btn-primary/.btn-outline-primary/.btn-outline-danger rules' one
   class, so this wins regardless of source order); admin keeps its red buttons. */
.dp-portal-body .btn-primary {
    --bs-btn-bg:              var(--dp-charcoal);
    --bs-btn-border-color:    var(--dp-charcoal);
    --bs-btn-hover-bg:        #000000;
    --bs-btn-hover-border-color: #000000;
    --bs-btn-active-bg:       #000000;
    --bs-btn-active-border-color: #000000;
    --bs-btn-focus-shadow-rgb: 25, 31, 34;
}

.dp-portal-body .btn-outline-primary,
.dp-portal-body .btn-outline-danger {
    --bs-btn-color:              var(--dp-charcoal);
    --bs-btn-border-color:       var(--dp-charcoal);
    --bs-btn-hover-bg:           var(--dp-charcoal);
    --bs-btn-hover-border-color: var(--dp-charcoal);
    --bs-btn-active-bg:          #000000;
    --bs-btn-active-border-color: #000000;
    --bs-btn-hover-color:        #fff;
}

/* Offer card */
.dp-offer-card {
    background: #fff;
    border: 1px solid #dee2e6;
    border-radius: 4px;
    padding: 2rem;
}

.dp-offer-card__product-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 0.5rem 0;
}

.dp-offer-card__product-row + .dp-offer-card__product-row {
    border-top: 1px solid #f0f0f0;
}

.dp-offer-card__total-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 0.75rem 0 0;
    border-top: 2px solid var(--dp-charcoal);
    font-weight: 600;
}

.dp-offer-card__price {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--dp-charcoal);
}

/* Decline / NoLongerOwn pages: a small, personalised header (greeting + vehicle) — deliberately
   the subtle sibling of the Offer page's full hero-card treatment (.dp-offer-card--hero), since
   these pages have no quote/pricing content to lead with. A thin bottom rule separates it from
   the confirmation copy below without the weight of a second card. */
.dp-decline-context {
    border-bottom: 1px solid #eee;
    padding-bottom: 1rem;
}
.dp-decline-context__image {
    height: 56px;
    width: auto;
    object-fit: contain;
    border-radius: 6px;
    flex-shrink: 0;
}

/* "What does this plan cover?" disclosure — native <details>/<summary>, deliberately no JS
   backing it (see the 2026-06-30 "native HTML5 details/summary" decision). Replaces each
   browser's own default marker with a Porsche-red chevron, matching the same visual language
   already established for the admin nav's collapsible-group indicator (.dp-nav-chevron) — down
   (▼) when expanded, rotated to point right (▶) at rest, driven purely by the [open] attribute
   selector rather than JS. */
.dp-offer-summary {
    list-style: none;
    cursor: pointer;
    user-select: none;
}
.dp-offer-summary::-webkit-details-marker {
    display: none;
}
.dp-offer-summary .dp-offer-summary__chevron {
    display: inline-block;
    margin-left: 0.35rem;
    color: var(--dp-red);
    font-size: 0.85em;
    line-height: 1;
    vertical-align: middle;
    transition: transform 0.15s;
    transform: rotate(-90deg);
}
details[open] > .dp-offer-summary .dp-offer-summary__chevron {
    transform: rotate(0deg);
}

/* Portal Offer page: the primary "Your renewal offer" card gets real visual weight, distinct
   from the plain, secondary Odometer Reading card below it — reusing the same accent-bar +
   sheen + glass + corner-glow language already established for the Dashboard's KPI cards
   (.dp-payment-card--kpi), just sized for a large content card instead of a small tile.
   The glass panel covers the WHOLE card (::before, inset:0) — including behind/around the
   image — not just the text area below it, since a smaller glass surface reads as much less
   "glassy" even at the same opacity, simply because there's less of it visible on screen. This
   restores the shape (full-card coverage, this opacity level) that was confirmed genuinely
   visible in a real browser session mid-development — a later "fix" for a headless-Chrome-only
   <img> blur-bleed risk shrank the glass surface to just the text area, which visibly killed
   the effect; reverted here in favour of matching the confirmed-working real-browser result.
   If the vehicle photo is ever seen looking soft/hazy rather than crisp in a real browser
   (the headless-only risk this shape carries), the fix is to scope the glass panel to exclude
   the image's own box — tried and confirmed working, at the cost of roughly half the visible
   glass surface; only worth doing if the bleed is ever actually observed outside headless
   Chrome, which it wasn't during live testing. */
.dp-offer-card--hero {
    position: relative;
    overflow: hidden;
    background: transparent;
    border: 1px solid rgba(0, 0, 0, 0.06);
    border-top: 4px solid var(--dp-charcoal-light);
    box-shadow:
        0 12px 32px rgba(25, 31, 34, 0.14),
        inset 0 1px 0 rgba(255, 255, 255, 0.75);
}
.dp-offer-card--hero::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    background:
        linear-gradient(135deg, rgba(255, 255, 255, 0.42) 0%, rgba(255, 255, 255, 0.12) 45%, rgba(255, 255, 255, 0.02) 100%),
        var(--dp-glass-bg);
    backdrop-filter: blur(calc(var(--dp-glass-blur) + 6px)) saturate(160%);
    -webkit-backdrop-filter: blur(calc(var(--dp-glass-blur) + 6px)) saturate(160%);
}
.dp-offer-card--hero::after {
    content: '';
    position: absolute;
    top: -50px;
    right: -40px;
    width: 150px;
    height: 150px;
    border-radius: 50%;
    background: var(--dp-red);
    opacity: 0.06;
    z-index: 0;
    pointer-events: none;
}
.dp-offer-card--hero .dp-offer-card__content {
    position: relative;
    z-index: 1;
}

/* Total price — the one number that actually matters on this page, given real presence instead
   of matching the same visual weight as the coverage dates line above it. */
.dp-offer-total-hero {
    position: relative;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 1rem 1.25rem;
    margin-top: 0.75rem;
    background: rgba(61, 78, 84, 0.06);
    border-radius: 6px;
    border-top: 2px solid var(--dp-charcoal-light);
}
.dp-offer-total-hero__label {
    font-size: 0.9rem;
    color: var(--dp-charcoal);
    font-weight: 600;
}
.dp-offer-total-hero__amount {
    font-size: 2rem;
    font-weight: 700;
    color: var(--dp-charcoal);
    line-height: 1;
}

/* Coverage checklist — replaces dense comma-separated prose with short, scannable phrases, each
   with an icon. Includes get a green checkmark; Excludes (where present) get their own short
   list underneath in muted grey with a plain dash — "not included," not a warning, so no red/
   alarm colour is used for it. */
.dp-coverage-list {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 0.85rem;
    line-height: 1.4;
}
.dp-coverage-list li {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
    color: #444;
}
.dp-coverage-list li:last-child {
    margin-bottom: 0;
}
.dp-coverage-list__icon {
    flex-shrink: 0;
    width: 15px;
    height: 15px;
    margin-top: 0.2em;
}
.dp-coverage-list--includes .dp-coverage-list__icon {
    color: #1a7f37;
}
.dp-coverage-list--excludes {
    margin-top: 0.6rem;
}
.dp-coverage-list--excludes li {
    color: #888;
}
.dp-coverage-list--excludes .dp-coverage-list__icon {
    color: #aaa;
}

/* Step strip (Review / Sign / Pay) — a solid dark bar rather than text-shadow-on-photo, since
   the latter has already proven unreliable on this exact page against a real, unpredictable
   workshop photo (see the 2026-07-08 "text-shadow wasn't enough" fix) — a solid background
   guarantees legibility regardless of what's behind it. Shared across every page in the
   renewal journey (see _StepStrip.cshtml) so the customer's sense of "where am I" carries
   through, not just on the first page they land on. */
.dp-offer-steps {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0;
    margin-bottom: 1.25rem;
    padding: 0.55rem 1.25rem;
    background: rgba(25, 31, 34, 0.88);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    border-radius: 999px;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
}
.dp-offer-steps__step {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.55);
    white-space: nowrap;
}
.dp-offer-steps__step.is-active {
    color: #fff;
}
.dp-offer-steps__step.is-complete {
    color: rgba(255, 255, 255, 0.85);
}
.dp-offer-steps__circle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.2);
    font-size: 0.7rem;
    flex-shrink: 0;
}
.dp-offer-steps__step.is-active .dp-offer-steps__circle {
    background: var(--dp-red);
    color: #fff;
}
.dp-offer-steps__step.is-complete .dp-offer-steps__circle {
    background: rgba(255, 255, 255, 0.35);
    color: #fff;
}
.dp-offer-steps__line {
    width: 32px;
    height: 2px;
    background: rgba(255, 255, 255, 0.25);
    margin: 0 0.6rem;
    flex-shrink: 0;
}

/* Auth layout (login / MFA / change-password / forgot-password / access-denied) — full-bleed
   rotating background image (see _AuthLayout.cshtml for the random-pick logic), shown at full
   brightness with no dark overlay (matches the reference Events Manager login pages — Bentley,
   Lamborghini). Contrast comes from a semi-transparent frosted-glass card and a solid dark
   footer bar, not from dimming the photo. Falls back to a plain charcoal background when
   wwwroot/images/login-backgrounds/ has no images yet. */
.dp-auth-body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    background-color: var(--dp-charcoal);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    background-attachment: fixed;
}

.dp-auth-scrim {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.dp-auth-header {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem 2rem 0;
}

.dp-auth-header__logo {
    height: 20.8px;
    width: auto;
    fill: #fff;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
}

.dp-auth-main {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2.5rem 1rem;
}

/* Frosted glass — content behind it (the background photo) still shows through. */
.dp-auth-card {
    background: var(--dp-glass-bg);
    backdrop-filter: blur(var(--dp-glass-blur));
    -webkit-backdrop-filter: blur(var(--dp-glass-blur));
    border: 1px solid rgba(255, 255, 255, 0.4);
    border-radius: 6px;
    padding: 2.5rem;
    width: 100%;
    max-width: 420px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
}

/* The status-code number on the branded 404/401/error page — a small, prominent red
   accent, matching how the reference page highlights its own "ERROR 404:" prefix. */
.dp-status-error-code {
    color: var(--dp-red);
    font-weight: 700;
    font-size: 0.85rem;
    letter-spacing: 0.08em;
    margin-bottom: 0.5rem;
}

/* Slim solid dark bar, logo inline with the text (not stacked) — keeps the footer
   legible regardless of what's behind it while minimising the dark footprint. */
.dp-auth-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem 1.5rem;
    padding: 0.65rem 2rem;
    color: rgba(255, 255, 255, 0.65);
    font-size: 0.8rem;
    background: rgba(25, 31, 34, 0.92);
    margin-top: auto;
}

.dp-auth-footer__text p {
    margin: 0;
}

.dp-auth-footer a {
    color: rgba(255, 255, 255, 0.85);
}

.dp-auth-footer a:hover {
    color: var(--dp-yellow);
}

.dp-auth-footer__logo-link {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
}

.dp-auth-footer__logo-link img {
    height: 26px;
    width: auto;
}

.dp-auth-footer__version {
    font-size: 0.72rem;
    opacity: 0.75;
}

.dp-auth-footer__legal {
    font-size: 0.72rem;
    opacity: 0.65;
    margin-top: 0.15rem;
}

.dp-auth-footer__legal a {
    text-decoration: none;
}

.dp-auth-footer__legal a:hover {
    text-decoration: underline;
}

.dp-auth-footer__legal span {
    margin: 0 0.4em;
    opacity: 0.6;
}

/* Password show/hide toggle — wraps an <input> + <button class="dp-password-toggle"> */
.dp-password-field {
    position: relative;
}

.dp-password-field .form-control {
    padding-right: 3.5rem;
}

.dp-password-toggle {
    position: absolute;
    top: 0;
    right: 0;
    height: 100%;
    padding: 0 0.9rem;
    background: transparent;
    border: none;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--dp-charcoal);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    cursor: pointer;
    z-index: 5;
}

.dp-password-toggle:hover {
    color: var(--dp-red);
}

/* Signature pad */
.dp-signature-canvas {
    border: 2px solid #ced4da;
    border-radius: 4px;
    cursor: crosshair;
    touch-action: none;
    background: #fff;
}

.dp-signature-canvas:focus {
    outline: 2px solid var(--dp-red);
    outline-offset: 2px;
}

/* Payment choice cards — same frosted-glass material as the login card (.dp-auth-card),
   recoloured for a light page background: semi-transparent white + blur + soft shadow
   instead of a flat grey block, with a clearer lift-and-glow on hover/selection. */
.dp-payment-card {
    position: relative;
    background: var(--dp-glass-bg);
    backdrop-filter: blur(var(--dp-glass-blur));
    -webkit-backdrop-filter: blur(var(--dp-glass-blur));
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 6px;
    padding: 1.5rem;
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s, background-color 0.15s;
    box-shadow: 0 2px 10px rgba(25, 31, 34, 0.06);
    height: 100%;
}

.dp-payment-card:hover:not(.dp-payment-card--static),
.dp-payment-card.is-selected {
    border-color: var(--dp-red);
    background: var(--dp-glass-bg-active);
    box-shadow: 0 10px 28px rgba(149, 0, 20, 0.14);
    transform: translateY(-3px);
}

/* Modifier, applied alongside the base class (class="dp-payment-card dp-payment-card--static") —
   same convention as .dp-payment-card--kpi below. For a block using the same glass material but
   that isn't itself the click target (only a button inside it is): no pointer cursor, no
   hover-lift (excluded above via :not()), and a shorter, non-stretched height since it isn't a
   sibling in a flex-stretch row like the two payment-method cards are. */
.dp-payment-card--static {
    cursor: default;
    padding: 1.25rem 1.5rem;
    height: auto;
}

/* Dashboard KPI accent — a coloured top bar plus a soft, low-opacity glow tucked into the
   corner, identifying what KIND of metric a card represents (not whether it's currently
   notable — the big number's own colour, via ValueCssClass, already does that). Deliberately
   subtle: this is about giving each card its own visual identity on an otherwise flat page,
   not about alarm colours. data-accent picks the palette; see DashboardKpiCardViewModel.
   The Dashboard sits on default-background.jpg — a near-white, low-contrast embossed leather
   texture (confirmed by inspecting the actual file). Blur+saturate alone barely reads as
   "glass" here, because there's almost no colour/detail behind the card for either to visibly
   act on — a frosted-glass effect only looks glassy when there's something with contrast to
   distort. What DOES read as glass regardless of what's behind it is light/shadow modelling: a
   diagonal specular "sheen" gradient (bright top-left fading out, as if catching a light
   source) layered on top of the shared --dp-glass-bg tint, plus a more pronounced outer lift
   shadow so the card reads as a raised, dimensional glass slab rather than a flat tinted
   rectangle. */
.dp-payment-card--kpi {
    position: relative;
    overflow: hidden;
    background:
        linear-gradient(135deg, rgba(255, 255, 255, 0.65) 0%, rgba(255, 255, 255, 0.15) 45%, rgba(255, 255, 255, 0.02) 100%),
        var(--dp-glass-bg);
    backdrop-filter: blur(calc(var(--dp-glass-blur) + 6px)) saturate(160%);
    -webkit-backdrop-filter: blur(calc(var(--dp-glass-blur) + 6px)) saturate(160%);
    border-top: 4px solid var(--dp-charcoal-light);
    box-shadow:
        0 10px 24px rgba(25, 31, 34, 0.14),
        inset 0 1px 0 rgba(255, 255, 255, 0.75),
        inset 0 -14px 24px -18px rgba(25, 31, 34, 0.12);
}

.dp-payment-card--kpi:hover {
    background:
        linear-gradient(135deg, rgba(255, 255, 255, 0.75) 0%, rgba(255, 255, 255, 0.2) 45%, rgba(255, 255, 255, 0.04) 100%),
        var(--dp-glass-bg-active);
    box-shadow:
        0 16px 34px rgba(25, 31, 34, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.85),
        inset 0 -14px 24px -18px rgba(25, 31, 34, 0.14);
}

/* The card is an <a>; nothing about it should read as a link except by behaviour. */
.dp-payment-card--kpi,
.dp-payment-card--kpi:hover {
    color: inherit;
    text-decoration: none;
}

/* Icon watermark, adopted from the Admin3 design experiment — replaces the soft accent-coloured
   corner circle this card carried before, which said nothing about the metric. Sized well past
   the card's own corner and clipped by its overflow:hidden, so it reads as a bled watermark
   rather than a picture placed in the card. */
.dp-kpi-icon {
    position: absolute;
    right: -14px;
    bottom: -14px;
    width: 104px;
    height: 104px;
    color: var(--dp-kpi-accent, var(--dp-charcoal-light));
    opacity: 0.08;
    pointer-events: none;
}

.dp-kpi-icon svg {
    width: 100%;
    height: 100%;
    display: block;
}

/* The watermark is positioned, so it would otherwise paint over this in-flow text. */
.dp-kpi-label,
.dp-kpi-value,
.dp-kpi-subtext {
    position: relative;
    z-index: 1;
}

/* tabular-nums keeps the number the same width at every value, so the count-up animation
   (js/kpi-cards.js) does not visibly jitter the digits as it runs. */
.dp-kpi-value {
    font-variant-numeric: tabular-nums;
}

.dp-payment-card--kpi[data-accent="red"]      { --dp-kpi-accent: var(--dp-red);        border-top-color: var(--dp-red); }
.dp-payment-card--kpi[data-accent="amber"]    { --dp-kpi-accent: var(--dp-yellow);     border-top-color: var(--dp-yellow); }
.dp-payment-card--kpi[data-accent="green"]    { --dp-kpi-accent: var(--bs-success);    border-top-color: var(--bs-success); }
.dp-payment-card--kpi[data-accent="blue"]     { --dp-kpi-accent: var(--bs-info);       border-top-color: var(--bs-info); }
.dp-payment-card--kpi[data-accent="charcoal"] { --dp-kpi-accent: var(--dp-charcoal);   border-top-color: var(--dp-charcoal); }

/* Reserves 3 lines (4.5em, at this label's own 1.5em line-height) so every card's number lands
   on the same baseline regardless of how much its own label wraps — see decisions.md for the
   measured numbers. Do NOT re-add flex: 1 1 auto here: in this column flex container it makes
   the label grow past that reservation. Deliberately NOT cursor: help — the whole card is a
   link and clicking the label navigates, so the help cursor would describe the wrong action. */
.dp-kpi-label {
    min-height: 4.5em;
}

/* ---- KPI hover-expand breakdown panel ----
   Ported from the Admin2 experiment (wwwroot/admin2/css/dashboard.css) so both dashboards use the
   identical mechanism — a card whose .dp-payment-card--kpi needs overflow:hidden (for its own
   corner-glow ::after) can't also host an absolutely-positioned panel as a CHILD without clipping
   it, so the panel is a SIBLING of the card instead, both wrapped in .dp-kpi-slot, which is what
   the panel's top:calc(100% + Xpx) positions itself against. */
.dp-kpi-slot {
    position: relative;
    height: 100%;
}

.dp-kpi-breakdown {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 8px);
    background: var(--dp-bg-card);
    border: 1px solid var(--dp-border);
    border-radius: 6px;
    box-shadow: 0 16px 34px rgba(25, 31, 34, 0.18);
    padding: 14px 16px;
    z-index: 20;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px);
    pointer-events: none;
    transition: opacity 0.22s ease, transform 0.22s ease, visibility 0s linear 0.22s;
}

.dp-kpi-slot--expandable:hover .dp-kpi-breakdown,
.dp-kpi-slot--expandable:focus-within .dp-kpi-breakdown {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
    transition: opacity 0.22s ease, transform 0.22s ease, visibility 0s;
}

.dp-kpi-breakdown-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    padding: 6px 0;
    font-size: 0.75rem;
    border-bottom: 1px dashed var(--dp-border);
}

.dp-kpi-breakdown-row:last-child {
    border-bottom: none;
}

/* min-width: 0 overrides a flex item's default min-width: auto, which otherwise refuses to
   shrink below the label's min-content width — for a single unbroken word like
   "PausedCustomerQuery" that is the whole word, and the count gets pushed out past the panel.
   Shortening the labels (KpiBreakdownBuilder.ActiveCycleBreakdownLabel) is the first half of
   this; these two rules are what make it structurally impossible rather than merely unlikely. */
.dp-kpi-breakdown-row__label {
    color: var(--dp-text-muted);
    min-width: 0;
    overflow-wrap: anywhere;
}

.dp-kpi-breakdown-row__value {
    font-weight: 600;
    display: flex;
    gap: 6px;
    align-items: baseline;
    flex-shrink: 0;
}

.dp-kpi-breakdown-row__money {
    font-weight: 400;
    color: var(--dp-text-muted);
    font-size: 0.7rem;
}

.dp-kpi-breakdown-footer {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--dp-border);
    font-size: 0.7rem;
    color: var(--dp-text-muted);
}

@media (prefers-reduced-motion: reduce) {
    .dp-kpi-breakdown {
        transition: none;
    }
}

/* ---- KPI label tooltip ----
   Adopted from the Admin3 design experiment. Deliberately not Bootstrap's tooltip (which the
   layout still initialises globally for every [data-bs-toggle="tooltip"] elsewhere): this one is
   wider, wraps at a readable measure, and is what the ⓘ button's replacement was approved as.
   Positioned and appended to <body> by js/kpi-cards.js — see that file for why it cannot be a
   child of the card. */
.dp-tooltip {
    position: fixed;
    z-index: 1080;
    max-width: 280px;
    background-color: var(--dp-charcoal);
    color: #fff;
    font-size: 0.75rem;
    line-height: 1.45;
    padding: 8px 11px;
    border-radius: 4px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.22);
    opacity: 0;
    transition: opacity 0.12s;
    pointer-events: none;
}

.dp-tooltip.is-visible {
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    .dp-tooltip {
        transition: none;
    }
}

/* Bootstrap's built row-cols-* utilities stop at 6 (its default $grid-row-columns) — the
   Dashboard's own KPI row grew to 7 cards, and the row's existing comment already anticipated
   more being added later with "no column-width rebalancing needed". One rule, matching
   Bootstrap's own generated shape exactly, rather than rebuilding Bootstrap for one column count. */
@media (min-width: 1200px) {
    .row-cols-xl-7 > * {
        flex: 0 0 auto;
        width: 14.28571429%;
    }
}

/* ---- Upcoming Expirations by-month: 4-card sliding window + chevron nav ----
   The "in view" card layers a strong ring onto its existing glass shadow (all three original
   layers kept, not replaced). Deliberately not a thicker border-top instead — a border adds to
   box height and shifts this card's number down relative to its same-height siblings; box-shadow
   is paint-only and can't. Older/newer cards differ only by AccentColor (set at the call site)
   plus a small opacity dip on the older one — kept subtle by design, see decisions.md. */
.dp-month-card--current {
    box-shadow:
        0 0 0 3px var(--dp-kpi-accent, var(--dp-red)),
        0 10px 24px rgba(25, 31, 34, 0.14),
        inset 0 1px 0 rgba(255, 255, 255, 0.75),
        inset 0 -14px 24px -18px rgba(25, 31, 34, 0.12);
}

.dp-month-card--older {
    opacity: 0.82;
}

.dp-month-nav-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    border: 1px solid var(--dp-border);
    background: var(--dp-bg-card);
    color: var(--dp-red);
    font-size: 1rem;
    line-height: 1;
    text-decoration: none;
    flex-shrink: 0;
    transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s;
}

.dp-month-nav-btn:hover {
    border-color: var(--dp-red);
    background: var(--dp-red-light);
    box-shadow: 0 2px 8px rgba(149, 0, 20, 0.14);
    color: var(--dp-red);
}

.dp-month-nav-btn--disabled {
    color: var(--dp-text-muted);
    opacity: 0.4;
    cursor: default;
    pointer-events: none;
}

.dp-payment-card__title {
    font-size: 1.1rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
}

.dp-payment-card__logos {
    display: block;
    max-width: 100%;
    height: auto;
    margin-top: 0.85rem;
}

/* Secondary CTA over a photo background — Bootstrap's plain btn-outline-secondary reads as
   near-invisible grey-on-photo until hover. A firm, mostly-opaque surface at rest keeps it
   legible against any background photo; Porsche red on hover ties it to every other CTA. */
.dp-invoice-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: rgba(255, 255, 255, 0.82);
    border: 1.5px solid rgba(25, 31, 34, 0.3);
    border-radius: 4px;
    padding: 0.6rem 1.25rem;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--dp-charcoal);
    text-decoration: none;
    box-shadow: 0 2px 10px rgba(25, 31, 34, 0.12);
    transition: border-color 0.15s, background-color 0.15s, color 0.15s, box-shadow 0.15s;
}

.dp-invoice-link:hover,
.dp-invoice-link:focus {
    border-color: var(--dp-red);
    background: #ffffff;
    color: var(--dp-red);
    box-shadow: 0 6px 18px rgba(149, 0, 20, 0.22);
}

/* ---------------------------------------------------------------------------
   System Config grouped-form + email template header-image widget
   --------------------------------------------------------------------------- */

/* Compact field row (System Settings grouped form) */
.dp-config-row {
    padding: 0.35rem 0;
    border-bottom: 1px solid #f0f0f0;
}
.dp-config-row:last-child { border-bottom: none; }

.dp-config-label {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--dp-charcoal);
    margin-bottom: 0;
}

/* Tooltip (i) icon — no underline, red, compact superscript, matches the reference
   Porsche admin systems' styling (Events Manager family). Reused anywhere a field needs
   an inline help tooltip, not just System Config. */
.dp-tooltip-icon {
    display: inline-block;
    font-size: 0.65em;
    line-height: 0;
    vertical-align: super;
    color: var(--dp-red);
    text-decoration: none !important;
    background: none;
    border: none;
    padding: 0;
    margin-left: 0.2rem;
    cursor: help;
    /* Never squeezed by a sibling label in the same flex row — a fixed-size
       glyph has nothing to gain from shrinking, and every bit of the row's flex-shrink pressure
       should land on the label's own text instead. */
    flex-shrink: 0;
}
.dp-tooltip-icon:hover,
.dp-tooltip-icon:focus {
    color: var(--dp-red-dark);
    text-decoration: none !important;
}
/* Bootstrap's .form-floating > label sets pointer-events:none (so clicking anywhere in the
   label area focuses the input instead) — that would make a tooltip icon nested inside a
   floating label completely unhoverable/unclickable. Restore pointer events for just the
   icon itself; the rest of the label stays click-through as normal. */
.form-floating > label .dp-tooltip-icon {
    pointer-events: auto;
}

/* Sortable table headers. Two mechanisms share this styling deliberately, so a sortable column
   looks and feels identical wherever it appears:
     - client-side (wwwroot/js/sortable-table.js) — add class="dp-sortable" to an UNPAGED table;
     - server-side (_SortHeader.cshtml)           — for a PAGED table, which must sort in the
       database or it would only reorder the visible page.
   A table never uses both: the script skips [data-server-sort], and AdminSortingConsistencyTests
   fails the build if a paged view tries to sort client-side. */
.dp-sortable-header {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.dp-sortable-header:hover {
    background-color: rgba(0, 0, 0, 0.04);
}
.dp-sort-indicator {
    display: inline-block;
    margin-left: 0.35rem;
    font-size: 0.7em;
    color: var(--dp-red);
}

/* The server-sorted header is an <a> so it can carry the sort/filter/page query string, but it
   must not read as a link — it should be indistinguishable from a client-sorted <th>. */
.dp-sort-link,
.dp-sort-link:hover,
.dp-sort-link:focus {
    color: inherit;
    text-decoration: none;
    display: block;
}

/* Date-field display-format overlay (wwwroot/js/date-display-format.js) — wrap any
   native <input type="date"> in <div class="dp-date-field"> to guarantee its
   displayed value always reads dd/mm/yyyy, regardless of the visiting browser's own
   language setting (which is what actually controls a native date input's display —
   see the script's own header comment for why the page's own locale can't). The real
   native input still handles every actual interaction (calendar popup, typing,
   keyboard nav, the submitted value) — only its own text is hidden here, with the
   JS-rendered overlay standing in for it at all times, INCLUDING while focused.
   Earlier version of this fix un-masked the native input on :focus specifically to
   preserve its per-segment highlight box while editing — but that meant the one
   moment a user actually opens the calendar or clicks into the field (i.e. the
   moment they're most likely to be looking at it), the wrong-locale MM/DD/YYYY text
   reappeared, which is exactly the bug this whole mechanism exists to prevent.
   Masking the input's text colour doesn't disable any of its real functionality —
   the calendar popup, typing, and arrow-key segment navigation all still work
   normally underneath; Bootstrap's own :focus border/box-shadow styling (untouched
   here, since only `color` is overridden) still gives a clear focus affordance even
   without the native segment-highlight box. Both padding variants below match
   Bootstrap's .form-control / .form-control-sm exactly so the overlay text lines up
   pixel-for-pixel with where the native text would otherwise sit. */
.dp-date-field {
    position: relative;
}
.dp-date-field input[type="date"] {
    color: transparent;
}
.dp-date-field input[type="date"]::-webkit-datetime-edit-fields-wrapper {
    color: transparent;
}
.dp-date-field .dp-date-overlay {
    position: absolute;
    inset: 1px;
    display: flex;
    align-items: center;
    padding-left: 0.75rem;
    font-size: 1rem;
    pointer-events: none;
    /* Opaque, not transparent — while focused, the native input can draw its own
       segment-selection highlight underneath (a background box, independent of the
       text-colour masking above); an opaque overlay fully occludes it instead of
       letting it show through as a faint artifact. Matches Bootstrap's .form-control
       background; inset 1px (not 0) keeps clear of the input's own 1px border/focus
       ring so the overlay never paints over it. */
    background: #fff;
    color: var(--dp-charcoal);
    overflow: hidden;
    white-space: nowrap;
    border-radius: var(--bs-border-radius, 0.375rem);
}
.dp-date-field .dp-date-overlay.form-control-sm {
    padding-left: 0.5rem;
    font-size: 0.875rem;
}
.dp-date-field .dp-date-overlay.dp-date-overlay--empty {
    color: var(--dp-text-muted, #6c757d);
}
/* Real bug, found live (2026-07-15): the overlay's opaque background — necessary to
   fully hide the native input's own text (see the block comment above) — also hides
   Chrome's native calendar-picker-indicator icon, which normally renders at the same
   spot. The icon is still fully functional underneath (pointer-events:none lets every
   click reach it exactly as before), but with no VISIBLE icon there, a Chrome user has
   no cue that clicking that one spot — as opposed to the "text" showing the date, which
   in Chrome only focuses a segment rather than opening the calendar — is what actually
   opens it; they can only find it by trial ("only clickable in the right blank space").
   Safari doesn't have this problem because Safari opens its date picker on a click
   anywhere in the field, not just the icon, so the hidden icon was never noticed there.
   This purely-decorative icon restores the missing visual cue at the same position the
   real (invisible) native one occupies — it does not itself need to be clickable. */
.dp-date-field .dp-date-overlay::after {
    content: "";
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236c757d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
    background-size: contain;
    background-repeat: no-repeat;
    pointer-events: none;
}

/* Tooltip popup content (data-bs-custom-class="dp-config-tooltip") — wider box, left-aligned,
   brand charcoal background instead of Bootstrap's default near-black, with room for a full
   sentence rather than the default 200px max-width. Key terms inside the description (marked
   with **term** and converted to <strong class="dp-tooltip-highlight"> server-side) render in
   the brand highlight yellow, matching the reference Porsche admin system's tooltip styling. */
.dp-config-tooltip .tooltip-inner {
    max-width: 320px;
    text-align: left;
    background-color: var(--dp-charcoal);
    font-size: 0.8125rem;
    line-height: 1.5;
    padding: 0.6rem 0.75rem;
}
.dp-config-tooltip .tooltip-arrow::before {
    border-top-color: var(--dp-charcoal);
    border-bottom-color: var(--dp-charcoal);
    border-left-color: var(--dp-charcoal);
    border-right-color: var(--dp-charcoal);
}
.dp-tooltip-highlight {
    color: var(--dp-yellow);
    font-weight: 700;
}

/* Header image preview thumbnail (Email Templates Edit + System Config) */
.dp-header-image-preview {
    max-width: 240px;
    max-height: 70px;
    display: block;
    border: 1px solid #e0e0e0;
    border-radius: 2px;
    background: #f8f8f8;
    object-fit: contain;
}

/* ---------------------------------------------------------------------------
   Print
   --------------------------------------------------------------------------- */
@media print {
    .dp-topbar,
    .dp-sidebar,
    .dp-sidebar-overlay,
    .btn {
        display: none !important;
    }

    .dp-main {
        margin-left: 0 !important;
        padding: 0 !important;
    }

    body {
        background: #fff !important;
    }
}
