/* PlaneSales Public Website Styles */
/* [Requirement("FTR-PSG-2026-0112")] — prototype-v2 design system migration */
/* [Requirement("FTR-PSG-2026-0114")] — prototype-v2 full sync */

/* [RFT-PSG-2026-0727] The self-hosted typeface moved OUT of this file.

   RFT-PSG-2026-0626 self-hosted Roboto here, with the two woff2 in this app's own
   wwwroot/fonts/. RFT-PSG-2026-0727 consolidates the whole platform onto ONE face,
   Inter (Head Warden ruling 2026-09-06, GitHub issue #240 item 9), and moves the
   @font-face pair + the --ps-font-family token into the SHARED sheet:

       src/PlaneSales.UI.Shared/wwwroot/css/planesales.css
       (served to every app as _content/PlaneSales.UI.Shared/css/planesales.css)

   App.razor loads that sheet BEFORE this one, so --ps-font-family is always
   defined by the time these rules resolve. One copy of the woff2 now serves
   Public, Seller and Admin — a font in THIS wwwroot never served the other two,
   which is how Seller/Admin ended up rendering in Arial.

   The former Roboto woff2 in wwwroot/fonts/ were deleted with this change; the
   preload in Components/App.razor now points at the shared Inter `latin` subset.
   Still NO third-party font fetch, and CSP stays font-src 'self' data:. */

html, body {
    font-family: var(--ps-font-family, 'Inter', Arial, Helvetica, sans-serif);
    font-size: 14px;
    line-height: 1.6;
    background-color: var(--ps-bg-primary);
    color: var(--ps-text-secondary);
}

/* [RFT-PSG-2026-0621 M4.1] Horizontal-overflow safety net — no page may scroll sideways on
   mobile. `overflow-x: clip` (NOT `hidden`) is deliberate: `hidden` coerces the cross-axis to
   `auto` and turns the root into a scroll container, which would break every `position: sticky`
   element on the site (.filter-sidebar, .detail-sidebar, the enquiry/gallery rails). `clip`
   clips at the viewport without establishing a scroll container, so sticky keeps working AND the
   designated inner scrollers (.similar-carousel, the listings kind-tabs strip) still scroll
   horizontally on their own overflow-x:auto. This is a net, not a fix for a specific overflow. */
html { overflow-x: clip; }

/* Headings */
h1, h2, h3, h4, h5, h6 { color: var(--text-primary); font-weight: 500; line-height: 1.3; margin-bottom: 0.5em; }
h1 { font-size: 30px; font-weight: 700; }
h2 { font-size: 24px; font-weight: 700; }
h3 { font-size: 20px; font-weight: 500; }
h4 { font-size: 17px; font-weight: 500; }
h5 { font-size: 14px; font-weight: 500; }
h6 { font-size: 12px; font-weight: 500; color: var(--text-muted); }

@media (max-width: 767.98px) {
    h1 { font-size: 22px; }
    h2 { font-size: 18px; }
}

a, .btn-link {
    color: var(--ps-primary);
}

a:hover, .btn-link:hover {
    color: var(--ps-primary-hover);
}

/* Primary Button */
.btn-primary {
    /* [Sheet #41 item 2 — button consistency, 2026-09-03] Was var(--ps-primary) (#1B2E56 navy),
       which made the site carry TWO filled button colours: a navy primary (5 uses, all
       error-state retry buttons) and a blue variant (41 uses). Gavin asked for "blue with white
       writing" across the site, so this now matches that variant and every filled button agrees.
       (Deliberately not naming the other class here: a source test does IndexOf on it and prose
       appearing earlier in the file would shadow the real rule.)
       CONTRAST NOTE: white on --brand-blue (#2D93D1) is 3.38:1, BELOW the WCAG AA 4.5:1 threshold.
       That is pre-existing and already applies to all 41 uses of the blue variant — not introduced
       here. Darkening --brand-blue to #257BAF (4.63:1) fixes all 46 at once and is a one-line
       token change awaiting a Head Warden brand ruling. */
    color: #FFFFFF;
    background-color: var(--brand-blue);
    border-color: var(--brand-blue);
}

.btn-primary:hover,
.btn-primary:focus {
    color: #FFFFFF;
    background-color: var(--ps-primary-hover);
    border-color: var(--ps-primary-hover);
}

.btn-primary:active,
.btn-primary.active {
    background-color: var(--ps-primary-hover);
    border-color: var(--ps-primary-hover);
}

/* Secondary Button */
.btn-secondary {
    color: var(--ps-primary);
    background-color: var(--ps-secondary);
    border-color: var(--ps-secondary);
}

.btn-secondary:hover,
.btn-secondary:focus {
    color: var(--ps-primary);
    background-color: var(--ps-secondary-hover);
    border-color: var(--ps-secondary-hover);
}

/* Outline Buttons */
.btn-outline-primary {
    color: var(--ps-primary);
    border-color: var(--ps-primary);
}

.btn-outline-primary:hover,
.btn-outline-primary:focus {
    color: #FFFFFF;
    background-color: var(--ps-primary);
    border-color: var(--ps-primary);
}

.btn-outline-secondary {
    color: var(--ps-secondary);
    border-color: var(--ps-secondary);
}

.btn-outline-secondary:hover,
.btn-outline-secondary:focus {
    color: var(--ps-primary);
    background-color: var(--ps-secondary);
    border-color: var(--ps-secondary);
}

/* Focus States */
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
    box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem rgba(27, 46, 86, 0.5);
}

/* Text & Background Utilities */
.text-primary {
    color: var(--ps-primary) !important;
}

.text-secondary {
    color: var(--ps-text-secondary) !important;
}

.bg-primary {
    background-color: var(--ps-primary) !important;
}

.bg-secondary {
    background-color: var(--ps-secondary) !important;
}

.bg-light {
    background-color: var(--ps-bg-primary) !important;
}

/* ============================================================
   NAVIGATION — prototype-v2 ps-nav (light grey gradient)
   ============================================================ */

.ps-nav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--nav-height);
    background: linear-gradient(180deg, var(--panel-grad-top) 0%, var(--panel-grad-bottom) 100%);
    border-bottom: 1px solid var(--border-muted);
    z-index: 1000;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.10);
}

.ps-nav-inner {
    display: flex;
    align-items: flex-end;
    height: 100%;
    padding-bottom: 0;
}

.ps-nav-logo {
    display: flex;
    align-items: center;
    text-decoration: none;
    flex-shrink: 0;
    margin-right: 36px;
    padding-top: 20px;
    padding-bottom: 14px;
}

.ps-nav-logo:hover {
    text-decoration: none;
    opacity: 0.88;
}

.ps-nav-logo-img {
    height: 56px;
    width: auto;
    display: block;
}

.ps-logo-icon {
    font-size: 28px;
    margin-right: 8px;
}

.ps-logo-text {
    font-size: 18px;
    font-weight: 700;
    color: var(--brand-navy);
    line-height: 1.1;
}

.ps-logo-text span {
    display: block;
    font-size: 11px;
    font-weight: 400;
    color: var(--text-muted);
}

.ps-nav-links {
    display: flex;
    align-items: flex-end;
    gap: 4px;
    flex: 1;
}

.ps-nav-links a {
    color: var(--brand-navy);
    font-size: 15px;
    font-weight: 500;
    padding: 8px 16px 6px;
    border-radius: var(--r-xs) var(--r-xs) 0 0;
    transition: background var(--t-fast), color var(--t-fast);
    white-space: nowrap;
    display: block;
    text-decoration: none;
}

.ps-nav-links a:hover,
.ps-nav-links a.active {
    color: var(--brand-blue);
    background: rgba(27, 46, 86, 0.06);
    text-decoration: none;
    border-bottom: 3px solid var(--brand-blue);
}

.ps-nav-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    padding-bottom: 14px;
}

/* [BUG-PSG-2026-0729] The nav ghost-button rule moved out of this block and down into
   § 7 BUTTONS, beside the other button variants. The Sign In button now also carries the shared
   button base class so it matches the List Aircraft button's size and shape (Gavin, #278 comment
   2026-09-03). That base class is declared in § 7 with a transparent 1px border; at equal
   specificity the LATER rule wins, so leaving the ghost rule up here would have stripped the Sign
   In button's blue border the moment the base class was added. Live declaration: § 7 BUTTONS.
   NOTE: this comment deliberately names no selector literally — the CSS source tests extract a
   rule body by scanning forward from a selector token, and a dotted token inside a comment is read
   as a rule and fails the assertion against the following block. */

.ps-nav-hamburger {
    display: none;
    flex-direction: column;
    gap: 5px;
    cursor: pointer;
    padding: 8px;
    margin-left: auto;
    background: none;
    border: none;
}

.ps-nav-hamburger span {
    width: 22px;
    height: 2px;
    background: var(--brand-navy);
    border-radius: 2px;
    display: block;
}

/* ------------------------------------------------------------
   Mobile nav — off-canvas drawer (Bootstrap Offcanvas pattern)
   [Requirement("FTR-PSG-2026-0124")]
   ------------------------------------------------------------ */

/* Backdrop / overlay */
.ps-mobile-nav-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.5);
    z-index: 1040;
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--t-fast) ease, visibility var(--t-fast) ease;
}

.ps-mobile-nav-backdrop.show {
    opacity: 1;
    visibility: visible;
}

/* Drawer panel — slides in from the left */
.ps-mobile-nav {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: 300px;
    max-width: 85vw;
    background: #fff;
    box-shadow: 0 0 24px rgba(0,0,0,0.18);
    z-index: 1045;
    display: flex;
    flex-direction: column;
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform 0.3s ease, visibility 0.3s ease;
    overflow-y: auto;
}

.ps-mobile-nav.show {
    transform: translateX(0);
    visibility: visible;
}

.ps-mobile-nav-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border);
}

.ps-mobile-nav-title {
    font-size: 16px;
    font-weight: 700;
    color: var(--brand-navy);
}

.ps-mobile-nav-close {
    background: none;
    border: none;
    font-size: 28px;
    line-height: 1;
    color: var(--brand-navy);
    cursor: pointer;
    padding: 0 4px;
}

.ps-mobile-nav-close:hover {
    color: var(--brand-blue);
}

.ps-mobile-nav-body {
    flex: 1;
    padding: 8px 0 16px;
}

.ps-mobile-nav-link {
    display: block;
    padding: 12px 24px;
    color: var(--brand-navy);
    font-size: 14px;
    text-decoration: none;
    border-bottom: 1px solid var(--border);
}

.ps-mobile-nav-link:last-child,
.ps-mobile-nav-link-child:last-child {
    border-bottom: none;
}

.ps-mobile-nav-link.active {
    background: rgba(27,46,86,0.06);
    color: var(--brand-blue);
}

.ps-mobile-nav-link:hover,
.ps-mobile-nav-link-child:hover {
    background: rgba(27,46,86,0.06);
    color: var(--brand-blue);
}

.ps-mobile-nav-group {
    border-bottom: 1px solid var(--border);
}

.ps-mobile-nav-submenu {
    background: rgba(27,46,86,0.02);
}

.ps-mobile-nav-link-child {
    display: block;
    padding: 10px 24px 10px 40px;
    color: var(--brand-navy);
    font-size: 13px;
    text-decoration: none;
    border-bottom: 1px solid var(--border);
}

.ps-mobile-nav-actions {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 16px 24px;
}

/* [BUG-PSG-2026-0748] Every control in the drawer's action block now wears the shared
   .btn base (Sign In, List Aircraft, and the three signed-in controls), so the second
   selector — a .btn-ghost-nav standalone half kept from before BUG-PSG-2026-0740 paired
   them all with the base — matched nothing and has been dropped. */
.ps-mobile-nav-actions .btn {
    width: 100%;
    text-align: center;
}

/* Drawer only participates on mobile widths; hidden on desktop to avoid
   any layout shift (transform/visibility already keep it off-screen). */
@media (min-width: 768px) {
    .ps-mobile-nav,
    .ps-mobile-nav-backdrop {
        display: none;
    }
}

/* Nav dropdowns */
.ps-nav-dropdown {
    position: relative;
    display: flex;
    align-items: flex-end;
}

.ps-nav-dropdown > a {
    display: block;
}

.ps-nav-dropdown-menu {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 180px;
    background: #fff;
    border: 1px solid var(--border-muted);
    border-top: none;
    border-radius: 0 0 var(--r-md) var(--r-md);
    box-shadow: 0 4px 12px rgba(0,0,0,0.10);
    z-index: 1001;
    padding: 4px 0;
}

.ps-nav-dropdown-menu a {
    display: block;
    padding: 9px 16px;
    color: var(--brand-navy);
    font-size: 14px;
    font-weight: 400;
    border-bottom: none;
    border-radius: 0;
    white-space: nowrap;
    text-decoration: none;
    transition: background var(--t-fast), color var(--t-fast);
}

.ps-nav-dropdown-menu a:hover {
    background: rgba(27,46,86,0.06);
    color: var(--brand-blue);
    text-decoration: none;
}

.ps-nav-dropdown:hover .ps-nav-dropdown-menu,
.ps-nav-dropdown:focus-within .ps-nav-dropdown-menu {
    display: block;
}

/* Listing count beside a category nav entry — muted so the label stays primary. [BUG-PSG-2026-0599] */
.ps-nav-count {
    color: var(--brand-slate, #6b7280);
    font-weight: 400;
    font-size: 0.85em;
}

/* Signed-in Profile dropdown — click-toggled (InteractiveServer), not hover. [FTR-PSG-2026-0479 item 4] */
.ps-nav-profile { position: relative; display: flex; align-items: center; }

/* [BUG-PSG-2026-0740] .ps-nav-profile-btn's declarations used to live here — display/align/gap/cursor,
   all of which the shared .btn base now supplies since the trigger wears the same class pair as the
   Sign In button it must match — the base plus whichever variant Sign In carries, which since
   BUG-PSG-2026-0748 is the solid blue one. (Not naming that class here: it is declared ~990 lines
   below and a source test finds its rule by plain string search, which prose above would shadow.) What remains of the rule is in § 7, immediately after .btn-ghost-nav,
   because at equal specificity the LATER rule wins and this block is declared ~960 lines before .btn —
   anything about the trigger's shape, border, colour or sizing left here would be silently overridden.
   That is the same cascade contract BUG-PSG-2026-0729 established for .btn-ghost-nav itself. */

/* The default disc is blue-on-white, for a light-backgrounded trigger. Inside the header's own
   trigger the button is now solid blue, so the disc is inverted there instead — see
   `.ps-nav-profile-btn .ps-nav-profile-avatar` in § 7. [BUG-PSG-2026-0748] */
.ps-nav-profile-avatar {
    display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px; border-radius: 50%;
    background: var(--brand-blue); color: #fff;
    font-size: 12px; font-weight: 700; line-height: 1; flex-shrink: 0;
}

.ps-nav-profile-name {
    max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.ps-nav-profile-menu {
    display: none;
    position: absolute;
    top: 100%;
    right: 0;
    min-width: 180px;
    background: #fff;
    border: 1px solid var(--border-muted);
    border-radius: var(--r-md);
    box-shadow: 0 4px 12px rgba(0,0,0,0.10);
    z-index: 1001;
    padding: 4px 0;
    margin-top: 4px;
}

.ps-nav-profile-menu a,
.ps-nav-profile-menu .ps-nav-profile-logout {
    display: block; width: 100%; text-align: left;
    padding: 9px 16px;
    background: none; border: none;
    color: var(--brand-navy);
    font-size: 14px; font-weight: 400;
    white-space: nowrap; text-decoration: none; cursor: pointer;
    transition: background var(--t-fast), color var(--t-fast);
}

.ps-nav-profile-menu a:hover,
.ps-nav-profile-menu .ps-nav-profile-logout:hover {
    background: rgba(27,46,86,0.06);
    color: var(--brand-blue);
    text-decoration: none;
}

.ps-nav-profile.show .ps-nav-profile-menu { display: block; }

@media (max-width: 767.98px) {
    .ps-nav-links { display: none; }
    .ps-nav-hamburger { display: flex; }
    /* Hide the inline toolbar actions (Sign In / List Aircraft) on mobile — they
       crowded the top bar and pushed the hamburger toggle out of reach, hiding the
       nav. Both actions remain available inside the off-canvas drawer.
       [FTR-PSG-2026-0516 item 4 / UAT-28] */
    .ps-nav-actions { display: none; }

    /* [BUG-PSG-2026-0619] Keep the hamburger inside the viewport on phones (320/360/375px).
       The fixed-position .ps-nav clips silently, so the flex-shrink:0 logo + 24px gutter +
       36px logo margin used to push the toggle off-screen. Shrink the gutter, the logo (now
       CSS-driven since the inline 56px was removed from PageHeader) and its spacing so the
       row fits: at 320px the logo is ~36px tall (~198px wide), leaving the 12px gap + ~38px
       hamburger comfortably inside a 288px content box. --nav-height is reduced to 72px in
       tokens.css at this breakpoint to match the shorter bar. */
    .ps-container    { padding-left: 16px; padding-right: 16px; }
    .ps-nav-logo     { margin-right: 12px; padding-top: 12px; padding-bottom: 10px; }
    .ps-nav-logo-img { height: clamp(36px, 11vw, 44px); }
}

/* ============================================================
   LISTINGS KIND-TABS SUB-BAR — [BUG-PSG-2026-0620]
   The kind-tabs (MainLayout.razor) render on every /listings/* route. They previously had
   ZERO CSS and so sat in normal flow at y=0, hidden entirely behind the fixed .ps-nav
   (position:fixed; height:var(--nav-height); z-index:1000). This styles them from the
   canonical tokens and positions the strip as a fixed sub-bar pinned directly below the
   header, so it clears the header at EVERY breakpoint — including BUG-PSG-2026-0619's
   reduced mobile --nav-height (72px). Because the strip is fixed (out of flow), the page
   content below must clear BOTH the header and the strip; the .page-body override at the
   end of this block adds that combined offset on listings routes only. Height is single-
   sourced via --kind-tabs-height so the strip and the content offset can never drift.
   z-index 900 keeps it below the header (1000) and its dropdowns (1001).
   ============================================================ */
.listings-kind-nav {
    position: fixed;
    top: var(--nav-height);
    left: 0;
    right: 0;
    height: var(--kind-tabs-height);
    z-index: 900;
    background: var(--section-white);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--ps-shadow-sm);
}

.listings-kind-nav .ps-container {
    display: flex;
    align-items: stretch;
    height: 100%;
    gap: var(--sp-5);
    /* 3 short tabs fit ≥320px, but never let a future 4th tab wrap and break the fixed
       height — overflow to a horizontal scroll instead. Scrollbar hidden for a clean bar. */
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}

.listings-kind-nav .ps-container::-webkit-scrollbar { display: none; }

.kind-tab {
    display: inline-flex;
    align-items: center;
    height: 100%;
    color: var(--text-secondary);
    font-weight: 600;
    font-size: 0.95rem;
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
    border-bottom: 3px solid transparent;
    transition: color var(--t-fast) ease, border-color var(--t-fast) ease;
}

.kind-tab:hover {
    color: var(--brand-navy);
}

.kind-tab.active {
    color: var(--brand-blue);
    border-bottom-color: var(--brand-blue);
}

.kind-tab:focus-visible {
    outline: 2px solid var(--brand-blue);
    outline-offset: -2px;
    border-radius: var(--r-xs);
}

/* On /listings/* routes the fixed kind-tabs strip sits between the header and the content,
   so the page body must clear header + strip (not just the header). The adjacent-sibling
   selector matches only when the strip is present (MainLayout renders <nav> immediately
   before <main> on listings routes), so non-listings pages keep the plain --nav-height. */
.listings-kind-nav + main .page-body {
    padding-top: calc(var(--nav-height) + var(--kind-tabs-height));
}

/* ============================================================
   FOOTER — prototype-v2 ps-footer
   ============================================================ */

.ps-footer {
    background: var(--ps-footer-bg);
    color: #ffffff;
    padding: 52px 0 0;
    margin-top: 64px;
}

.footer-grid {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr 1fr;
    gap: 40px;
    margin-bottom: 44px;
}

.footer-brand-logo {
    font-size: 18px;
    font-weight: 700;
    color: #fff;
    margin-bottom: 10px;
}

.footer-brand-logo-img {
    height: 72px;
    width: auto;
    display: block;
    margin-bottom: 14px;
}

.footer-brand p {
    font-size: 13px;
    line-height: 1.75;
    margin-bottom: 16px;
    color: rgba(255, 255, 255, 0.8);
}

/* Anchors are styled by the shared .social-chip classes (UAT-21-2 #2). */
.footer-social {
    display: flex;
    gap: 12px;
}

.footer-col h4 {
    /* [RFT-PSG-2026-0523] colour folded from the removed "§ 25" duplicate, which won the cascade. */
    color: rgba(255, 255, 255, 0.85);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-bottom: 14px;
}

.footer-col ul {
    list-style: none;
    padding: 0;
    margin: 0;
}

/* Preserve newlines in free-text footer content (e.g. the Contact Us address block)
   so each line renders on its own row. [FTR-PSG-2026-0516 item 8 / UAT-28] */
.footer-col p {
    white-space: pre-line;
}

.footer-col ul li {
    margin-bottom: 8px;
}

.footer-col ul li a {
    /* [RFT-PSG-2026-0523] colour folded from the removed "§ 25" duplicate, which won the cascade. */
    color: rgba(255, 255, 255, 0.55);
    font-size: 13px;
    transition: color var(--t-fast);
    text-decoration: none;
}

.footer-col ul li a:hover {
    color: var(--accent-sky);
    text-decoration: none;
}

.footer-bottom {
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    padding: 16px 0;
}

.footer-bottom-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 12px;
    /* [RFT-PSG-2026-0523] colour folded from the removed "§ 25" duplicate, which won the cascade. */
    color: rgba(255, 255, 255, 0.35);
    flex-wrap: wrap;
    gap: 8px;
}

.footer-bottom-links {
    display: flex;
    gap: 20px;
}

.footer-bottom-links a {
    /* [RFT-PSG-2026-0523] colour folded from the removed "§ 25" duplicate, which won the cascade. */
    color: rgba(255, 255, 255, 0.35);
    font-size: 12px;
    transition: color var(--t-fast);
    text-decoration: none;
}

.footer-bottom-links a:hover {
    color: rgba(255, 255, 255, 0.6);
    text-decoration: none;
}

/* Responsive footer */
@media (max-width: 1199.98px) {
    .footer-grid { grid-template-columns: 1fr 1fr 1fr; }
    .footer-brand { grid-column: span 3; }
}

@media (max-width: 991.98px) {
    .footer-grid { grid-template-columns: 1fr 1fr; }
    .footer-brand { grid-column: span 2; }
}

@media (max-width: 767.98px) {
    .footer-grid { grid-template-columns: 1fr; }
    .footer-brand { grid-column: span 1; }
    .ps-footer { margin-top: 32px; }
}

/* [RFT-PSG-2026-0523] Duplicate .card base removed here — the single copy lives under
   "§ 9. GENERAL CARDS" (its resting box-shadow was folded in). The partial .listing-card block
   that used to sit here (transition + a hover translateY(-2px) lift + .listing-card-img 3/2) was
   also removed; the hover lift was folded into the authoritative "§ 10" .listing-card:hover and the
   3/2 image ratio already lives in "§ 10". */

/* ============================================================
   BADGES
   ============================================================ */
.badge-featured {
    background-color: var(--brand-blue);
    color: #FFFFFF;
    border-radius: var(--r-xs);
    font-weight: 600;
}

.badge-sold {
    background-color: var(--ps-danger);
    color: #FFFFFF;
    border-radius: 12px;
    font-weight: 600;
}

.badge-condition-excellent {
    background-color: var(--ps-success);
    color: #FFFFFF;
}

.badge-condition-good {
    background-color: var(--ps-info);
    color: #FFFFFF;
}

.badge-condition-fair {
    background-color: var(--ps-warning);
    color: var(--text-on-warning);
}

.badge-condition-poor {
    background-color: var(--ps-danger);
    color: #FFFFFF;
}

/* ============================================================
   FORM CONTROLS
   ============================================================ */
.form-control,
.form-select {
    border-color: var(--ps-border-color);
}

.form-control:focus,
.form-select:focus {
    border-color: var(--ps-primary);
    box-shadow: 0 0 0 0.25rem rgba(27, 46, 86, 0.25);
}

.form-control::placeholder {
    color: var(--ps-text-placeholder);
}

.form-label {
    font-weight: 600;
}

/* ============================================================
   HERO SECTION
   ============================================================ */
.hero-section {
    background-size: cover;
    background-position: center;
}

.hero-section-bg {
    background: linear-gradient(135deg, var(--ps-primary) 0%, var(--ps-primary-hover) 100%);
}

/* ============================================================
   CARD HOVER EFFECT
   ============================================================ */
.hover-lift {
    transition: transform var(--t-fast) ease-in-out, box-shadow var(--t-fast) ease-in-out;
}

.hover-lift:hover {
    transform: translateY(-4px);
    box-shadow: var(--ps-shadow-md);
}

/* ============================================================
   LISTING DETAIL
   ============================================================ */
.listing-detail-price {
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--ps-primary);
    margin-bottom: 1rem;
}

.listing-specs-table table {
    border-collapse: collapse;
    width: 100%;
}

.listing-specs-table table tr:nth-child(even) {
    background-color: var(--ps-bg-light);
}

.listing-specs-table table td,
.listing-specs-table table th {
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--ps-border-color);
}

/* ============================================================
   ARTICLE CONTENT
   ============================================================ */
.article-content h2 {
    margin-top: 2rem;
    margin-bottom: 1rem;
}

.article-content p {
    margin-bottom: 1rem;
    line-height: 1.8;
}

.article-content ul, .article-content ol {
    margin-bottom: 1rem;
    padding-left: 1.5rem;
}

.article-content li {
    margin-bottom: 0.5rem;
}

.article-content h3 {
    margin-top: 1.75rem;
    margin-bottom: 0.75rem;
}

.article-content blockquote {
    border-left: 4px solid var(--brand-navy);
    padding-left: 1rem;
    margin-left: 0;
    color: var(--text-muted);
    font-style: italic;
}

/* ============================================================
   ARTICLE PAGE LAYOUT
   ============================================================ */
.article-layout {
    display: grid;
    grid-template-columns: 1fr 300px;
    gap: 32px;
    align-items: start;
}

@media (max-width: 991.98px) {
    .article-layout {
        grid-template-columns: 1fr;
    }

    .article-sidebar {
        display: none;
    }
}

/* Hero image */
.article-hero {
    margin: 0 0 1.5rem;
}

.article-hero-img {
    width: 100%;
    max-height: 480px;
    object-fit: cover;
    border-radius: 8px;
    display: block;
}

/* Metadata row */
.article-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    color: var(--text-muted);
    margin-bottom: 1.5rem;
    border-bottom: 1px solid var(--ps-border-light);
    padding-bottom: 1rem;
}

.article-meta-author {
    font-weight: 600;
    color: var(--text-primary);
}

.article-meta-sep {
    color: var(--border);
}

.article-meta-share {
    display: flex;
    gap: 6px;
}

/* Tags */
.article-tags-label {
    margin-right: 8px;
    font-size: 14px;
}

/* Author bio avatar */
.article-author-avatar {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--brand-navy);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.4rem;
    font-weight: 700;
    flex-shrink: 0;
}

/* Related articles */
.article-related-title {
    font-size: 1.15rem;
    border-bottom: 2px solid var(--brand-navy);
    padding-bottom: 0.5rem;
}

.article-related-card-img {
    width: 100%;
    height: 140px;
    object-fit: cover;
}

/* Sidebar */
.article-sidebar-widget .card-header {
    background: var(--brand-navy);
    color: #fff;
    border-radius: 0;
}

.article-sidebar-widget .card-header h5 {
    color: #fff;
}

.article-sidebar-news-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.article-sidebar-news-list li {
    padding: 12px 16px;
    border-bottom: 1px solid var(--ps-border-light);
}

.article-sidebar-news-list li:last-child {
    border-bottom: none;
}

.article-sidebar-news-list a {
    font-size: 13px;
    color: var(--text-primary);
    line-height: 1.4;
    text-decoration: none;
}

.article-sidebar-news-list a:hover {
    color: var(--brand-navy);
    text-decoration: underline;
}

/* ============================================================
   FORM VALIDATION
   ============================================================ */
.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--outline-success);
}

.invalid {
    outline: 1px solid var(--outline-error);
}

.validation-message {
    color: var(--outline-error);
    font-size: 0.875rem;
    margin-top: 0.25rem;
}

/* ============================================================
   BLAZOR
   ============================================================ */
.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbmsiPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, var(--error-bg-strong);
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

.blazor-error-boundary::after {
    content: "An error has occurred."
}

/* ============================================================
   FORM STYLES
   ============================================================ */
.darker-border-checkbox.form-check-input {
    border-color: var(--border-neutral);
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* ============================================================
   RESPONSIVE IMAGES
   ============================================================ */
img {
    max-width: 100%;
    height: auto;
}

/* [RFT-PSG-2026-0361] page-body / ps-container / section / section-* were defined
   twice; the duplicate block here was removed. Canonical definitions live under
   "§ 5. LAYOUT" below (they were identical, with a section-white bg fallback). */

/* [RFT-PSG-2026-0523] The first of the two .btn base blocks was removed here; the single
   authoritative button set now lives under "§ 7. BUTTONS" below. The two blocks were identical
   for the btn base and the btn-lg/btn-sm/btn-blue/btn-white/btn-outline variants; the only rule
   unique to this block (the inverse light-on-dark outline) was merged into § 7. */

/* [RFT-PSG-2026-0523] Duplicate .stats-bar/.stat-* base removed here — the single copy lives under
   "§ 14. STATS BAR" (the unique .stats-bar-inner width constraints were folded in there). */

/* ============================================================
   LISTING CARD — featured card + card extras
   [RFT-PSG-2026-0523] The non-featured .listing-card rules that used to live here (base, :hover,
   link, img, badges, body, seller, seller-dot, title, specs, spec-pill, footer-row, price, location,
   cta) were byte-equivalent to the authoritative "§ 10. LISTING CARDS" set below (which wins the
   cascade), so they were removed. Retained here:
     • the featured-card base + body/cta surfaces — the FIRST .listing-card-featured base is what
       FeaturedCardDarken/IceBlue/PublicVisualPolish extract, and #99c5ff must appear on ≥4 surfaces
       INCLUDING this "2nd card block" per IceBlue_AppearsOnAllFeaturedSurfaces, so the featured base
       is deliberately retained here AND in § 10 (a test-sanctioned, documented non-merge);
     • rules unique to this block (.listing-card-id, the .listing-card-featured-large size overrides,
       .seller-dot-dealer/-private, .listing-card-price-por).
   The featured :hover + featured-label were dropped here (identical copies live in § 10, which also
   carries the FTR-0381 !important border and the white separator-line rules).
   ============================================================ */
.listing-card-featured {
    background: var(--brand-pale-blue-bg, #99c5ff); /* Ice blue featured background (FTR-0381; superseded the FTR-0350 Azure) */
    border: 2px solid var(--brand-navy);
}

/* UAT #17 — featured card is a uniform colour, including the body and the
   View Details (CTA) section the button sits on. The button keeps its own colour. FTR-0350. */
.listing-card-featured .listing-card-body,
.listing-card-featured .listing-card-cta {
    background: var(--brand-pale-blue-bg, #99c5ff);
}

/* UAT #18 — listing ID shown on the thumbnail, between the title and the price. */
.listing-card-id {
    font-size: 12px;
    font-weight: 600;
    color: var(--brand-navy);
    opacity: 0.7;
    margin: 2px 0 4px;
    letter-spacing: 0.02em;
}

.listing-card-featured-large .listing-card-img {
    aspect-ratio: 16 / 9;
}

.listing-card-featured-large .listing-card-title {
    font-size: 18px;
    font-weight: 600;
}

.listing-card-featured-large .listing-card-price {
    font-size: 26px;
}

.listing-card-featured-large .listing-card-body {
    padding: 16px 18px 18px;
}

.listing-card-featured-large .listing-card-featured-label {
    font-size: 12px;
    padding: 4px 14px;
}

/* Seller-dot colour variants (declared before the § 10 .seller-dot base, matching prior cascade). */
.seller-dot-dealer   { background: var(--ps-success); }
.seller-dot-private  { background: var(--ps-info); }

/* [RFT-PSG-2026-0523] Duplicate .badge base + .badge-new/reduced/used removed here — the single
   authoritative set lives under "§ 8. BADGES" (which also adds badge-success/info/dealer).
   The .listings-grid base (identical to the "§ 10" copy) with its responsive @media (2-col ≤991,
   1-col ≤575) is retained below as the complete responsive definition; the "§ 10" base copy was
   removed instead. The duplicate .grid-2/3/4 base + responsive @media were removed — the single
   copy lives under "§ 5. LAYOUT" + "§ 27. RESPONSIVE BREAKPOINTS". */
.listings-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
}
@media (max-width: 991.98px) {
    .listings-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 575.98px) {
    .listings-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   DEALER FILTER BAR — prototype-v2 dealers.html FilterBar
   ============================================================ */
.dealer-filter-bar {
    display: flex;
    gap: 12px;
    align-items: center;
    flex-wrap: wrap;
    background: #fff;
    border-bottom: 1px solid var(--border);
    padding: 14px 0;
    margin-bottom: 20px;
}
.dealer-filter-bar .form-input { width: auto; }
.dealer-search-input { max-width: 340px; flex: 1 1 200px; }

/* ============================================================
   DEALER CARDS — prototype-v2 section 19
   ============================================================ */
.dealer-card {
    background: #fff;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    overflow: hidden;
    transition: box-shadow var(--t-fast);
}

.dealer-card:hover { box-shadow: var(--shadow-card-hover); }

.dealer-card-link {
    display: block;
    text-decoration: none;
    color: inherit;
}

.dealer-card-link:hover { text-decoration: none; }

.dealer-card-banner {
    height: 90px;
    overflow: hidden;
    background: var(--brand-navy);
    position: relative;
}

.dealer-card-banner img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0.5;
}

.dealer-card-logo-wrap {
    padding: 0 16px;
    margin-top: -26px;
    position: relative;
    z-index: 1;
}

.dealer-card-logo {
    width: 52px;
    height: 52px;
    background: #fff;
    border-radius: var(--r-md);
    border: 2px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    font-weight: 700;
    color: var(--brand-navy);
    overflow: hidden;
}

/* A dealer that HAS a logo previously rendered the <img> at its natural size inside this
   52px overflow:hidden box — i.e. corner-cropped — while the no-image dealers got a correctly
   centred monogram, making the with-image cards the odd ones out. Letterbox it instead.
   `contain`, never `cover`: a dealer logo must never be cropped.
   [FTR-PSG-2026-0819 / INV-PSG-2026-0812 item 6] */
.dealer-card-logo img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    padding: 4px;
    display: block;
}

.dealer-card-body    { padding: 10px 16px 16px; }
.dealer-card-name    { font-size: 15px; font-weight: 500; color: var(--text-primary); margin-bottom: 4px; }
.dealer-card-location { font-size: 12px; color: var(--text-muted); margin-bottom: 8px; }

.dealer-verified {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    font-weight: 500;
    color: var(--ps-success);
    background: var(--success-light);
    border-radius: var(--r-pill);
    padding: 2px 8px;
    margin-bottom: 8px;
}

.dealer-stats {
    display: flex;
    gap: 16px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--ps-border-light);
}

.dealer-stat       { text-align: center; }
.dealer-stat-val   { font-size: 17px; font-weight: 700; color: var(--brand-navy); }
.dealer-stat-label { font-size: 11px; color: var(--text-muted); }

/* [RFT-PSG-2026-0523] Duplicate .section-header/.section-subtitle removed here (byte-identical to
   the "§ 17. SECTION HEADERS" copy, which is retained). Duplicate .feature-strip/.feature-item/etc.
   removed here — the single copy lives under "§ 15. FEATURE STRIP" + "§ 27" responsive. */

/* ============================================================
   JUST LISTED LAYOUT
   ============================================================ */
.just-listed-layout {
    display: grid;
    grid-template-columns: 1fr var(--sidebar-width);
    gap: 24px;
    align-items: start;
}

.just-listed-main    { min-width: 0; }
.just-listed-sidebar { display: flex; flex-direction: column; gap: 16px; }

@media (max-width: 991.98px) {
    .just-listed-layout { grid-template-columns: 1fr; }
}


/* [RFT-PSG-2026-0523] Duplicate utilities removed here (.w-100 → "§ 26. UTILITIES";
   .text-navy/.text-blue/.text-sm → "§ 4. TYPOGRAPHY", which also adds .text-xs/.text-lg/.text-right). */

/* [RFT-PSG-2026-0523] Duplicate .listings-layout/.filter-sidebar removed here — the single copy
   lives under "§ 12. FORMS" (filter-sidebar there uses the nav-offset sticky top that wins the
   cascade today) + the "≤991" sidebar-hide rule. Duplicate .detail-layout/.detail-sidebar removed
   here — the single copy lives under "§ 20-23. LISTING DETAIL" (detail-sidebar sticky top =
   calc(var(--nav-height) + 16px), which wins today) + "§ 27" responsive. The ≤767 stats-bar
   responsive (.stats-bar-inner flex-wrap + .stat-item min-width) is also a duplicate of "§ 27"
   and was removed. */

/* ============================================================
   PRINT STYLES
   ============================================================ */
@media print {
    .ps-nav, .listings-kind-nav, .ps-footer, .cookie-consent {
        display: none !important;
    }
}

/* ============================================================
   PROTOTYPE-V2 MIGRATION — BUG-PSG-2026-0113
   Sections 4–27: all missing classes ported from prototype-v2/_styles.css
   Organised by section number matching prototype source.
   Bootstrap 5.2 coexistence strategy: prototype cascade after Bootstrap.
   ============================================================ */

/* ------------------------------------------------------------
   § 4. TYPOGRAPHY
   ------------------------------------------------------------ */
.text-navy  { color: var(--brand-navy) !important; }
.text-blue  { color: var(--brand-blue) !important; }
.text-sm    { font-size: 12px; }
.text-xs    { font-size: 11px; }
.text-lg    { font-size: 16px; }
.text-right { text-align: right !important; }

.fw-300 { font-weight: 300; }
.fw-400 { font-weight: 400; }
.fw-500 { font-weight: 500; }
.fw-700 { font-weight: 700; }

/* Price typography */
.price     { font-size: 22px; font-weight: 700; color: var(--text-primary); line-height: 1.1; }
.price-lg  { font-size: 30px; font-weight: 700; color: var(--text-primary); line-height: 1.1; }
.price-sm  { font-size: 17px; font-weight: 700; color: var(--text-primary); }
.price-poa { color: var(--text-muted); font-style: italic; }

/* ------------------------------------------------------------
   § 5. LAYOUT
   ------------------------------------------------------------ */
.ps-container {
    max-width: var(--container-max);
    margin: 0 auto;
    padding: 0 24px;
}

.page-body { padding-top: var(--nav-height); }

.section    { padding: var(--sp-8) 0; }
.section-sm { padding: var(--sp-6) 0; }
.section-lg { padding: var(--sp-10) 0; }

.section-alt   { background: var(--section-grey); }
.section-white { background: var(--section-white, #ffffff); }
.section-navy  { background: var(--brand-navy); color: rgba(255,255,255,0.75); }
.section-navy h1, .section-navy h2 { color: var(--brand-blue); }
.section-navy h3 { color: #fff; }
.section-navy .section-subtitle { color: rgba(255,255,255,0.75); }

/* [FTR-PSG-2026-0627] CTA button group — prototype-v2 sell/CTA band treatment.
   The mockup lays the CTA-band buttons out as a centred flex row with a 14px gap that wraps on
   narrow viewports (index.html "Ready to sell your aircraft?" and advertise.html CTA cards). The
   .cta-buttons class was applied in markup on all five section-navy CTA bands (Index sell-CTA,
   About, Advertise x2, Pricing) but had no rule, so the buttons rendered flush with no gap. This
   supplies the canonical spacing/alignment without per-page inline styles.
   Gap is the mockup's literal 14px (between --sp-3 12px and --sp-4 16px; the scale has no 14px
   step and the scope guard is to match the mockup, not round to the nearest token). */
.cta-buttons { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }

/* [RFT-PSG-2026-0520] Layout-contract regression guard.
   The full-bleed band pattern is <section class="section section-*"><div class="ps-container">.
   .section supplies vertical padding only; ALL horizontal padding comes from .ps-container. If a
   .section band is ever nested INSIDE a .ps-container again (the inverted Advertise-page defect),
   the tint stops at the content column and content loses its 24px side padding. This rule contains
   that failure mode by zeroing the horizontal padding a container would otherwise impose on a band.
   The correct nesting is enforced at build time by LayoutContractVoy0383SourceTests. */
.ps-container > .section,
.ps-container > .section-sm,
.ps-container > .section-lg { padding-left: 0; padding-right: 0; }

/* [RFT-PSG-2026-0520] Become-a-dealer "Why Join" / "Dealer Plans" blocks live inside the page's
   2-column layout (left column beside the sticky application form), so they are content blocks — not
   page-level full-bleed bands. This supplies their vertical rhythm now that the tinted .section band
   classes have been dropped (a column-width tint is the inverted-nesting defect). */
.become-dealer-section { padding: var(--sp-6) 0; }
.become-dealer-section:first-child { padding-top: 0; }

.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }

.flex         { display: flex; }
.flex-center  { display: flex; align-items: center; }
.flex-between { display: flex; align-items: center; justify-content: space-between; }
.flex-col     { display: flex; flex-direction: column; }
.flex-wrap    { flex-wrap: wrap; }
.align-start  { align-items: flex-start; }

.gap-1 { gap: var(--sp-1); }
.gap-2 { gap: var(--sp-2); }
.gap-3 { gap: var(--sp-3); }
.gap-4 { gap: var(--sp-4); }
.gap-5 { gap: var(--sp-5); }

/* ------------------------------------------------------------
   § 6. NAVIGATION — prototype-v2 nav classes (light grey gradient)
   ------------------------------------------------------------ */
/* [RFT-PSG-2026-0523] This section duplicated a SUBSET of the authoritative nav rules under
   "NAVIGATION — prototype-v2 ps-nav" near the top of the file (which additionally defines the
   logo image/text, the off-canvas mobile drawer, nav dropdowns, the signed-in profile menu and
   the ≤767 responsive rules). Values were identical, so the duplicate was removed and the single
   authoritative nav block above is retained. */

/* ------------------------------------------------------------
   § 7. BUTTONS — prototype-v2 variants (Bootstrap .btn base preserved)
   ------------------------------------------------------------ */
/* Override .btn base with prototype inline-flex spec */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    padding: 14px 22px; font-size: 14px; font-weight: 500;
    font-family: var(--ps-font-family, 'Inter', Arial, sans-serif);
    border-radius: var(--r-md); border: 1px solid transparent;
    cursor: pointer; text-decoration: none;
    transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
    white-space: nowrap; line-height: 1; min-height: 44px;
}
/* Override Bootstrap btn-lg/btn-sm with prototype values */
.btn-lg { padding: 14px 28px; font-size: 15px; }
.btn-sm { padding: 6px 14px; font-size: 13px; border-radius: var(--r-xs); }
.btn-xs { padding: 4px 10px; font-size: 12px; border-radius: var(--r-xs); }

/* PS-specific button variants.
   [RFT-PSG-2026-0523] the blue button keeps its two-space opener formatting (selector then two
   spaces before the brace) — pinned by FeaturedCardIceBlueFtr0381CssTests.ViewDetailsButton_BtnBlue_Unchanged.
   The inverse outline variant (formerly the Bootstrap-shaped light outline) was merged in from the
   removed first button block; see .btn-outline-inverse below [BUG-PSG-2026-0547]. */
.btn-blue  { background: var(--brand-blue); color: #fff; border-color: var(--brand-blue); }
.btn-blue:hover { background: var(--brand-blue-dark); border-color: var(--brand-blue-dark); color: #fff; text-decoration: none; }

.btn-white { background: #fff; color: var(--brand-navy); border-color: #fff; }
.btn-white:hover { background: var(--surface-pressed); color: var(--brand-navy); text-decoration: none; }

/* Nav "ghost" variant — a white, blue-outlined secondary action paired with the shared .btn base.
   Relocated here from the nav block by BUG-PSG-2026-0729 so it is declared AFTER that base and its
   border/background survive the cascade.
   [BUG-PSG-2026-0748] It is NO LONGER the public header's Sign In treatment. BUG-PSG-2026-0729 had
   given Sign In the same size and shape as List Aircraft while deliberately keeping this colour,
   on the reading that Sign In was the secondary action; Gavin came back on #306 item 3 — "the Sign
   In button needs to be the same as the List Aircraft button" — and the Head Warden ruled on
   2026-09-10 that the two must match in colour as well. Sign In, the signed-in profile trigger and
   the drawer's signed-in controls all wear .btn-blue now.
   The class is NOT retired and must stay declared: SaveListingDialog's Register button uses it as
   the genuine secondary half of a Log In / Register pair.
   [Sheet #41 item 2 — button consistency, 2026-09-03] border was 1px solid var(--border)
   (#dadce0) — grey. Now brand blue. */
.btn-ghost-nav { background: #fff; color: var(--brand-navy); border: 1px solid var(--brand-blue); }
/* Kept as the `border` SHORTHAND, not just border-color, so the class is self-sufficient: until
   BUG-PSG-2026-0740 the signed-in profile trigger and the mobile drawer's profile/saved/logout controls
   wore .btn-ghost-nav WITHOUT .btn, and border-color alone rendered them borderless (a bare <button>
   falls back to the UA default). Its one remaining call site (SaveListingDialog's Register button)
   pairs it with .btn, but the shorthand stays so a future standalone use cannot regress silently.
   Declared after .btn so it wins there too. */
.btn-ghost-nav:hover {
    color: var(--brand-blue);
    border-color: var(--brand-blue);
    background: #fff;
    text-decoration: none;
}

/* Signed-in profile trigger — the logged-in counterpart of the Sign In button above, swapped in by
   AuthorizeView. [BUG-PSG-2026-0740 / Gavin, #278] It wears whatever class pair Sign In wears —
   .btn .btn-blue since BUG-PSG-2026-0748 — so border, radius, background, colour, font and horizontal
   metrics come from those two rules by construction, which is the whole point of the fix and why this
   rule must NOT restate any of them (NavProfileButtonChromeBug0740SourceTests pins that).
   The ONE thing it does restate is vertical padding. .btn is sized for a text line (font-size 14px,
   line-height 1) with 14px top/bottom padding, reaching its 44px min-height. This button's content is
   the 26px .ps-nav-profile-avatar disc, so .btn's padding would make it 26 + 28 + 2 = 56px — visibly
   taller than the 44px Sign In button it is meant to match. At 8px the box is 26 + 16 + 2 = exactly
   the 44px min-height the base already sets, so the two render at the same height whichever branch
   AuthorizeView picks. Shrinking the avatar instead was rejected: it is a deliberate 26px affordance.
   Declared HERE, after the base, because at equal specificity the later rule wins. */
.ps-nav-profile-btn { padding-top: 8px; padding-bottom: 8px; }

/* [BUG-PSG-2026-0748] The one thing the now solid-blue trigger genuinely needs. § 4 gives
   .ps-nav-profile-avatar a var(--brand-blue) disc with white initials, sized for the white bordered
   box this trigger used to be. On a solid brand-blue button that disc is blue-on-blue: it vanishes
   entirely, leaving a white initial floating in the middle of the button with no affordance around it.
   Inverted here — white disc, navy initial — the disc separates from the button at the same 3.38:1
   white-on-brand-blue the button's own label already relies on (see the § 1 contrast note: that ratio
   is a pre-existing, Head-Warden-pending token decision affecting all 40+ blue buttons, not something
   introduced here), and the initial itself reads at 13.36:1 against the white disc — navy-on-white is
   the same pairing .btn-ghost-nav and .btn-outline already use. Deliberately NOT a blue initial: blue
   and white are 3.38:1 in EITHER direction, so that would have bought nothing over the white-on-blue
   it replaced. All three figures measured in Chromium against the served stylesheet, not calculated
   from the source. The 26px affordance is untouched (NavProfileButtonChromeBug0740SourceTests pins it).
   The profile NAME needs nothing — it inherits the button's own #fff, exactly like List Aircraft's label.
   Written as a descendant selector rather than declarations on .ps-nav-profile-btn itself,
   deliberately: that rule is contractually limited to vertical padding (see above), and this is the
   avatar's chrome, not the button's. Specificity 0-2-0 beats the § 4 base rule at any position. */
.ps-nav-profile-btn .ps-nav-profile-avatar { background: #fff; color: var(--brand-navy); }

.btn-outline { background: transparent; color: var(--brand-navy); border-color: var(--brand-blue); }
/* [Sheet #41 item 2 — button consistency, 2026-09-03] border was var(--brand-navy); now brand blue so every outline button on the site
   carries the same blue outline. Label stays navy (13.36:1) — see the contrast note above. */
.btn-outline:hover { background: var(--brand-navy); color: #fff; text-decoration: none; }

.btn-outline-blue { background: transparent; color: var(--brand-navy); border-color: var(--brand-blue); }
/* [Sheet #41 item 2 — button consistency, 2026-09-03] previously color AND border were brand blue, giving the site two different outline
   treatments (.btn-outline navy x42, .btn-outline-blue x1). Both now read the same: blue
   border, navy label. Kept as a class rather than deleted so existing markup still resolves. */
.btn-outline-blue:hover { background: var(--brand-blue); color: #fff; text-decoration: none; }

/* [BUG-PSG-2026-0547] Inverse (light-on-dark) outline button. Replaces a retired outline variant
   that carried a Bootstrap-shaped name for a bespoke re-skin, which the Head Warden's "retire the
   Bootstrap button family, do not re-skin it" ruling outlaws. Declarations are identical to that
   retired rule so appearance is unchanged; used on dark grounds (cookie banner, .section-navy CTAs). */
.btn-outline-inverse { background: transparent; color: #fff; border-color: rgba(255,255,255,0.6); }
.btn-outline-inverse:hover { background: rgba(255,255,255,0.1); color: #fff; text-decoration: none; }

.btn-ghost { background: transparent; color: var(--brand-navy); border-color: var(--brand-blue); }
/* [Sheet #41 item 2 — button consistency, 2026-09-03] was color:var(--text-secondary) with border-color:var(--border) (#dadce0) — the grey
   outline Gavin asked us to remove. Border is now brand blue; the LABEL stays navy because
   brand blue on white is 3.38:1, below the WCAG AA 4.5:1 text threshold. */
.btn-ghost:hover { background: var(--section-grey); text-decoration: none; }

/* [RFT-PSG-2026-0523] Brand-consistent destructive treatment (custom family, not Bootstrap
   btn-danger). Replaces stock-Bootstrap red for destructive actions; uses --ps-danger so a
   palette change flows through. Public destructive call sites migrate onto these. */
.btn-red { background: var(--ps-danger); color: #fff; border-color: var(--ps-danger); }
.btn-red:hover { background: var(--danger-strong); border-color: var(--danger-strong); color: #fff; text-decoration: none; }
.btn-outline-red { background: transparent; color: var(--ps-danger); border-color: var(--ps-danger); }
.btn-outline-red:hover { background: var(--ps-danger); color: #fff; text-decoration: none; }

.btn-block { display: flex; width: 100%; text-align: center; justify-content: center; }
.btn-icon  { padding: 9px; background: transparent; border: none; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; line-height: 1; }

/* [RFT-PSG-2026-0523] btn-close is Bootstrap's modal/alert dismiss control (retained for
   behaviour). Give it a brand-consistent focus ring so it matches the PlaneSales palette rather
   than Bootstrap's default blue. Public-only (Seller/Admin load neither this sheet nor Bootstrap). */
.btn-close:focus { box-shadow: 0 0 0 0.2rem rgba(45, 147, 209, 0.4); outline: none; }

/* ------------------------------------------------------------
   § 8. BADGES — prototype-v2 variants (Bootstrap .badge base preserved)
   ------------------------------------------------------------ */
/* Extend Bootstrap .badge with prototype display/padding spec */
.badge {
    display: inline-block; padding: 3px 8px;
    font-size: 11px; font-weight: 600; border-radius: var(--r-xs);
    letter-spacing: 0.25px; white-space: nowrap;
}
.badge-new     { background: var(--brand-navy); color: #fff; }
.badge-reduced { background: var(--badge-reduced-bg); color: #fff; }
.badge-used    { background: #fff; color: var(--text-muted); border: 1px solid var(--border); font-weight: 400; }
.badge-success { background: var(--success-light, #e6f4ea); color: var(--ps-success); }
.badge-info    { background: var(--info-light, #e8f0fe); color: var(--ps-info); }
.badge-dealer  { background: var(--info-light); color: var(--link-blue); }

/* ------------------------------------------------------------
   § 9. GENERAL CARDS — override/complete Bootstrap card
   ------------------------------------------------------------ */
.card {
    background: var(--ps-bg-secondary);
    border: 1px solid var(--ps-border-color);
    border-radius: var(--r-md);
    overflow: hidden;
    /* [RFT-PSG-2026-0523] resting box-shadow folded in from the removed first .card block so cards
       keep their subtle shadow at rest (it was leaking through the cascade before de-dup). */
    box-shadow: var(--ps-shadow-card);
    transition: box-shadow var(--t-fast), border-color var(--t-fast);
}
.card:hover    { box-shadow: var(--shadow-card-hover); border-color: var(--ps-divider); }
.card-body     { padding: 20px; }
.card-header   { padding: 15px 20px; border-bottom: 1px solid var(--ps-border-color); background: var(--surface-alt); }
.card-header h3 { font-size: 14px; font-weight: 500; margin: 0; }
.card-footer   { padding: 13px 20px; background: var(--surface-alt); border-top: 1px solid var(--ps-border-light); }

/* ------------------------------------------------------------
   § 10. LISTING CARDS
   ------------------------------------------------------------ */
/* [RFT-PSG-2026-0523] duplicate .listings-grid base removed — the single authoritative
   .listings-grid (with its 2-col ≤991 / 1-col ≤575 responsive @media) lives under
   "LISTINGS GRID" above. */

/* Full prototype listing-card definition (overrides partial existing) */
.listing-card {
    background: var(--ps-bg-secondary);
    border-radius: var(--r-md);
    border: 1px solid var(--ps-border-color);
    overflow: hidden;
    transition: box-shadow var(--t-fast), border-color var(--t-fast);
    position: relative;
}
.listing-card:hover {
    box-shadow: var(--shadow-card-hover);
    border-color: var(--ps-divider);
    /* [RFT-PSG-2026-0523] hover lift folded in from the removed partial .listing-card block so the
       card still nudges up on hover (it was leaking through the cascade before de-dup). */
    transform: translateY(-2px);
}
.listing-card-link { display: block; text-decoration: none; color: inherit; }
.listing-card-link:hover { text-decoration: none; }

/* 3:2 aspect ratio (prototype spec, overrides existing 16/9) */
.listing-card-img {
    aspect-ratio: 3 / 2;
    /* [FTR-PSG-2026-0822] Stop the image box contributing a min-content width wider than its
       column. With a definite height and an aspect-ratio, the box's intrinsic width contribution
       is height x ratio (~594px for the 16/9 featured-large override at app.css:1164), which is
       what floored the .listings-grid track and widened the page. */
    max-width: 100%;
    overflow: hidden; background: var(--section-grey); position: relative;
}
.listing-card-img img {
    width: 100%; height: 100%; object-fit: cover;
    transition: transform var(--t-std) ease;
}
.listing-card:hover .listing-card-img img { transform: scale(1.04); }

/* Card overlays */
.card-badges {
    position: absolute; top: 10px; left: 10px;
    display: flex; gap: 5px; flex-wrap: wrap; z-index: 2;
}
/* Card body */
.listing-card-body { padding: 12px 14px 14px; }

.listing-card-seller {
    font-size: 11px; color: var(--text-muted); font-weight: 400;
    margin-bottom: 3px; display: flex; align-items: center; gap: 4px;
}
.seller-dot {
    width: 5px; height: 5px; background: var(--ps-success); border-radius: 50%;
    display: inline-block;
}
.listing-card-title {
    font-size: 15px; font-weight: 500; color: var(--text-primary);
    line-height: 1.35; margin-bottom: 8px;
}
.listing-card-specs {
    display: flex; flex-wrap: wrap; gap: 10px 14px; margin-bottom: 10px;
}
.spec-pill {
    font-size: 12px; color: var(--text-muted);
    display: flex; align-items: center; gap: 3px; white-space: nowrap;
}
.listing-card-footer-row {
    display: flex; align-items: flex-end; justify-content: space-between;
    margin-top: 8px; padding-top: 10px; border-top: 1px solid var(--ps-border-light);
}
.listing-card-price    { font-size: 20px; font-weight: 700; color: var(--text-primary); line-height: 1; }
/* [RFT-PSG-2026-0523] price-on-request variant moved here from the featured card block so the base
   .listing-card-price rule (with --text-primary) precedes it in source order. */
.listing-card-price-por { font-size: 15px; color: var(--text-muted); font-style: italic; }
.listing-card-location { font-size: 11px; color: var(--text-muted); text-align: right; }
.listing-card-cta {
    padding: 8px 14px; background: var(--surface-subtle); border-top: 1px solid var(--ps-border-light);
    display: flex; gap: 8px;
}

/* Featured card prominence — FTR-PSG-2026-0224; darkened bg FTR-PSG-2026-0310;
   Azure FTR-PSG-2026-0350 (UAT #1/#17); Ice blue #99c5ff FTR-PSG-2026-0381 */
.listing-card-featured {
    background: var(--brand-pale-blue-bg, #99c5ff);
    border: 2px solid var(--brand-navy) !important;
}
.listing-card-featured:hover { border-color: var(--brand-navy) !important; }
.listing-card-featured-label {
    position: absolute; top: 0; left: 0;
    background: var(--brand-navy); color: #FFFFFF;
    font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
    padding: 3px 10px; border-radius: 0 0 6px 0;
    z-index: 3; text-transform: uppercase;
}

/* FTR-0381 — the two thin white separator lines on a featured card must be equal
   length with an equal gap at each end. The footer-row line is inset 14px each side
   by the body padding (.listing-card-body: 12px 14px 14px); the CTA line sits on the
   full-width element edge. Recolour both to white and inset the CTA line by the same
   14px so both lines match length and are symmetrically centred. White on Ice blue.
   The View Details button (.btn-blue) is untouched — only its container box aligns. */
.listing-card-featured .listing-card-footer-row,
.listing-card-featured .listing-card-cta {
    border-top-color: #ffffff;
}
.listing-card-featured .listing-card-cta {
    margin-inline: 14px;
    padding-inline: 0;
}

/* ------------------------------------------------------------
   § 11. DEALER CARDS
   ------------------------------------------------------------ */
/* [RFT-PSG-2026-0523] Duplicate dealer-card set removed here. The single authoritative copy lives
   under "DEALER CARDS — prototype-v2 section 19" above, which is a superset: it additionally
   defines .dealer-card-link/.dealer-card-link:hover and .dealer-verified { margin-bottom: 8px }.
   All values here were equivalent (--border == --ps-border-color, --ps-bg-secondary == #fff), so
   removing this copy preserves the rendered result. */

/* ------------------------------------------------------------
   § 12. FORMS — extra helpers + filter sidebar
   ------------------------------------------------------------ */
.form-group    { margin-bottom: var(--sp-4); }
.form-required { color: var(--ps-danger); margin-left: 2px; }
.form-hint     { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.form-error    { font-size: 12px; color: var(--ps-danger); margin-top: 4px; }

.form-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.form-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }

/* Listings layout: sidebar + main */
.listings-layout {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr;
    gap: 24px; align-items: start;
}

/* [FTR-PSG-2026-0822] A grid/flex item's automatic minimum size floors its track at the item's
   min-content width. `.listing-card-featured-large .listing-card-img`'s 16/9 aspect-ratio
   (app.css:1164) made that floor ~594px, which forced the single 1fr `.listings-grid` track to
   ~598px inside a 430px column at a 390px viewport. The page then measured 623px wide,
   Chrome-mobile widened the Initial Containing Block to match, and the `position: fixed` `.ps-nav`
   (app.css:162) -- sized to the ICB, not the visual viewport -- rendered 623px wide with its
   hamburger toggle 171px past the visible right edge. Same clamp as `.detail-main` (app.css:2473)
   and `.just-listed-main` (app.css:1324). Measured before/after in INV-PSG-2026-0814.
   ListingGrid.razor:26-29 (live on /search) renders the same cards into a Bootstrap `.row`/`.col`
   instead, which `.listings-grid > *` does not reach; measured at 390px, the `max-width: 100%`
   above is sufficient there on its own, so no `.col` clamp is added. */
.listings-results { min-width: 0; }
.listings-grid > * { min-width: 0; }

/* Filter sidebar */
.filter-sidebar {
    background: var(--ps-bg-secondary);
    border: 1px solid var(--ps-border-color);
    border-radius: var(--r-md); overflow: hidden;
    position: sticky; top: calc(var(--nav-height) + 12px);
    max-height: calc(100vh - var(--nav-height) - 24px);
    overflow-y: auto;
}
.filter-sidebar-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 13px 16px; border-bottom: 1px solid var(--ps-border-color);
    background: var(--brand-navy); position: sticky; top: 0; z-index: 1;
}
.filter-sidebar-head h3 { color: #fff; font-size: 13px; font-weight: 500; margin: 0; letter-spacing: 0.2px; }
/* 'Clear All' in the navy filter header. Reuses the site-standard blue button (.btn.btn-blue.btn-sm);
   this rule only trims the .btn base metrics so it fits the compact header. Was a faint white-65% text
   link that was unreadable on the navy strip. Shared header => fixes aircraft AND parts. [BUG-PSG-2026-0512] */
.filter-clear-all { min-height: 0; padding: 6px 14px; font-size: 12px; }

.filter-section { border-bottom: 1px solid var(--ps-border-light); }
.filter-section:last-child { border-bottom: none; }

.filter-sect-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 11px 16px; cursor: pointer;
    font-size: 13px; font-weight: 500; color: var(--text-primary);
    background: transparent; width: 100%; border: none;
    transition: background var(--t-fast); text-align: left; font-family: inherit;
}
.filter-sect-head:hover { background: var(--surface-subtle); }
.filter-chevron { font-size: 11px; color: var(--text-muted); }
.filter-sect-body { padding: 2px 16px 14px; }
.filter-cols-2 { display: grid; grid-template-columns: 1fr 1fr; }

.filter-option { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; cursor: pointer; }
.filter-option input[type=checkbox] { accent-color: var(--brand-blue); width: 15px; height: 15px; flex-shrink: 0; cursor: pointer; }
.filter-option label { font-size: 13px; color: var(--text-secondary); cursor: pointer; flex: 1; line-height: 1.3; }
.filter-opt-count { font-size: 11px; color: var(--text-muted); margin-left: auto; flex-shrink: 0; }

.filter-range-label { font-size: 12px; color: var(--text-muted); margin-bottom: 8px; }
.filter-range-inputs { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: center; padding: 0 16px; }
.filter-range-inputs input { padding: 6px 10px; font-size: 13px; border: 1px solid var(--ps-border-color); border-radius: var(--r-xs); outline: none; width: 100%; font-family: inherit; }
.filter-range-inputs input:focus { border-color: var(--brand-blue); }
.filter-range-sep { display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--text-muted); }

.filter-apply {
    display: flex; flex-direction: column; align-items: center; gap: 8px; margin-top: 12px;
    padding: 12px 16px 16px;
    position: sticky; bottom: 0; background: #fff;
    border-top: 1px solid var(--ps-border-light);
}
.filter-clear-link { font-size: 12px; color: var(--brand-blue); cursor: pointer; text-decoration: underline; background: none; border: none; padding: 0; }
.filter-clear-link:hover { color: var(--brand-blue-dark); }

/* Filter explainer & help icons */
.filter-explainer {
    font-size: 11.5px; color: var(--text-muted); margin: 0;
    padding: 8px 16px; border-bottom: 1px solid var(--ps-border-light);
    line-height: 1.4;
}
.filter-help-icon {
    position: relative; display: inline-flex; align-items: center; justify-content: center;
    width: 16px; height: 16px; color: var(--text-muted); cursor: pointer; flex-shrink: 0;
    border-radius: 50%; outline: none;
}
.filter-help-icon svg { width: 14px; height: 14px; display: block; }
.filter-help-icon:hover, .filter-help-icon:focus { color: var(--brand-blue); }
.filter-tooltip {
    display: none; position: absolute; right: 0; top: calc(100% + 6px);
    background: var(--tooltip-bg); color: #fff; font-size: 11.5px; line-height: 1.4; white-space: normal;
    width: 180px; padding: 6px 9px; border-radius: 5px; z-index: 10; pointer-events: none;
    box-shadow: 0 2px 8px rgba(0,0,0,0.18);
}
.filter-tooltip::before {
    content: ''; position: absolute; right: 4px; bottom: 100%;
    border: 5px solid transparent; border-bottom-color: var(--tooltip-bg);
}
.filter-help-icon:hover .filter-tooltip,
.filter-help-icon:focus .filter-tooltip { display: block; }
.filter-coming-soon {
    font-size: 10px; font-weight: 600; color: var(--text-muted);
    background: var(--page-bg); border: 1px solid var(--ps-border-light);
    border-radius: var(--r-pill); padding: 1px 7px; letter-spacing: 0.02em;
    text-transform: uppercase; flex-shrink: 0;
}

/* Active filter chips */
.filter-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.filter-chip {
    display: inline-flex; align-items: center; gap: 5px;
    background: var(--info-light); color: var(--brand-navy);
    border: 1px solid var(--chip-border); border-radius: var(--r-pill);
    font-size: 12px; font-weight: 500; padding: 4px 10px 4px 12px;
}

/* Kind toggle (All / Aircraft / Parts) [FTR-PSG-2026-0227] */
.filter-kind-toggle {
    display: flex; gap: 0; border: 1px solid var(--ps-border-light); border-radius: 6px; overflow: hidden;
    margin: 8px 16px 0;
}
.filter-kind-btn {
    flex: 1; padding: 6px 0; font-size: 12px; font-weight: 500; color: var(--slate-text);
    background: #fff; border: none; border-right: 1px solid var(--ps-border-light);
    cursor: pointer; transition: background var(--t-fast), color var(--t-fast);
}
.filter-kind-btn:last-child { border-right: none; }
.filter-kind-btn:hover { background: var(--slate-50); }
.filter-kind-btn.active { background: var(--slate-active); color: #fff; }

/* Advanced filters collapsible [FTR-PSG-2026-0227] */
.filter-advanced { border-top: 1px solid var(--ps-border-light); }
.filter-advanced-toggle {
    list-style: none; cursor: pointer; padding: 8px 16px;
    font-size: 12px; font-weight: 600; color: var(--brand-blue);
    user-select: none;
}
.filter-advanced-toggle::-webkit-details-marker { display: none; }
.filter-advanced-toggle::before { content: '▸ '; }
.filter-advanced[open] .filter-advanced-toggle::before { content: '▾ '; }
.filter-advanced-badge {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 16px; height: 16px; padding: 0 4px;
    border-radius: 8px; background: var(--brand-blue); color: #fff;
    font-size: 10px; font-weight: 700; margin-left: 6px; vertical-align: middle;
}

/* Mobile offcanvas sticky footer [FTR-PSG-2026-0227] */
.offcanvas-footer {
    position: sticky; bottom: 0; z-index: 10;
    display: flex; gap: 8px; padding: 12px 16px;
    background: #fff; border-top: 1px solid var(--ps-border-light);
    box-shadow: 0 -2px 8px rgba(0,0,0,0.06);
}

/* Disabled reset button muted appearance */
.btn-outline-secondary:disabled { opacity: 0.45; cursor: not-allowed; }

/* Price preset pills [FTR-PSG-2026-0227] */
.filter-preset-btn {
    display: inline-block; padding: 3px 10px; margin: 2px 3px 2px 0;
    border: 1px solid var(--slate-border); border-radius: 20px;
    background: #fff; font-size: 12px; cursor: pointer;
    color: var(--slate-text-strong); transition: background var(--t-fast), border-color var(--t-fast);
}
.filter-preset-btn:hover { background: var(--slate-50); border-color: var(--slate-border-strong); }
.filter-preset-btn.active { background: var(--slate-active); border-color: var(--slate-active); color: #fff; }

/* Mobile filter trigger bar [FTR-PSG-2026-0227] */
.mobile-filter-bar {
    display: flex; align-items: center; gap: 8px; padding: 8px 0 12px;
}
/* 'Click for Filters' — site-blue, full-width so it is an obvious tap target on mobile
   [FTR-PSG-2026-0515 / UAT-28 #5]. The trailing 'Clear' link sits beside it, so the button
   flex-grows to fill the remaining width rather than spanning the whole row. */
.mobile-filter-toggle {
    flex: 1 1 auto;
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 600;
}
/* Active-filter dot: white so it reads on the blue trigger button. */
.filter-badge { color: #fff; font-size: 10px; margin-left: 3px; }

/* Back-to-previous control at the top of the listings results [FTR-PSG-2026-0515 / UAT-28 #10] */
.results-back-bar { margin-bottom: 10px; }
.results-back-btn { display: inline-flex; align-items: center; gap: 4px; }
.results-back-btn i, .results-back-btn svg { width: 15px; height: 15px; }

/* Hide desktop sidebar and show mobile offcanvas on small screens [FTR-PSG-2026-0227]
   [RFT-PSG-2026-0523] kept at the 991.98 lg boundary (not folded to a bare 991):
   MobileFilterToggleAndBackButtonFtr0515.DesktopSidebar_HiddenOnlyBelowLgBreakpoint pins this exact
   media boundary and the sidebar-hide rule as its first line. Documented one-off exception. */
@media (max-width: 991.98px) {
    .filter-sidebar { display: none; }
    .listings-layout { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------------
   § 12b. HOMEPAGE HERO SLOT [FTR-PSG-2026-0171 / FTR-PSG-2026-0280]
   ------------------------------------------------------------ */
.homepage-hero-slot {
    width: 100%;
    overflow: hidden;
}
.homepage-hero-img {
    display: block;
    width: 100%;
    max-width: 100%;
    height: auto;
    object-fit: cover;
}
/* [RFT-PSG-2026-0523] min-width:880px is a documented one-off KEPT deliberately: 880px is the
   hero creative's native width, and this guard stops the hero image shrinking below it on wide
   viewports. Folding to a standard stop (768/992) changes when the guard engages and risks hero
   overflow/shrink, so it does not fold cleanly — retained per the order's escape clause. */
@media (min-width: 880px) {
    .homepage-hero-img {
        min-width: 880px;
    }
}

/* Multi-hero rotator — FTR-PSG-2026-0280 */
.homepage-hero-slot.hero-rotator {
    position: relative;
}
.hero-rotator-slide {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    opacity: 0;
    transition: opacity 1s ease-in-out;
    pointer-events: none;
}
.hero-rotator-slide--active {
    position: relative; /* keeps slot height from collapsing */
    opacity: 1;
    pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
    .hero-rotator-slide {
        transition: none;
    }
}

/* ------------------------------------------------------------
   § 13. HERO — BILLBOARD AD SLOT
   ------------------------------------------------------------ */
.hero-billboard {
    background: var(--brand-navy);
}
.hero-billboard .ps-container { padding-top: 14px; padding-bottom: 0; }

.ad-unit-billboard-hero {
    position: relative; overflow: hidden;
    border-radius: var(--r-md) var(--r-md) 0 0;
    min-height: 170px;
    background: linear-gradient(135deg, var(--navy-deepest) 0%, var(--brand-navy) 45%, var(--navy-gradient-mid) 100%);
    display: flex; align-items: center; justify-content: space-between;
    padding: 32px 44px;
}
.billboard-label {
    position: absolute; top: 10px; right: 14px;
    font-size: 10px; font-weight: 400; color: rgba(255,255,255,0.45);
    letter-spacing: 0.6px; text-transform: uppercase;
    background: rgba(255,255,255,0.08); border-radius: var(--r-pill);
    padding: 2px 9px;
}
.sponsor-content { position: relative; z-index: 1; }
.sponsor-eyebrow {
    display: inline-block;
    background: var(--brand-blue); color: #fff;
    font-size: 10px; font-weight: 700; letter-spacing: 0.8px; text-transform: uppercase;
    padding: 3px 10px; border-radius: var(--r-xs); margin-bottom: 10px;
}
.sponsor-headline { font-size: 26px; font-weight: 700; color: #fff; line-height: 1.2; margin-bottom: 8px; }
.sponsor-sub      { font-size: 13px; color: rgba(255,255,255,0.7); margin-bottom: 18px; line-height: 1.5; }
.sponsor-cta      { display: inline-flex; gap: 10px; }

.sponsor-visual {
    position: relative; z-index: 1;
    text-align: right;
    display: flex; flex-direction: column; align-items: flex-end; gap: 6px;
}
.sponsor-aircraft       { font-size: 13px; color: rgba(255,255,255,0.5); }
.sponsor-aircraft-name  { font-size: 20px; font-weight: 700; color: rgba(255,255,255,0.85); }
.sponsor-aircraft-price { font-size: 13px; color: rgba(255,255,255,0.55); margin-top: 4px; }

/* Hero search */
.hero-search-wrap { background: var(--brand-navy-dark); padding: 0 0 16px; }
.hero-search-wrap .ps-container { padding-top: 14px; }
.hero-search-context { font-size: 12px; color: rgba(255,255,255,0.55); margin-bottom: 8px; font-weight: 300; }

.hero-search-bar {
    display: flex; align-items: stretch; gap: 0;
    background: #fff; border-radius: var(--r-md); overflow: hidden;
    box-shadow: 0 4px 20px rgba(0,0,0,0.22);
    height: 52px;
}
.hero-search-type {
    padding: 0 12px 0 14px;
    font-size: 14px; font-weight: 500; color: var(--text-primary);
    border: none; border-right: 1px solid var(--ps-border-color);
    /* [BUG-PSG-2026-0823] Was `var(--surface-subtle)` (#f8f9fa) while `.hero-search-input`
       below was `transparent` — the two controls sat side by side in one white bar at two
       different greys. Aligned to transparent so the select inherits the bar's `#fff`, which
       is what the <=767.98px override already renders for BOTH controls. */
    background: transparent; height: 100%; min-width: 145px; cursor: pointer; outline: none;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23616161'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 10px center; padding-right: 28px;
    font-family: inherit;
}
.hero-search-input {
    /* [BUG-PSG-2026-0823] Typography/padding aligned with `.hero-search-type` and
       `.hero-search-btn`, which are both 14px/500. This input was 15px/normal with a 16px
       inset against the select's authored 14px left inset — visible as a text baseline and
       left-edge mismatch, and most obvious at <=767.98px where the controls stack vertically.
       `flex: 1` is deliberately KEPT here: at >=768px the bar is a nowrap row and the input
       must absorb the remaining width. See the <=767.98px block for why it is cancelled there.
       The `::placeholder` rule below keeps its lighter font-weight: 300 by design. */
    flex: 1; padding: 0 14px; font-size: 14px; font-weight: 500;
    border: none; outline: none; color: var(--text-primary); background: transparent;
    font-family: inherit;
}
.hero-search-input::placeholder { color: var(--ps-text-placeholder); font-weight: 300; }
.hero-search-btn {
    background: var(--brand-blue); color: #fff;
    padding: 0 26px; font-size: 14px; font-weight: 500;
    border: none; cursor: pointer; white-space: nowrap; font-family: inherit;
    transition: background var(--t-fast);
}
.hero-search-btn:hover { background: var(--brand-blue-dark); }

/* ------------------------------------------------------------
   § 14. STATS BAR
   ------------------------------------------------------------ */
.stats-bar { background: #fff; border-bottom: 1px solid var(--ps-border-color); }
/* [RFT-PSG-2026-0523] max-width/margin/padding folded in from the removed first .stats-bar block
   so the inner bar stays constrained to the container width (was leaking through the cascade). */
.stats-bar-inner { display: flex; max-width: var(--container-max); margin: 0 auto; padding: 0 24px; }
.stat-item {
    flex: 1; text-align: center; padding: 16px 12px;
    border-right: 1px solid var(--ps-border-color);
}
.stat-item:last-child { border-right: none; }
.stat-value { font-size: 22px; font-weight: 700; color: var(--brand-navy); line-height: 1; }
.stat-label { font-size: 11px; color: var(--text-muted); margin-top: 3px; text-transform: uppercase; letter-spacing: 0.4px; }

/* Results bar (listings page) */
.results-bar {
    display: flex; align-items: center; justify-content: space-between;
    padding: 10px 0; margin-bottom: 14px;
    border-bottom: 1px solid var(--ps-border-color);
}
.results-count { font-size: 14px; color: var(--text-secondary); }
.results-count strong { color: var(--text-primary); font-weight: 500; }
.results-sort  { display: flex; align-items: center; gap: 8px; }
.results-sort label { font-size: 13px; color: var(--text-muted); }
.results-sort select {
    font-size: 13px; border: 1px solid var(--ps-border-color); border-radius: var(--r-xs);
    padding: 5px 28px 5px 10px; color: var(--text-primary); outline: none; cursor: pointer;
    appearance: none;
    background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23616161'/%3E%3C/svg%3E") no-repeat right 8px center;
    font-family: inherit;
}

/* ------------------------------------------------------------
   § 15. FEATURE STRIP
   ------------------------------------------------------------ */
.feature-strip {
    display: grid; grid-template-columns: repeat(4, 1fr);
    background: #fff; border-top: 1px solid var(--ps-border-color); border-bottom: 1px solid var(--ps-border-color);
}
.feature-item {
    padding: 20px 22px; text-align: center;
    border-right: 1px solid var(--ps-border-color);
}
.feature-item:last-child { border-right: none; }
.feature-icon  { font-size: 26px; margin-bottom: 6px; }
.feature-title { font-size: 13px; font-weight: 500; color: var(--text-primary); margin-bottom: 3px; }
.feature-desc  { font-size: 12px; color: var(--text-muted); line-height: 1.4; }

/* ------------------------------------------------------------
   § 16. AD UNITS
   ------------------------------------------------------------ */
.ad-unit {
    border-radius: var(--r-md);
    position: relative;
    /* FTR-PSG-2026-0521 — one sizing contract for every slot: a uniform 12px inset on
       all four sides so the box hugs its creative with an even frame. The grey
       placeholder frame (--ad-bg / --ad-border) and overflow:hidden were dropped —
       since FTR-0384 the component renders nothing for an empty slot, so that frame
       only ever wrapped a LIVE creative, and overflow:hidden paired with a fixed slot
       height cropped any creative whose real aspect ratio differed from nominal. Slots
       are now sized by max-width + aspect-ratio (see the per-slot rules below), never a
       fixed height, so the box can never crop the creative. */
    padding: var(--sp-3);
    display: flex; align-items: center; justify-content: center;
    flex-direction: column;
}
/* [RFT-PSG-2026-0626] Removed dead placeholder-state rules .ad-unit-label / .ad-unit-content /
   .ad-unit-placeholder / .ad-unit-dims — these styled the "Advertisement / <dims>" placeholder
   card that FTR-PSG-2026-0384 deleted from AdUnit.razor (an empty slot now renders NOTHING). No
   markup, razor or JS emits these classes; proven unused before removal (not referenced by any
   test either). */

/* Ad slot sizes — FTR-PSG-2026-0521: the nominal size is expressed as a max-width (never a
   fixed height); the box is centred with margin:0 auto and hugs its creative with the uniform
   .ad-unit inset. Fixed heights are replaced by aspect-ratio derived from the nominal size so
   overflow can never crop an off-nominal creative.
   RFT-PSG-2026-0624 (RECORDED HEAD WARDEN RULING 2026-08-06, superseding the FTR-0439/RFT-0559
   "constrain the box, do not stretch the creative" contract of 2026-07-26/2026-08-03): the DISPLAY
   slot now STRETCHES to fill the content column while the UPLOAD/rate-card spec stays 880×110
   (what advertisers are told to supply — unchanged). The max-width:880px cap is removed so the box
   spans the full content column (~1232px inside the .ad-unit 12px inset at desktop); the box keeps
   aspect-ratio 880/110 (≈1232×154) so its reserved space stays proportional and the canonical
   880×110 creative scales up aspect-preserved. The leaderboard creative is added to the
   width:100%/height:auto stretch group below, so it fills the column (aspect preserved). NOTE: a
   legacy 730×90 asset now stretches too and will distort — such creatives need re-supply at 880×110
   (admin follow-up; no CSS letterboxing is provided under the new ruling). */
/* [Sheet #41 item 3 — HEAD WARDEN RULING 2026-09-03, SUPERSEDING RFT-PSG-2026-0624]
   The leaderboard is capped at its ACTUAL size again. RFT-0624 (ruling of 2026-08-06) removed the
   880px cap so the DISPLAY slot stretched to fill the content column (~1232px) while the upload
   spec stayed 880x110; Gavin reported the result as "considerably bigger than 880 x 110" and the
   ruling is now reversed: where a leaderboard would be made 100% of its section and wider than
   880px, it renders at actual size instead.
   max-width:880px (not a fixed width) keeps it shrinking with the viewport, and matches what
   .ad-secondary-banner and .ad-top-feature already do — the leaderboard was the odd one out. */
.ad-leaderboard    { width: 100%; max-width: 880px; margin: 0 auto; aspect-ratio: 880 / 110; }
/* [RFT-PSG-2026-0626] Removed dead .ad-leaderboard-lg and .ad-mrec. AdUnit.razor's AdSizeClass
   only ever emits `ad-leaderboard` (Leaderboard) and `ad-mrec-full` (Mrec), never these two
   variants; proven unused across markup/razor/JS before removal. NOTE: .ad-leaderboard-lg had been
   an identical duplicate of .ad-leaderboard (RFT-PSG-2026-0624 made them equal) so nothing renders
   differently. .ad-mrec-full is kept (live). */
.ad-mrec-full      { max-width: 250px; margin: 0 auto; aspect-ratio: 1 / 1; }

/* Banner creative image — responsive within its slot (never crushed to a fixed height) */
.ad-unit-creative { display: block; max-width: 100%; height: auto; }
/* Full-width banners (secondary / billboard / top feature) fill the section width and
   scale height by the creative's aspect ratio; they shrink with the viewport.
   The leaderboard stays in this group, but its BOX is now capped at 880px (see above, Head Warden
   ruling 2026-09-03 superseding RFT-PSG-2026-0624), so width:100% here fills up to 880px — i.e. the
   creative's actual size — and still shrinks aspect-preserved on narrow viewports. */
.ad-leaderboard .ad-unit-creative,
.ad-secondary-banner .ad-unit-creative,
.ad-top-feature .ad-unit-creative,
.ad-unit-billboard-hero .ad-unit-creative { width: 100%; height: auto; }

/* Secondary homepage banner — 880×110 (placement: home-secondary-ad-880x110).
   FTR-PSG-2026-0521: fixed height:110px replaced by aspect-ratio 880/110 (the former
   mobile-only fallback, now promoted to the base rule) so no creative is cropped. */
.ad-secondary-banner {
    width: 100%; max-width: 880px; margin: 0 auto; aspect-ratio: 880 / 110;
}

/* Search-results ad suite — FTR-PSG-2026-0439 */
/* Top Feature 880×330 — top of search-results pages */
.ad-top-feature { width: 100%; max-width: 880px; margin: 0 auto; }
/* Tower skyscrapers 400×800 (left tower in filter sidebar, right tower on detail pages);
   creative scales down by aspect ratio inside narrower sidebars via .ad-unit-creative */
.ad-tower { width: 100%; max-width: 400px; margin: 0 auto; }
/* Breathing room for ads inside the filter sidebar panel */
.sidebar-ad { margin: 12px; width: auto; }
/* In-results Horizontal ad spans the full listings grid row (inert in rows view) */
.listings-grid .listings-grid-ad,
.listings-rows .listings-grid-ad { grid-column: 1 / -1; }
/* Listing-detail bottom Horizontal banner (880x110) — reuses the .ad-secondary-banner
   sizing (max-width 880px, mobile aspect-ratio fallback), centred in the detail main
   column with breathing room above. [FTR-PSG-2026-0499] */
.listing-detail-ad { margin-top: 20px; }
/* Listing-detail SIDEBAR ad units (Right Tower + MREC). On desktop they sit in the sticky
   right rail; on mobile the sidebar stacks into the main column and these would render
   mid-listing, breaking the reading flow — so they are hidden ≤991px (see the responsive
   breakpoint below). Rendering-only change: the slots stay active and serve on desktop.
   [BUG-PSG-2026-0517 / UAT-28 #7] */
.hero-secondary-band {
    background: var(--brand-navy);
    padding: 12px 0 16px;
}
.hero-secondary-band .ps-container {
    display: flex; justify-content: center;
}

/* [RFT-PSG-2026-0626] Removed the dead "Native in-feed ad" block — the native-ad-card container
   and its children native-ad-tag / native-ad-img / native-ad-body (h5, p). The native slot is
   rendered by AdUnit.razor, whose AdSizeClass emits `ad-unit-native` for AdTypes.Native; NOTHING
   in markup, razor or JS ever emits any native-ad-* class (proven by grep before removal). The
   order-enumerated selector was the card container; its child rules are its now-orphaned
   descendants and are removed with it so no dead ad CSS is left behind.
   (Selector names are written WITHOUT a leading dot on purpose: the removed rules are pinned by
   source-tests asserting the dotted class strings — those pins are deliberately obsoleted here and
   flipped by TST, so this comment must not accidentally satisfy them.) */

/* ------------------------------------------------------------
   § 17. SECTION HEADERS
   ------------------------------------------------------------ */
.section-header { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 20px; flex-wrap: wrap; gap: 8px; }
.section-header h2 { margin-bottom: 0; }
.section-header a  { font-size: 13px; font-weight: 500; white-space: nowrap; }
.section-subtitle  { font-size: 14px; color: var(--text-muted); margin-top: -8px; margin-bottom: 20px; }

/* ------------------------------------------------------------
   § 18. BREADCRUMBS
   ------------------------------------------------------------ */
.breadcrumb { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); padding: 12px 0; flex-wrap: wrap; list-style: none; margin-bottom: 0; }
.breadcrumb a { color: var(--text-muted); transition: color var(--t-fast); }
.breadcrumb a:hover { color: var(--brand-blue); text-decoration: none; }
.breadcrumb-sep     { color: var(--ps-divider); }
.breadcrumb-current { color: var(--text-secondary); }

/* NavPageHeader component — dark navy breadcrumb strip */
.page-header-title    { font-size: 22px; font-weight: 700; margin: 0; color: var(--brand-blue); }
.page-header-subtitle { font-size: 13px; margin: 4px 0 0; color: rgba(255,255,255,0.75); }
.breadcrumb-nav { display: flex; align-items: center; gap: 6px; font-size: 12px; flex-wrap: wrap; margin-bottom: 8px; }
.breadcrumb-nav .breadcrumb-link  { color: var(--ps-footer-link); text-decoration: none; transition: color var(--t-fast); }
.breadcrumb-nav .breadcrumb-link:hover { color: #fff; text-decoration: none; }
.breadcrumb-nav .breadcrumb-sep   { color: rgba(255,255,255,0.35); }
.breadcrumb-nav .breadcrumb-current { color: var(--ps-footer-link); }

.divider { border: none; border-top: 1px solid var(--ps-border-color); margin: 20px 0; }

/* ------------------------------------------------------------
   § 19. TRUST BADGES + ENQUIRY CARD
   ------------------------------------------------------------ */
.trust-row  { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; padding: 16px 0; border-top: 1px solid var(--ps-border-light); }
.trust-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }
.trust-item span { font-size: 16px; }

/* [FTR-PSG-2026-0801] Enquiry honeypot. Hides the decoy field on BOTH public enquiry forms - the shared
   ListingEnquiryForm (aircraft/part/property/dealer pages) and the separate Contact Us form.
   Deliberately an EXTERNAL class with a neutral name: an inline style="display:none" on the input, or a
   class called .honeypot / .hp / .leave-blank, is exactly what a scraper pattern-matches on to skip the
   trap. Rotate the rendered field NAME via EnquiryModeration:Honeypot:FieldName; this rule does not name
   the field, so it never needs to change with it.
   Belt and braces on purpose - !important and the off-screen/zero-size properties together mean a page
   stylesheet that resets display cannot accidentally expose the field to a real user, and the markup also
   carries aria-hidden + tabindex="-1" + autocomplete="off" so assistive tech and autofill stay away. */
.form-field-alt {
    position: absolute !important;
    left: -9999px !important;
    top: auto;
    width: 1px !important;
    height: 1px !important;
    overflow: hidden !important;
    opacity: 0 !important;
    pointer-events: none !important;
}

/* [FTR-PSG-2026-0802] Spacing for the Cloudflare Turnstile widget on the public enquiry forms.
   Layout ONLY - deliberately nothing that could clip, scale or hide the widget. Cloudflare renders an
   iframe of its own fixed size inside this wrapper, and a challenge the buyer cannot see or click is a
   form they cannot submit. The wrapper collapses to nothing when Turnstile is off, since TurnstileWidget
   then renders no markup at all. */
.turnstile-field {
    margin: 0 0 1rem;
}

.enquiry-card { background: var(--ps-bg-secondary); border: 1px solid var(--ps-border-color); border-radius: var(--r-md); overflow: hidden; }
/* [RFT-PSG-2026-0523] merged the two .enquiry-card-head declarations into one authoritative rule.
   The later "§ ENQUIRY FORM" override (flex-direction:column; align-items:flex-start; gap:4px) won
   the cascade, so those values are folded in here (align-items center→flex-start, gap 10px→4px). */
.enquiry-card-head {
    background: var(--brand-navy); padding: 16px 20px;
    display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
}
.enquiry-card-head h3 { color: #fff; font-size: 15px; font-weight: 500; margin: 0; }
.enquiry-card-body    { padding: 20px; }

/* ------------------------------------------------------------
   § 20–23. LISTING DETAIL
   ------------------------------------------------------------ */
.listing-gallery {
    display: block; margin-bottom: 24px;
}
.gallery-main {
    aspect-ratio: 3/2; overflow: hidden;
    border-radius: var(--r-md); background: var(--section-grey);
}
.gallery-main img  { width: 100%; height: 100%; object-fit: cover; }
.gallery-thumbs {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 8px; margin-top: 8px;
    max-height: 158px; /* 2 rows × 70px + 1 gap × 8px + 10px breathing room */
    overflow-y: auto;
}
/* [RFT-PSG-2026-0523] Single authoritative .gallery-thumb definition (the second app.css block
   under "LISTING GALLERY — ARROW BUTTONS" was merged in here: padding:0 + the border reset).
   HEAD WARDEN RULING: object-fit: contain so aircraft photography is never wingtip-cropped in the
   thumbnail strip. The box keeps a neutral section-grey fill so the contain letterbox reads as
   intentional (consistent with .gallery-main). The competing app.css cover/reset blocks and the
   planesales.css 150×100 definition no longer disagree on the public detail page. */
.gallery-thumb {
    height: 70px; min-width: 0; overflow: hidden; border-radius: var(--r-sm);
    cursor: pointer; background: var(--section-grey); padding: 0;
    border: 2px solid transparent; transition: border-color var(--t-fast);
}
.gallery-thumb:hover { border-color: var(--brand-blue); }
.gallery-thumb img   { width: 100%; height: 100%; object-fit: contain; }
.gallery-more {
    height: 70px; background: var(--brand-navy);
    border-radius: var(--r-sm); display: flex;
    align-items: center; justify-content: center;
    color: #fff; font-size: 13px; font-weight: 500; cursor: pointer;
}

.detail-layout  { display: grid; grid-template-columns: 1fr 310px; gap: 28px; align-items: start; }
.detail-sidebar { position: sticky; top: calc(var(--nav-height) + 16px); }

.detail-card { background: var(--ps-bg-secondary); border: 1px solid var(--ps-border-color); border-radius: var(--r-md); overflow: hidden; margin-bottom: 16px; }
.detail-card-header { padding: 14px 18px; border-bottom: 1px solid var(--ps-border-color); background: var(--surface-alt); }
.detail-card-header h3 { font-size: 14px; font-weight: 500; margin: 0; color: var(--text-primary); }
/* FTR-PSG-2026-0469: highlights card header hosts the save heart, right-aligned against the title. */
.detail-card-header-actions { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.detail-card-body   { padding: 18px; }

/* Audience cards — /content/advertise */
.audience-card { padding: 24px; text-align: center; }
.audience-icon { margin-bottom: 12px; color: var(--brand-blue); }
.audience-icon i { width: 32px; height: 32px; }
.audience-stat { font-size: 22px; font-weight: 700; color: var(--brand-navy); margin-bottom: 6px; }
.audience-label { font-size: 13px; font-weight: 600; color: var(--text-primary); margin-bottom: 4px; }
.audience-desc { font-size: 13px; color: var(--text-muted); }

/* Spec table */
.spec-table { width: 100%; border-collapse: collapse; }
.spec-table tr { border-bottom: 1px solid var(--ps-border-light); }
.spec-table tr:last-child { border-bottom: none; }
.spec-table td { padding: 9px 0; font-size: 13px; vertical-align: top; }
.spec-table td:first-child { color: var(--text-muted); font-weight: 400; width: 48%; padding-right: 12px; }
.spec-table td:last-child  { color: var(--text-primary); font-weight: 500; }

/* ------------------------------------------------------------
   § 24. PAGINATION
   ------------------------------------------------------------ */
/* [FTR-PSG-2026-0822] `<div class="pagination mt-4">` (ListingsBrowser.razor:575,
   Dealers/Index.razor:149) wraps Pagination.razor, which emits TWO children -- ul.pagination
   and a sibling div.text-muted.small.mt-2 (Pagination.razor:68). Without flex-wrap both were
   forced into one nowrap centred row, which is the residual ~20px overflow on /dealers. */
.pagination { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4px; padding: 28px 0; list-style: none; margin-bottom: 0; max-width: 100%; }
.pg-btn {
    display: flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; border-radius: var(--r-xs);
    font-size: 14px; font-weight: 400; cursor: pointer;
    transition: all var(--t-fast); border: 1px solid transparent;
    color: var(--text-secondary); background: transparent;
    text-decoration: none;
}
.pg-btn:hover    { background: var(--section-grey); border-color: var(--ps-border-color); text-decoration: none; color: var(--text-primary); }
.pg-btn.active   { background: var(--brand-navy); color: #fff; border-color: var(--brand-navy); }
.pg-btn.disabled { opacity: 0.35; cursor: default; pointer-events: none; }
.pg-dots { color: var(--text-muted); width: 28px; text-align: center; font-size: 14px; }

/* ------------------------------------------------------------
   § 25. FOOTER — prototype-v2 footer layout classes
   ------------------------------------------------------------ */
/* [RFT-PSG-2026-0523] This duplicate footer-layout set was removed. The single authoritative footer
   lives under "FOOTER — prototype-v2 ps-footer" near the top of the file, which is a superset
   (it also defines .ps-footer, .footer-brand-logo-img, .footer-col ul, .footer-col p white-space,
   and the responsive @media incl. .ps-footer margin-top at ≤767). The colours this block set —
   which won the cascade before de-dup (.footer-col h4 .85, .footer-col ul li a .55, .footer-bottom-inner
   .35, .footer-bottom-links a .35) — were folded into that authoritative block, preserving the
   rendered result. */

/* ------------------------------------------------------------
   § 26. UTILITIES
   ------------------------------------------------------------ */
.mb-0 { margin-bottom: 0 !important; }
.mb-1 { margin-bottom: var(--sp-1) !important; }
.mb-2 { margin-bottom: var(--sp-2) !important; }
.mb-3 { margin-bottom: var(--sp-3) !important; }
.mb-4 { margin-bottom: var(--sp-4) !important; }
.mb-5 { margin-bottom: var(--sp-5) !important; }
.mb-6 { margin-bottom: var(--sp-6) !important; }
.mt-0 { margin-top: 0 !important; }
.mt-2 { margin-top: var(--sp-2) !important; }
.mt-3 { margin-top: var(--sp-3) !important; }
.mt-4 { margin-top: var(--sp-4) !important; }
.mt-5 { margin-top: var(--sp-5) !important; }
.mt-6 { margin-top: var(--sp-6) !important; }
.p-3  { padding: var(--sp-3); }
.p-4  { padding: var(--sp-4); }
.p-5  { padding: var(--sp-5); }
.text-center { text-align: center !important; }
.d-none      { display: none; }
.d-block     { display: block; }
.d-flex      { display: flex; }
.w-100       { width: 100%; }
.rounded     { border-radius: var(--r-md); }

/* ------------------------------------------------------------
   § 27. RESPONSIVE BREAKPOINTS
   ------------------------------------------------------------ */
/* [RFT-PSG-2026-0523] The footer-grid/footer-brand responsive rules that used to live in this
   section (a 1199 block here plus lines in the 991 and 767 blocks below) duplicated the footer's
   own responsive @media under "Responsive footer" near the top of the file (which additionally
   sets .ps-footer margin-top at ≤767). They were removed; the top footer @media is authoritative. */

@media (max-width: 991.98px) {
    .listings-layout  { grid-template-columns: 1fr; }
    .filter-sidebar   { position: static; max-height: none; }
    .detail-layout    { grid-template-columns: 1fr; }
    /* Sidebar stacks into the flow here — hide its ad units so no ad renders mid-listing
       on mobile; the bottom 880x110 horizontal banner stays. [BUG-PSG-2026-0517] */
    .detail-sidebar-ad { display: none; }
    .gallery-thumbs { grid-template-columns: repeat(3, 1fr); max-height: 134px; /* 2 rows × 58px + 8px gap + 10px */ }
    .gallery-thumb, .gallery-more { height: 58px; }
    .grid-3           { grid-template-columns: repeat(2, 1fr); }
    .grid-4           { grid-template-columns: repeat(2, 1fr); }
    .feature-strip    { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 767.98px) {
    /* [RFT-PSG-2026-0621 M4.3] The `.ps-nav-links { display:none } / .ps-nav-hamburger
       { display:flex }` pair that used to sit here was an exact duplicate of the authoritative
       mobile-nav block above (the BUG-PSG-2026-0619 ≤767.98px block). Removed — the single copy
       there governs the hamburger swap; this block keeps only the hero-search/homepage rules. */
    .hero-search-bar  {
        flex-direction: column; border-radius: 0; height: auto;
        background: transparent; box-shadow: none; gap: 8px; overflow: visible;
    }
    /* [BUG-PSG-2026-0823] `background-color`, NOT the `background` shorthand: the shorthand
       resets `background-image` to none, which wiped the custom chevron the base rule paints
       (app.css §13) while `appearance: none` — not reset here — kept the native arrow hidden.
       The select therefore had NO dropdown affordance at all below 768px. */
    .hero-search-type  { border-radius: var(--r-md) !important; height: 46px; background-color: #fff; border: 1px solid rgba(255,255,255,0.3); border-right: 1px solid rgba(255,255,255,0.3); width: 100%; }
    /* [BUG-PSG-2026-0823] PRIMARY FIX. `.hero-search-bar` above turns this into a COLUMN flex
       container, so height becomes the main axis. The base `flex: 1` computes to
       `flex-basis: 0%`, and a non-`auto` flex-basis REPLACES `height` when resolving main
       size — so the `height: 46px` on this very line was silently discarded. The bar is
       `height: auto`, so flex-grow had no free space to reclaim and the input collapsed to its
       content minimum: INV-PSG-2026-0814 measured 21px, beside a 46px select and a 46px button
       (which keep `flex-basis: auto` and so honour their height normally).
       `flex: none` (= 0 0 auto) restores `flex-basis: auto`, which lets `height: 46px` apply. */
    .hero-search-input { border-radius: var(--r-md) !important; flex: none; height: 46px; background-color: #fff; border: 1px solid rgba(255,255,255,0.3); }
    .hero-search-btn   { border-radius: var(--r-md) !important; height: 46px; width: 100%; }
    .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
    .feature-strip     { grid-template-columns: 1fr 1fr; }
    .stats-bar-inner   { flex-wrap: wrap; }
    .stat-item         { min-width: 50%; }
    /* [RFT-PSG-2026-0523] footer-grid/footer-brand removed (dup of the top footer @media);
       the redundant .gallery-thumbs repeat(3)/134px here (already applied by the ≤991 rule) removed. */
    /* FTR-PSG-2026-0521 — the base .ad-secondary-banner rule now carries aspect-ratio 880/110
       (no fixed height at any viewport), so this override is redundant at mobile; it is kept
       verbatim because BannerPlacementFTR0499SourceTests pins the shared listing-detail mobile
       fallback string. The former .ad-leaderboard { height:auto } override was dropped — the
       base leaderboard rule no longer sets a height, so it was a no-op. */
    .ad-secondary-banner { height: auto; aspect-ratio: 880 / 110; }
    .sponsor-visual    { display: none; }
    .form-row-2, .form-row-3 { grid-template-columns: 1fr; }
    .ad-unit-billboard-hero  { padding: 24px 20px; }
    .sponsor-headline  { font-size: 20px; }
}

/* ============================================================
   § LISTING DETAIL — TITLE BAR
   ============================================================ */
.detail-title-bar {
    display: flex; align-items: flex-start; justify-content: space-between;
    flex-wrap: wrap; gap: 12px; margin-bottom: 20px;
}
.detail-title-left { flex: 1; min-width: 0; }
.detail-title-right { text-align: right; flex-shrink: 0; }
.detail-title { font-size: 26px; font-weight: 700; color: var(--text-primary); margin: 6px 0 0; line-height: 1.2; }
.detail-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; margin-top: 10px; }
.detail-main { min-width: 0; }

@media (max-width: 767.98px) {
    .detail-title-bar { flex-direction: column; }
    .detail-title-right { text-align: left; }
    .detail-actions { justify-content: flex-start; }
}

/* ============================================================
   § DEALER DETAIL — BANNER
   ============================================================ */
/* Dealer profile banner on /dealers/{id}. When a banner image is set,
   GetBannerStyle injects an inline `background-image: url(...)` that overrides
   the gradient below — so the gradient serves as the default placeholder.
   The stored image is exactly 900x300 (ImageService cover-crop), so the box
   keeps the same 3:1 ratio and never exceeds the native 900px width —
   otherwise `cover` upscales and crops the image (UAT-21 #3 / FTR-0435). */
.dealer-detail-banner {
    width: min(100%, 900px);
    aspect-ratio: 3 / 1;
    margin-inline: auto;
    border-radius: 8px;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    background-color: var(--brand-navy);
    background-image: linear-gradient(135deg, var(--brand-navy), var(--brand-navy-medium));
}

/* Dealer directory list-row thumbnail when a banner (ImageBackground) is the image.
   The stored banner is 3:1 / 900×300; render it as a compact fixed-width thumbnail,
   cover-cropped so it never distorts in the row's logo slot. [FTR-PSG-2026-0476] */
.dealer-list-banner {
    width: 120px;
    aspect-ratio: 3 / 1;
    object-fit: cover;
    border-radius: 6px;
    display: block;
}

/* ============================================================
   § DEALER DIRECTORY LIST ROWS
   ============================================================ */
/* Every dealer past the first four on /dealers renders through this markup
   (Dealers/Index.razor:100-145). Until FTR-PSG-2026-0819 NONE of these classes had a rule
   anywhere in the solution — only .dealer-list-banner above — so the rows had no flex layout,
   no fixed logo column and no common height: a banner dealer got a 120x40 thumbnail, a
   logo-only dealer got an UNCONSTRAINED natural-size image, and an image-less dealer (155 of
   163 of them) got a bare text node. The fixed `min-height` on the row plus the fixed-size
   logo column is what makes all three image branches land identically.
   [FTR-PSG-2026-0819 / INV-PSG-2026-0812 item 6] */
.dealer-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.dealer-list-row {
    display: flex;
    align-items: center;
    gap: 16px;
    min-height: 88px;
    padding: 12px 16px;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    transition: box-shadow var(--t-fast);
}

.dealer-list-row:hover { box-shadow: var(--shadow-card-hover); }

/* The fixed-width image column. 120px matches .dealer-list-banner's own width, so the
   existing banner branch drops in unchanged and centres itself vertically. */
.dealer-list-logo {
    flex: 0 0 120px;
    width: 120px;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

/* The logo branch (Index.razor:113) carries no class of its own. Scoped with
   :not(.dealer-list-banner) deliberately: this selector is (0,1,1) and sits AFTER the
   banner's (0,1,0) rule, so without the :not() it would override the banner's
   `object-fit: cover` — banners SHOULD crop, logos must not. */
.dealer-list-logo img:not(.dealer-list-banner) {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    display: block;
}

/* Monogram fallback — the branch the overwhelming majority of dealers take. Mirrors
   .dealer-card-logo's treatment at a smaller size so a row with no image is the same
   height as one with. */
.dealer-logo-initials-sm {
    width: 48px;
    height: 48px;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #fff;
    border: 2px solid var(--border);
    border-radius: var(--r-md);
    font-size: 17px;
    font-weight: 700;
    color: var(--brand-navy);
}

/* min-width: 0 is load-bearing — without it a long company name blows the flex row out
   instead of wrapping inside its own column. */
.dealer-list-info {
    flex: 1 1 auto;
    min-width: 0;
}

.dealer-list-name {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 15px;
    font-weight: 600;
}

.dealer-list-name a {
    color: var(--text-primary);
    text-decoration: none;
}

.dealer-list-name a:hover { color: var(--link-blue); }

/* .dealer-verified carries margin-bottom: 8px for the card layout; neutralise it here so the
   pill sits on the name's baseline instead of dragging the row. */
.dealer-list-name .dealer-verified { margin-bottom: 0; }

.dealer-list-location {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-top: 4px;
    font-size: 12px;
    color: var(--text-muted);
}

.dealer-list-location svg {
    width: 14px;
    height: 14px;
}

/* min-width keeps the stats column aligned down the whole list regardless of the count's
   digit width. .dealer-stat already exists (line ~1306) — not redefined here. */
.dealer-list-stats {
    flex: 0 0 auto;
    min-width: 96px;
    text-align: center;
    font-size: 12px;
    color: var(--text-muted);
}

.dealer-list-action { flex: 0 0 auto; }

@media (max-width: 767.98px) {
    .dealer-list-row {
        flex-wrap: wrap;
        min-height: auto;
    }

    .dealer-list-info { flex: 1 1 100%; }

    .dealer-list-stats,
    .dealer-list-action { flex: 1 1 auto; }
}

/* ============================================================
   § DEALER DETAIL — INFO BAR ACTIONS
   ============================================================ */
/* Space the "View Listings" / "Visit Website" buttons on /dealers/{id}. */
.dealer-info-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
}

/* ============================================================
   § DEALER DETAIL — SOCIAL LINKS
   ============================================================ */
/* Brand-coloured chip row beside the website link on /dealers/{id} (UAT-21-2 #3).
   Chip appearance comes from the shared .social-chip classes. */
.dealer-social {
    display: flex;
    gap: 8px;
    align-items: center;
}

/* ============================================================
   § SOCIAL ICON CHIPS (UAT-21-2 #2 — uniform set/size/hover)
   ============================================================ */
/* Site-wide circular chip around the SocialIcon component's brand-coloured SVGs.
   Mirrors the FTR-0301 .share-icon treatment so hover behaviour is uniform. */
.social-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    text-decoration: none;
    transition: background var(--t-fast), opacity var(--t-fast);
}
.social-chip svg {
    width: 20px;
    height: 20px;
}
.social-chip-light { background: rgba(27, 46, 86, 0.06); }
.social-chip-light:hover { background: rgba(27, 46, 86, 0.14); opacity: 0.9; }
.social-chip-dark { background: rgba(255, 255, 255, 0.15); }
.social-chip-dark:hover { background: rgba(255, 255, 255, 0.28); opacity: 0.9; }
.social-chip:focus-visible { outline: 2px solid rgba(27, 46, 86, 0.5); outline-offset: 2px; }
.social-chip-dark:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.7); }

/* ============================================================
   § DEALER DETAIL — INFO BAR + LOGO (UAT-21-2 #4)
   ============================================================ */
/* Layout for the info bar on /dealers/{id}; the logo box is 300x300 on desktop
   and the image is contained (scaled, never distorted or cropped). */
.dealer-info-bar {
    padding: 24px 0;
}
.dealer-info-bar-inner {
    display: flex;
    gap: 24px;
    align-items: flex-start;
    flex-wrap: wrap;
}
.dealer-info-logo-wrap {
    width: min(300px, 100%);
    aspect-ratio: 1 / 1;
    flex-shrink: 0;
}
.dealer-info-logo {
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: #fff;
    border: 1px solid var(--ps-border-light);
    border-radius: 8px;
}
.dealer-info-logo-initials {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--brand-navy);
    color: #fff;
    font-size: 64px;
    font-weight: 700;
    border-radius: 8px;
}
.dealer-info-meta {
    flex: 1 1 320px;
    min-width: 0;
}
/* [RFT-PSG-2026-0548] normalised 576 -> 575.98 to close the 575/576 1px off-by-one and land on the
   Bootstrap 5 max-width scale (575.98/767.98/991.98/1199.98). SocialChipsAndDealerLogoFtr0443CssTests,
   which previously pinned "@media (max-width: 576px)", is updated in this same order to pin 575.98. */
@media (max-width: 575.98px) {
    .dealer-info-logo-wrap {
        margin-inline: auto;
    }
}

/* ============================================================
   § LISTING DETAIL — SPEC GRID (Highlights)
   ============================================================ */
.spec-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0;
}
.spec-item {
    padding: 14px 16px;
    border-bottom: 1px solid var(--ps-border-light);
    border-right: 1px solid var(--ps-border-light);
}
.spec-item:nth-child(even) { border-right: none; }
.spec-item:nth-last-child(-n+2) { border-bottom: none; }
.spec-label {
    display: flex; align-items: center; gap: 5px;
    font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
    color: var(--text-muted); margin-bottom: 4px; text-align: left;
}
.spec-label .lucide, .spec-label i { width: 13px; height: 13px; }
.spec-value { font-size: 16px; font-weight: 700; color: var(--text-primary); text-align: left; }

/* ============================================================
   § LISTING DETAIL — SELLER INFO CARD
   ============================================================ */
.seller-info-wrap {
    display: flex; align-items: center; gap: 12px; margin-bottom: 12px;
}
.seller-logo-wrap {
    width: 48px; height: 48px; flex-shrink: 0;
}
.seller-logo { width: 48px; height: 48px; object-fit: contain; border-radius: var(--r-sm); }
.seller-logo-initials {
    width: 48px; height: 48px;
    background: var(--brand-navy); color: #fff;
    display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 16px;
    border-radius: var(--r-md);
}
.seller-name { font-size: 14px; font-weight: 500; color: var(--text-primary); }
.seller-name a { color: inherit; text-decoration: none; }
.seller-name a:hover { color: var(--brand-blue); }
.seller-location { font-size: 13px; color: var(--text-secondary); margin-bottom: 8px; display: flex; align-items: center; gap: 5px; }
.seller-phone { font-size: 13px; color: var(--text-secondary); margin-bottom: 6px; display: flex; align-items: center; gap: 5px; }
.seller-phone a { color: var(--text-secondary); text-decoration: none; }
.seller-phone a:hover { color: var(--brand-blue); }
/* Contact name + phone(s) on a single line per contact (BUG-PSG-2026-0710 / Sheet 39 #6).
   Wraps only when the sidebar is too narrow to keep them side by side. */
.seller-contact-line { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 14px; margin-bottom: 6px; }
.seller-contact-line .seller-phone { margin-bottom: 0; }
.seller-contact-line-name { font-size: 14px; font-weight: 500; color: var(--text-primary); display: flex; align-items: center; gap: 5px; }

/* ============================================================
   § UTILITY — MUTED LINK BUTTON
   ============================================================ */
.btn-link-muted {
    background: none; border: none; padding: 0;
    font-size: 12px; color: var(--text-muted);
    cursor: pointer; text-decoration: underline;
    font-family: inherit;
}

/* ============================================================
   § LISTING DETAIL — HEADER NAVY (breadcrumb + title bar)
   ============================================================ */
.detail-header-navy {
    background: var(--brand-navy);
    padding: 16px 0 20px;
    margin-bottom: 24px;
    color: #fff;
}
.detail-header-navy .breadcrumb { color: var(--ps-footer-link); }
.detail-header-navy .breadcrumb a { color: var(--ps-footer-link); }
.detail-header-navy .breadcrumb a:hover { color: #fff; }
.detail-header-navy .breadcrumb-sep { color: var(--ps-footer-link); }
.detail-header-navy .breadcrumb-current { color: var(--ps-footer-link); }
.detail-header-navy .breadcrumb-item { color: var(--ps-footer-link); }
.detail-header-navy .breadcrumb-item.active { color: var(--ps-footer-link); }
.detail-header-navy .breadcrumb-item + .breadcrumb-item::before { color: var(--ps-footer-link); }
.detail-header-navy .detail-title { color: #fff; }
.detail-header-navy .listing-id { color: rgba(255,255,255,0.65); }
.detail-header-navy .detail-title-bar { margin-bottom: 0; }
.detail-header-navy .price-lg { color: #fff; }
.detail-header-navy .badge-used,
.detail-header-navy .badge-featured { opacity: 0.9; }
.detail-header-navy .btn-icon:not(.share-icon) { color: rgba(255,255,255,0.8); background: transparent; border: none; }
.detail-header-navy .btn-icon:not(.share-icon):hover { color: #fff; }

/* Social share icons — brand colours with circular pill background for visibility on dark navy */
.share-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: rgba(255,255,255,0.15);
    border: none;
    cursor: pointer;
    padding: 0;
    text-decoration: none;
    transition: background var(--t-fast), opacity var(--t-fast);
}
.share-icon:hover { background: rgba(255,255,255,0.28); opacity: 0.9; }
.share-icon:focus-visible { outline: 2px solid rgba(255,255,255,0.7); outline-offset: 2px; }

/* ============================================================
   § LISTING GALLERY — ARROW BUTTONS (Lucide icons)
   ============================================================ */
.main-image-container { position: relative; }
.gallery-arrow {
    position: absolute; top: 50%; transform: translateY(-50%);
    width: 40px; height: 40px;
    background: rgba(0,0,0,0.55); border: none; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer; color: #fff;
    transition: background var(--t-fast), color var(--t-fast);
    z-index: 10;
}
.gallery-arrow:hover { background: rgba(0,0,0,0.7); color: var(--brand-blue); }
.gallery-arrow:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: 2px; }
.gallery-arrow i, .gallery-arrow .lucide { width: 20px; height: 20px; }
.gallery-arrow-prev { left: 10px; }
.gallery-arrow-next { right: 10px; }
/* [RFT-PSG-2026-0523] the duplicate `.gallery-thumb { padding:0; background:none; ... }` reset
   that used to live here was merged into the single authoritative .gallery-thumb block under
   "§ 20-23. LISTING DETAIL". Active-thumb border still wins by source order (app.css loads after
   planesales.css and this rule follows the base) — no !important needed. */
.gallery-thumb-active { border-color: var(--brand-blue); }

/* ============================================================
   § ENQUIRY FORM — dark background text + form-input styles
   ============================================================ */
.form-input {
    display: block; width: 100%;
    padding: 9px 12px;
    font-size: 14px; line-height: 1.5;
    color: var(--text-primary);
    background: var(--ps-bg-secondary);
    border: 1px solid var(--ps-border-color);
    border-radius: var(--r-sm);
    transition: border-color var(--t-fast), box-shadow var(--t-fast);
    font-family: inherit;
}
.form-input:focus {
    outline: none;
    border-color: var(--brand-blue);
    box-shadow: 0 0 0 3px rgba(45,147,209,0.15);
}
.form-input::placeholder { color: var(--text-muted); }
textarea.form-input { resize: vertical; min-height: 90px; }

/* [RFT-PSG-2026-0523] the .enquiry-card-head override that used to sit here was merged into the
   single authoritative .enquiry-card-head rule under "§ 19. TRUST BADGES + ENQUIRY CARD". */
.enquiry-price { font-size: 22px; font-weight: 700; color: var(--brand-blue); }
.enquiry-title { font-size: 14px; font-weight: 500; color: rgba(255,255,255,0.9); }
.enquiry-dealer { font-size: 12px; color: rgba(255,255,255,0.55); }
.enquiry-success {
    display: flex; flex-direction: column; align-items: center;
    gap: 12px; padding: 24px 0; text-align: center;
    color: var(--text-primary);
}
.enquiry-success i, .enquiry-success .lucide { width: 40px; height: 40px; color: var(--success-icon); }

/* ============================================================
   § SIMILAR AIRCRAFT — 3-across carousel
   ============================================================ */
.similar-carousel {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 8px;
}
.similar-carousel::-webkit-scrollbar { height: 4px; }
.similar-carousel::-webkit-scrollbar-track { background: var(--section-grey); border-radius: 2px; }
.similar-carousel::-webkit-scrollbar-thumb { background: var(--ps-border-color); border-radius: 2px; }
.similar-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
    min-width: min-content;
}
.similar-grid > * {
    scroll-snap-align: start;
    min-width: 280px;
}
@media (max-width: 767.98px) {
    /* [BUG-PSG-2026-0623] Collapse the similar-aircraft grid to a single column on phones.
       RFT-0621 M4.2's two-column mobile layout never bit at real device widths: its per-card
       viewport-fraction floor only engaged below ~293px, so 320-767px still computed a
       2*240+16 = 496px min-content grid — a sliver wider than the viewport that forced the
       carousel to scroll before a whole first card was visible (QA-RFT-PSG-2026-0621 BUG-001).
       A single full-width column stacks the cards vertically: min-content = 240+16 = 256px fits
       every phone from 320px up, with no horizontal sliver. The per-card floor is kept as a lower
       bound. Desktop 3-col base and the .similar-carousel overflow-x scroll (BUG-0117 pins both)
       are untouched. */
    .similar-grid { grid-template-columns: repeat(1, 1fr); }
    .similar-grid > * { min-width: min(240px, 82vw); }
}
.btn-link-muted:hover { color: var(--text-secondary); }

/* ============================================================
   § PURCHASER DISCLAIMER
   ============================================================ */
.purchaser-disclaimer {
    background: var(--surface-subtle);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 14px 18px;
    margin-top: 24px;
    color: var(--text-muted);
    font-size: 11px;
    line-height: 1.6;
}
.purchaser-disclaimer p { margin: 0; }

/* ============================================================
   § VIEW TOGGLE (Cards / Rows)
   ============================================================ */
.view-toggle {
    display: flex; align-items: center; gap: 2px;
    border: 1px solid var(--ps-border-color); border-radius: var(--r-xs);
    overflow: hidden;
}
.view-toggle-btn {
    display: flex; align-items: center; justify-content: center;
    width: 32px; height: 30px; padding: 0;
    background: #fff; border: none; cursor: pointer;
    color: var(--text-muted); transition: background var(--t-fast), color var(--t-fast);
}
.view-toggle-btn:hover { background: var(--ps-bg-light); color: var(--text-primary); }
.view-toggle-btn.active { background: var(--brand-navy); color: #fff; }

/* ============================================================
   § LISTING ROW VIEW
   ============================================================ */
.listings-rows { display: flex; flex-direction: column; gap: 10px; }

.listing-row-link { display: block; text-decoration: none; color: inherit; }
.listing-row-link:hover { text-decoration: none; }

.listing-row {
    display: flex; align-items: stretch; gap: 0;
    border: 1px solid var(--ps-border-color); border-radius: var(--r-sm);
    background: #fff; overflow: hidden; position: relative;
    transition: box-shadow var(--t-fast), border-color var(--t-fast);
}
.listing-row:hover { box-shadow: 0 2px 12px rgba(0,0,0,0.09); border-color: var(--brand-navy-light, #4a6fa5); }

.listing-row-featured {
    border-color: var(--brand-pale-blue-border, #7baacf);
    background: var(--brand-pale-blue-bg, #99c5ff); /* Ice blue (FTR-0381; superseded the FTR-0350 Azure) */
}
.listing-row-featured:hover { border-color: var(--brand-navy); }

.listing-row-featured-label {
    position: absolute; top: 8px; left: 8px;
    background: var(--brand-navy); color: #fff;
    font-size: 10px; font-weight: 700; letter-spacing: 0.5px;
    padding: 2px 7px; border-radius: 3px; z-index: 1;
    text-transform: uppercase;
}

.listing-row-thumb {
    flex: 0 0 180px; width: 180px; height: 130px;
    position: relative; overflow: hidden; background: var(--ps-bg-light);
}
.listing-row-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.listing-row-badge {
    position: absolute; bottom: 6px; left: 6px;
    font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 3px;
}

.listing-row-body {
    flex: 1; padding: 12px 14px; display: flex; flex-direction: column; gap: 6px; min-width: 0;
}
.listing-row-title {
    font-size: 15px; font-weight: 600; color: var(--text-primary);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Listing ID on the row (list view) — mirrors .listing-card-id, secondary to the title. [BUG-PSG-2026-0551 / Sheet 29 #7] */
.listing-row-id {
    font-size: 12px;
    font-weight: 600;
    color: var(--brand-navy);
    opacity: 0.7;
    margin: 2px 0 4px;
    letter-spacing: 0.02em;
}
.listing-row-specs { display: flex; flex-wrap: wrap; gap: 5px; }
.listing-row-dealer { font-size: 12px; color: var(--text-muted); display: flex; align-items: center; gap: 5px; margin-top: auto; }

.listing-row-price-col {
    flex: 0 0 160px; display: flex; flex-direction: column;
    align-items: flex-end; justify-content: center; gap: 10px;
    padding: 12px 16px; border-left: 1px solid var(--ps-border-color);
}
.listing-row-price { font-size: 18px; font-weight: 700; color: var(--text-primary); white-space: nowrap; }
.listing-row-price-por { font-size: 13px; color: var(--text-muted); font-style: italic; white-space: nowrap; }

@media (max-width: 767.98px) {
    .listing-row-thumb { flex: 0 0 110px; width: 110px; height: 90px; }
    .listing-row-price-col { flex: 0 0 auto; padding: 10px 12px; border-left: none; border-top: 1px solid var(--ps-border-color); flex-direction: row; justify-content: space-between; align-items: center; width: 100%; }
    .listing-row { flex-wrap: wrap; }
    .listing-row-body { padding: 10px 12px; }
    .listing-row-title { font-size: 14px; }
    .listing-row-price-col { flex: 0 0 100%; }
    .listing-row-cta { display: none; }
}

/* ──────────────────────────────────────────────────────────────────────────
   Homepage category CTA — Aircraft / Parts / Property (icon + title + subtitle)
   3 clickable cards that funnel users into each listing search area.
   ────────────────────────────────────────────────────────────────────────── */
.category-cta-section {
    background-color: var(--ps-bg-primary);
}
.section-header-centered {
    justify-content: center;
    text-align: center;
}
.category-cta-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
}
.category-cta-card {
    position: relative;
    display: flex;
    align-items: center;
    gap: 1.25rem;
    padding: 1.75rem;
    background: var(--ps-bg-secondary);
    border: 1px solid var(--ps-border-light);
    border-radius: 14px;
    box-shadow: var(--ps-shadow-card);
    text-decoration: none;
    color: var(--ps-text-primary);
    overflow: hidden;
    transition: transform var(--t-fast) ease, box-shadow var(--t-fast) ease, border-color var(--t-fast) ease;
}
/* Accent bar that wipes up on hover */
.category-cta-card::before {
    content: "";
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 4px;
    background: var(--ps-secondary);
    transform: scaleY(0);
    transform-origin: bottom;
    transition: transform var(--t-fast) ease;
}
.category-cta-card:hover,
.category-cta-card:focus-visible {
    transform: translateY(-4px);
    box-shadow: var(--ps-shadow-lg);
    border-color: var(--ps-secondary);
    color: var(--ps-text-primary);
    outline: none;
}
.category-cta-card:hover::before,
.category-cta-card:focus-visible::before { transform: scaleY(1); }
.category-cta-icon {
    flex: 0 0 auto;
    width: 64px; height: 64px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--ps-bg-hover);
    color: var(--ps-secondary);
    transition: background var(--t-fast) ease, color var(--t-fast) ease, transform var(--t-fast) ease;
}
.category-cta-card:hover .category-cta-icon {
    background: var(--ps-secondary);
    color: #fff;
    transform: scale(1.05);
}
.category-cta-icon i,
.category-cta-icon svg { width: 30px; height: 30px; }
.category-cta-body { flex: 1 1 auto; min-width: 0; }
.category-cta-title {
    margin: 0 0 .3rem;
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--ps-primary);
    line-height: 1.2;
}
.category-cta-subtitle {
    margin: 0;
    font-size: .9rem;
    color: var(--ps-text-light);
    line-height: 1.45;
}
.category-cta-arrow {
    flex: 0 0 auto;
    color: var(--ps-text-placeholder);
    transition: transform var(--t-fast) ease, color var(--t-fast) ease;
}
.category-cta-card:hover .category-cta-arrow {
    color: var(--ps-secondary);
    transform: translateX(4px);
}
.category-cta-arrow i,
.category-cta-arrow svg { width: 20px; height: 20px; }

/* [RFT-PSG-2026-0523] kept at the 900 boundary (NOT folded to a standard stop): HomepageMobileFixesFTR0516
   .Css_CategoryCtaGrid_MobileBreakpoint pins this exact media boundary wrapping the equal-height
   rule. Documented one-off exception to the four-stop scale. */
@media (max-width: 900px) {
    /* Stack the category tiles and force equal-height rows so the three cards
       render as uniform tiles on mobile despite differing subtitle lengths.
       [FTR-PSG-2026-0516 item 2 / UAT-28] */
    .category-cta-grid { grid-template-columns: 1fr; grid-auto-rows: 1fr; }
}

/* ──────────────────────────────────────────────────────────────────────────
   Account / auth / error pages [BUG-PSG-2026-0356] — brand layout helpers.
   These pages now sit inside page-body + section + ps-container (no nav clash).
   ────────────────────────────────────────────────────────────────────────── */
/* Subtle aside card (dealer notice on Login/Register) — replaces Bootstrap bg-light */
.auth-aside { background: var(--ps-bg-hover); }

/* Profile avatar — replaces inline-styled bg-primary circle */
.profile-avatar {
    width: 80px; height: 80px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--ps-primary);
    color: #fff;
    font-size: 1.6rem; font-weight: 700;
    text-transform: uppercase;
}
/* Role chip — replaces Bootstrap bg-secondary badge */
.badge.role-badge { background: var(--ps-secondary); color: #fff; }

/* Shared 404/500 error-page layout (Error.razor + NotFound.razor) */
.error-page { max-width: 560px; margin: 0 auto; text-align: center; }
.error-page-code {
    font-size: 5rem; line-height: 1; font-weight: 800;
    color: var(--ps-secondary); margin-bottom: 1rem;
}
.error-page-title { font-size: 1.5rem; font-weight: 700; color: var(--ps-primary); margin-bottom: .75rem; }
.error-page-text { color: var(--ps-text-light); margin-bottom: 1.5rem; }
.error-page-ref { font-size: .85rem; color: var(--ps-text-light); margin-bottom: 1.5rem; }
.error-page-actions { display: flex; gap: .75rem; justify-content: center; flex-wrap: wrap; }
.error-page-search { margin-top: 2.5rem; }
.error-page-search-form { display: flex; gap: .5rem; max-width: 420px; margin: 1rem auto 0; }
.error-page-search-form .form-input { flex: 1 1 auto; }

/* About page [BUG-PSG-2026-0357] — brand placeholders replacing bg-secondary boxes */
.media-placeholder {
    min-height: 300px; height: 100%;
    display: flex; align-items: center; justify-content: center;
    background: var(--ps-bg-hover); color: var(--ps-primary);
    border-radius: 10px; font-weight: 700; font-size: 1.25rem;
}
.team-avatar {
    width: 100px; height: 100px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--ps-secondary); color: #fff;
    font-size: 1.6rem; font-weight: 700; text-transform: uppercase;
}

/* ──────────────────────────────────────────────────────────────────────────
   Content/info page helpers [FTR-PSG-2026-0358] — readable narrow column,
   card stacks, and a no-JS FAQ accordion (native <details>).
   ────────────────────────────────────────────────────────────────────────── */
.content-narrow { max-width: 820px; margin-left: auto; margin-right: auto; }
.content-stack { display: flex; flex-direction: column; gap: 1.25rem; }

.faq-filters { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.faq-list { display: flex; flex-direction: column; gap: .75rem; }
.faq-item {
    background: var(--ps-bg-secondary);
    border: 1px solid var(--ps-border-light);
    border-radius: 10px;
    overflow: hidden;
}
.faq-q {
    cursor: pointer;
    padding: 1rem 1.25rem;
    font-weight: 600;
    color: var(--ps-primary);
    list-style: none;
    display: flex; justify-content: space-between; align-items: center; gap: 1rem;
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q::after { content: "+"; font-size: 1.35rem; line-height: 1; color: var(--ps-secondary); }
.faq-item[open] .faq-q::after { content: "\2212"; }
.faq-a { padding: 0 1.25rem 1.25rem; color: var(--ps-text-secondary); }

/* Public FAQ page [FTR-PSG-2026-0745] - /content/faq (Pages/Content/Faq.razor).
   The page reuses .faq-filters above for its category buttons and Bootstrap's own .accordion-*
   classes for the questions (the E2E page object drives those selectors), so only the
   category-heading and closing-CTA additions live here. */
.faq-group-heading {
    font-size: 1.05rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--ps-secondary);
    margin: 2rem 0 .75rem;
}
.faq-group-heading:first-child { margin-top: 0; }

/* Bootstrap rounds only .accordion-item:first-of-type / :last-of-type, which - with the group
   headings interleaved between items - leaves every INTERNAL group boundary square. These two rules
   round the first and last item of each group instead, so each category reads as its own card stack.
   :has() is progressive: without it the corners are simply square, never broken. */
.faq-group-heading + .accordion-item,
.faq-group-heading + .accordion-item .accordion-button {
    border-top-left-radius: var(--bs-accordion-border-radius, 10px);
    border-top-right-radius: var(--bs-accordion-border-radius, 10px);
}
.accordion-item:has(+ .faq-group-heading) {
    border-bottom-left-radius: var(--bs-accordion-border-radius, 10px);
    border-bottom-right-radius: var(--bs-accordion-border-radius, 10px);
    margin-bottom: .25rem;
}

.faq-cta {
    margin-top: 2.5rem;
    padding: 2rem 1rem;
    background: var(--ps-bg-hover);
    border-radius: 12px;
}
.faq-cta h2 { color: var(--ps-primary); }

/* About page section helpers [FTR-PSG-2026-0358] */
.about-story { align-items: center; gap: 2rem; }
.about-figure { font-size: 2.5rem; line-height: 1; margin-bottom: .75rem; }
.about-stat { font-size: 2rem; font-weight: 800; color: var(--ps-secondary); line-height: 1.1; }

/* News index [FTR-PSG-2026-0358] — featured card + empty state + image fallback */
.news-feature {
    display: grid; grid-template-columns: 1fr 1fr; gap: 0;
    background: var(--ps-bg-secondary);
    border: 1px solid var(--ps-border-light);
    border-radius: 12px; overflow: hidden;
    text-decoration: none; color: var(--ps-text-primary);
    margin-bottom: 1.5rem;
    box-shadow: var(--ps-shadow-card);
    transition: box-shadow var(--t-fast) ease, transform var(--t-fast) ease;
}
.news-feature:hover { box-shadow: var(--ps-shadow-lg); transform: translateY(-2px); color: var(--ps-text-primary); }
.news-feature-img { min-height: 280px; background: var(--ps-bg-hover); }
.news-feature-img img { width: 100%; height: 100%; object-fit: cover; }
.news-feature-body { padding: 2rem; display: flex; flex-direction: column; gap: .5rem; align-items: flex-start; }
.news-feature-title { font-size: 1.5rem; font-weight: 700; color: var(--ps-primary); margin: 0; }
.empty-state { text-align: center; padding: 3rem 1rem; color: var(--ps-text-light); }
.article-tag { display: inline-block; background: var(--ps-bg-hover); color: var(--ps-primary); font-size: .8rem; font-weight: 600; padding: .25rem .6rem; border-radius: 999px; margin: 0 .4rem .4rem 0; }

/* Legal pages [FTR-PSG-2026-0359] — Privacy/Terms */
.legal-section { margin-bottom: 2.5rem; }
.legal-section h2 { color: var(--ps-primary); }
.legal-toc { margin-bottom: 1.5rem; }
.legal-callout {
    background: var(--ps-bg-hover);
    border-left: 4px solid var(--ps-secondary);
    border-radius: 8px;
    padding: 1rem 1.25rem;
    margin-bottom: 1.5rem;
}

/* Detail-page helpers [RFT-PSG-2026-0361] — replace inline styles */
.detail-prose { white-space: pre-wrap; }
.spec-item-full { grid-column: 1 / -1; }
.video-embed { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; }
.video-embed iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; }
.news-card-img { background: var(--ps-bg-hover); }
.news-card-img img { width: 100%; height: 100%; object-fit: cover; }
/* [RFT-PSG-2026-0523] normalised max-width 768 → 767 to close the 767/768 1px band. */
@media (max-width: 767.98px) { .news-feature { grid-template-columns: 1fr; } }

/* ============================================================
   § SAVE HEART — save/unsave control [FTR-PSG-2026-0460]
   Rendered by UI.Shared/Components/Listings/SaveHeart.razor on every listing card and in the
   .detail-actions bar of both detail pages. .listing-card-img is already position:relative.
   ============================================================ */
.save-heart {
    padding: 7px; background: transparent; border: none; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; line-height: 1;
    color: var(--text-primary);
    transition: transform var(--t-std) ease, color var(--t-std) ease, background var(--t-std) ease;
}
.save-heart:hover { transform: scale(1.1); }
.save-heart:disabled { cursor: default; opacity: 0.6; transform: none; }
.save-heart:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* On a card the heart floats over the top-right of the photo; .card-badges own the top-left.
   The translucent disc keeps an outline heart legible against a bright image. */
.save-heart-card {
    position: absolute; top: 10px; right: 10px; z-index: 2;
    color: #fff; border-radius: 50%; background: rgba(0, 0, 0, 0.35);
}
.save-heart-card:hover { background: rgba(0, 0, 0, 0.5); }

/* On a detail page it is simply another icon in the right-justified .detail-actions flex row. */
.save-heart-detail { padding: 9px; color: var(--text-primary); }

/* On a horizontal/list-view row the heart floats over the top-right of the thumb, mirroring the grid
   card. The thumb is position:relative (overflow:hidden), so the heart anchors inside its bounds and
   clears the bottom-left SOLD badge. [FTR-PSG-2026-0479 item 5] */
.save-heart-row {
    position: absolute; top: 6px; right: 6px; z-index: 2;
    color: #fff; border-radius: 50%; background: rgba(0, 0, 0, 0.35);
    padding: 5px;
}
.save-heart-row:hover { background: rgba(0, 0, 0, 0.5); }

/* Saved state — two classes, so it beats the positional colours above. */
.save-heart.save-heart-on { color: var(--heart-active); }
.save-heart-card.save-heart-on { background: rgba(255, 255, 255, 0.92); }
.save-heart-row.save-heart-on { background: rgba(255, 255, 255, 0.92); }

/* ============================================================
   RFT-PSG-2026-0545 — Advertise page brand-colour pass
   (brief: docs/12-Design/advertise-page-colour-brief-issue-174.md;
    issue #186 item 13 / #174 item 8)

   NOTE ON TOKEN SOURCE: the brief assumes RFT-0522's css/tokens.css
   single-source, which has NOT merged into VOY-0387's base — the
   canonical :root still lives in this file. These rules therefore
   reference the tokens already defined in :root above (no new tokens,
   no new :root, no brand-hex literals). #fff for light-on-dark text
   follows the established idiom (.section-navy h3 { color: #fff }).
   ============================================================ */

/* Option 2 — Branded price-table header + light-grey zebra striping.
   Replaces Bootstrap .table-dark. Header specificity (0,1,2) beats
   Bootstrap's cell rule (0,1,1); zebra td rule (0,2,3) beats it too. */
.advertise-price-table thead th {
    background-color: var(--brand-navy);   /* #1B2E56 — white text = 13.4:1 (AA large/body pass) */
    color: #fff;
    border-color: var(--brand-navy);
}
.advertise-price-table tbody tr:nth-child(even) td {
    background-color: var(--section-grey);  /* #e8eaed — body text #202124 = 13.3:1 */
}

/* Option 3 — Accent the Optional Extras + Banner Ads cards. Pale-blue tint
   (--ps-bg-hover #E8EEF5, a defined pale-blue token; the brief's --brand-pale-blue-bg
   is a VOY-0383 token not present on this branch) with a brand-navy left border.
   Measured text-on-tint contrast (all AA pass): headings/navy 11.4:1, body #3a3a3a
   9.7:1, text-primary #202124 13.8:1, text-muted fallback #616161 5.3:1. No brand-blue
   small text is placed on the tint. Inner price tiles keep their own white background. */
.advertise-accent-card {
    background-color: var(--ps-bg-hover);
    border-left: 4px solid var(--brand-navy);
    padding: var(--sp-5);
}
