/* =========================================================================
   DealRadar product layer.

   Loaded last. Owns the authenticated shell, navigation, dense data surfaces,
   the contextual drawer, the command palette, and the accessibility and motion
   corrections that the older layers got wrong.

   Breakpoint scale (the only values this file uses):
     480px  small mobile      640px  large mobile     860px  tablet
     1100px small desktop     1400px large desktop
   ========================================================================= */

/* =========================================================================
   1. Accessibility floors
   ========================================================================= */

/* A single, consistent focus ring. Several older layers either omitted focus
   styling or relied on the browser default against a dark panel. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--dr-green);
    outline-offset: 2px;
    border-radius: var(--dr-radius-sm);
}

/* Never remove the ring for keyboard users, even where a component sets
   outline:none for mouse interaction. */
:where(a, button, [role="button"]):focus:not(:focus-visible) {
    outline: none;
}

.skip-link:focus-visible {
    outline-offset: 4px;
}

/* =========================================================================
   2. Authenticated shell
   ========================================================================= */

.dr-shell {
    display: block;
    min-height: 100%;
}

/* Compact page header: title, supporting line, and a toolbar slot on the
   right. Replaces the oversized per-page hero blocks. */
.dr-page-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    gap: var(--dr-space-5);
    padding-bottom: var(--dr-space-5);
    margin-bottom: var(--dr-space-6);
    border-bottom: 1px solid var(--dr-line);
}

.dr-page-head-text {
    min-width: 0;
}

.dr-eyebrow {
    display: block;
    margin-bottom: var(--dr-space-2);
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.dr-page-head h1 {
    margin: 0;
    font-size: clamp(1.35rem, 2.4vw, 1.75rem);
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.2;
}

.dr-page-head p {
    max-width: 62ch;
    margin: var(--dr-space-2) 0 0;
    color: var(--dr-text-muted);
    font-size: var(--dr-text-base);
    line-height: 1.55;
}

/* Toolbar: the predictable home for page actions and filters. */
.dr-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--dr-space-2);
}

@media (max-width: 860px) {
    .dr-page-head {
        grid-template-columns: 1fr;
        gap: var(--dr-space-4);
    }

    .dr-toolbar {
        width: 100%;
    }
}

/* =========================================================================
   3. Sidebar navigation
   ========================================================================= */

.v2-sidebar {
    background: var(--dr-midnight-900);
    border: 1px solid var(--dr-line);
    border-radius: var(--dr-radius-md);
    scrollbar-width: thin;
    scrollbar-color: var(--dr-line-strong) transparent;
}

.v2-nav-title {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.1em;
}

/* Group labels were 0.6rem (9.6px). Raised to the 12px legibility floor. */
.v2-nav-group > span {
    padding: 0 var(--dr-space-3) var(--dr-space-2);
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
}

.v2-nav-group a {
    position: relative;
    display: flex;
    gap: var(--dr-space-3);
    align-items: center;
    min-height: 36px;
    padding: var(--dr-space-2) var(--dr-space-3);
    border-radius: var(--dr-radius-sm);
    color: var(--dr-text-soft);
    font-size: var(--dr-text-sm);
    text-decoration: none;
    transition:
        background-color var(--dr-motion-fast) var(--dr-ease),
        color var(--dr-motion-fast) var(--dr-ease);
}

.v2-nav-group a:hover {
    background: var(--dr-green-wash-soft);
    color: var(--dr-text);
}

/* Active state carries three independent cues: a left marker, a tinted
   surface and a colour change. Never colour alone. */
.v2-nav-group a[aria-current="page"] {
    background: var(--dr-green-wash);
    color: var(--dr-text);
    font-weight: 600;
}

.v2-nav-group a[aria-current="page"]::before {
    content: "";
    position: absolute;
    inset-block: 6px;
    left: 0;
    width: 2px;
    border-radius: 0 2px 2px 0;
    background: var(--dr-green);
}

.v2-badge {
    margin-left: auto;
    padding: 1px var(--dr-space-2);
    border-radius: var(--dr-radius-pill);
    background: var(--dr-green);
    color: var(--dr-midnight-950);
    font-size: var(--dr-text-xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* ---- Mobile drawer ------------------------------------------------------
   Below 860px the sidebar becomes a disclosure. Targets move to the 44px
   minimum and the two-column grid is dropped: it produced 34px-tall rows. */
@media (max-width: 860px) {
    .v2-sidebar {
        position: static;
        width: 100%;
        margin: 0 0 var(--dr-space-6);
        max-height: none;
    }

    .v2-sidebar summary {
        display: flex;
        align-items: center;
        justify-content: space-between;
        min-height: var(--dr-touch-min);
        padding: var(--dr-space-3) var(--dr-space-4);
        font-size: var(--dr-text-base);
        font-weight: 600;
        cursor: pointer;
    }

    .v2-sidebar .v2-nav-content {
        display: block;
        padding: var(--dr-space-2) var(--dr-space-3) var(--dr-space-4);
    }

    .v2-nav-group a {
        min-height: var(--dr-touch-min);
        padding: var(--dr-space-3);
        font-size: var(--dr-text-base);
    }

    .v2-nav-group > span {
        padding-top: var(--dr-space-3);
        font-size: var(--dr-text-xs);
    }
}

@media (max-width: 480px) {
    .v2-nav-group a {
        min-height: var(--dr-touch-min);
        padding: var(--dr-space-3);
        gap: var(--dr-space-3);
        font-size: var(--dr-text-base);
    }
}

/* =========================================================================
   4. Marketing chrome legibility
   ========================================================================= */

.brand-announcement .site-container {
    gap: var(--dr-space-2);
    min-height: 40px;
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
}

.v2-marketing .site-nav-links .nav-link {
    min-height: var(--dr-touch-min);
    display: inline-flex;
    align-items: center;
    font-size: var(--dr-text-sm);
}

@media (max-width: 860px) {
    .v2-marketing .site-nav-links .nav-link {
        padding-block: var(--dr-space-2);
    }
}

/* =========================================================================
   5. Filter chips
   ========================================================================= */

.dr-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--dr-space-2);
}

.dr-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--dr-space-2);
    min-height: 34px;
    padding: var(--dr-space-1) var(--dr-space-3);
    border: 1px solid var(--dr-line);
    border-radius: var(--dr-radius-pill);
    background: transparent;
    color: var(--dr-text-soft);
    font-size: var(--dr-text-sm);
    text-decoration: none;
    cursor: pointer;
    transition:
        border-color var(--dr-motion-fast) var(--dr-ease),
        background-color var(--dr-motion-fast) var(--dr-ease),
        color var(--dr-motion-fast) var(--dr-ease);
}

.dr-chip:hover {
    border-color: var(--dr-line-strong);
    color: var(--dr-text);
}

.dr-chip.is-active {
    border-color: var(--dr-line-signal);
    background: var(--dr-green-wash);
    color: var(--dr-text);
    font-weight: 600;
}

@media (max-width: 640px) {
    .dr-chips {
        flex-wrap: nowrap;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        padding-bottom: var(--dr-space-2);
        scrollbar-width: none;
    }

    .dr-chips::-webkit-scrollbar {
        display: none;
    }

    .dr-chip {
        flex: 0 0 auto;
        min-height: var(--dr-touch-min);
    }
}

/* =========================================================================
   6. Contextual detail drawer
   ========================================================================= */

.dr-drawer {
    position: fixed;
    inset: 0;
    z-index: 1200;
}

.dr-drawer[hidden] {
    display: none;
}

.dr-drawer-scrim {
    position: absolute;
    inset: 0;
    background: rgba(5, 7, 19, 0.62);
    backdrop-filter: blur(2px);
    animation: dr-fade-in var(--dr-motion-base) var(--dr-ease) both;
}

.dr-drawer-panel {
    position: absolute;
    inset-block: 0;
    right: 0;
    width: min(460px, 100%);
    display: flex;
    flex-direction: column;
    background: var(--dr-navy-850);
    border-left: 1px solid var(--dr-line-strong);
    box-shadow: var(--dr-shadow-overlay);
    animation: dr-slide-in var(--dr-motion-slow) var(--dr-ease-out) both;
}

.dr-drawer-head {
    display: flex;
    align-items: start;
    gap: var(--dr-space-3);
    padding: var(--dr-space-5);
    border-bottom: 1px solid var(--dr-line);
}

.dr-drawer-head h2 {
    flex: 1 1 auto;
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
    line-height: 1.3;
}

.dr-drawer-body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--dr-space-5);
}

.dr-drawer-close {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 1px solid var(--dr-line);
    border-radius: var(--dr-radius-sm);
    background: transparent;
    color: var(--dr-text-muted);
    cursor: pointer;
    transition:
        color var(--dr-motion-fast) var(--dr-ease),
        border-color var(--dr-motion-fast) var(--dr-ease);
}

.dr-drawer-close:hover {
    border-color: var(--dr-line-strong);
    color: var(--dr-text);
}

@media (max-width: 640px) {
    .dr-drawer-panel {
        inset: auto 0 0 0;
        width: 100%;
        max-height: 88vh;
        border-left: 0;
        border-top: 1px solid var(--dr-line-strong);
        border-radius: var(--dr-radius-lg) var(--dr-radius-lg) 0 0;
        animation: dr-slide-up var(--dr-motion-slow) var(--dr-ease-out) both;
    }

    .dr-drawer-close {
        width: var(--dr-touch-min);
        height: var(--dr-touch-min);
    }
}

/* =========================================================================
   8. Motion primitives
   ========================================================================= */

@keyframes dr-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes dr-slide-in {
    from { opacity: 0; transform: translateX(16px); }
    to   { opacity: 1; transform: none; }
}

@keyframes dr-slide-up {
    from { opacity: 0; transform: translateY(20px); }
    to   { opacity: 1; transform: none; }
}

@keyframes dr-rise {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

/* Reduced motion: no travel, no fade-in delay, content simply present. */
@media (prefers-reduced-motion: reduce) {
    .dr-drawer-scrim,
    .dr-drawer-panel {
        animation: none;
    }

    *,
    *::before,
    *::after {
        animation-duration: 1ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 1ms !important;
        scroll-behavior: auto !important;
    }
}

/* =========================================================================
   9. Shell details
   ========================================================================= */

.dr-signout {
    min-height: 34px;
    padding-inline: var(--dr-space-4);
    font-size: var(--dr-text-sm);
    white-space: nowrap;
}

/* Operator notice. Carries a label as well as a tint, so the state is not
   communicated by colour alone. */
.dashboard-operator-note {
    margin-bottom: var(--dr-space-5);
}

.dashboard-operator-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--dr-space-2);
    padding: var(--dr-space-1) var(--dr-space-3);
    border: 1px solid var(--dr-line-signal);
    border-radius: var(--dr-radius-pill);
    background: var(--dr-green-wash);
    color: var(--dr-green);
    font-size: var(--dr-text-xs);
    font-weight: 600;
}

.dashboard-operator-badge::before {
    content: "●";
    font-size: 0.8em;
}

.dashboard-note {
    margin: var(--dr-space-2) 0 0;
    color: var(--dr-text-muted);
    font-size: var(--dr-text-sm);
}

/* The shell owns the outer padding now, so pages must not add their own. */
.dr-shell .page-section {
    padding-block: 0;
}

.dr-shell > .site-container > :last-child {
    padding-bottom: var(--dr-space-10);
}

@media (max-width: 860px) {
    .dr-toolbar form,
    .dr-toolbar .dr-signout {
        width: 100%;
    }

    .dr-signout {
        min-height: var(--dr-touch-min);
    }
}

/* =========================================================================
   10. Command palette
   ========================================================================= */

.command-dialog {
    animation: dr-rise var(--dr-motion-base) var(--dr-ease-out) both;
}

.command-backdrop {
    animation: dr-fade-in var(--dr-motion-fast) var(--dr-ease) both;
}

.command-section-label {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
}

.command-section-label[hidden] {
    display: none;
}

[data-command-item] {
    min-height: var(--dr-touch-min);
    border-radius: var(--dr-radius-sm);
    transition: background-color var(--dr-motion-fast) var(--dr-ease);
}

[data-command-item][hidden] {
    display: none;
}

/* The active option is marked by a tint and a leading rule, so the highlight
   does not depend on colour perception alone. */
[data-command-item].is-selected {
    background: var(--dr-green-wash);
    box-shadow: inset 2px 0 var(--dr-green);
}

[data-command-item] small {
    display: block;
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
}

.command-empty {
    margin: 0;
    padding: var(--dr-space-5) var(--dr-space-4);
    color: var(--dr-text-muted);
    font-size: var(--dr-text-sm);
    text-align: center;
}

.command-empty[hidden] {
    display: none;
}

.command-footer kbd,
.site-nav-command kbd {
    font-size: var(--dr-text-xs);
}

@media (max-width: 640px) {
    .command-dialog {
        width: calc(100% - 2 * var(--dr-space-4));
        max-width: none;
    }

    .command-footer {
        flex-wrap: wrap;
        gap: var(--dr-space-2) var(--dr-space-4);
    }
}

/* =========================================================================
   11. Deal Score: "Why this score?"
   ------------------------------------------------------------------------
   A disclosure in the card, upgraded to the drawer above when script runs.
   ========================================================================= */

.dr-why {
    margin: var(--dr-space-4) 0 0;
    border: 1px solid var(--dr-line-signal);
    border-radius: var(--dr-radius-md);
    background: var(--dr-green-wash-soft);
}

.dr-why > summary {
    display: flex;
    align-items: center;
    gap: var(--dr-space-4);
    min-height: var(--dr-touch-min);
    padding: var(--dr-space-3) var(--dr-space-4);
    cursor: pointer;
    list-style: none;
}

.dr-why > summary::-webkit-details-marker {
    display: none;
}

.dr-why-score {
    flex: 0 0 auto;
    display: flex;
    align-items: baseline;
    color: var(--dr-green);
    font-variant-numeric: tabular-nums;
}

.dr-why-score-value {
    font-size: 1.75rem;
    font-weight: 600;
    letter-spacing: -0.03em;
    line-height: 1;
}

.dr-why-score-max {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-sm);
}

.dr-why-label {
    display: grid;
    gap: 2px;
    min-width: 0;
}

.dr-why-label strong {
    font-size: var(--dr-text-sm);
    font-weight: 600;
}

.dr-why-label small {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
}

/* A chevron marks the disclosure, so it is not identified by colour alone. */
.dr-why > summary::after {
    content: "\203A";
    margin-left: auto;
    color: var(--dr-text-muted);
    font-size: 1.3rem;
    line-height: 1;
}

.dr-why > summary:hover::after {
    color: var(--dr-green);
}

.dr-why-body {
    padding: 0 var(--dr-space-4) var(--dr-space-4);
}

.dr-drawer-body .dr-why-body {
    padding: 0;
}

.dr-why-lead {
    margin: 0 0 var(--dr-space-4);
    color: var(--dr-text-soft);
    font-size: var(--dr-text-base);
    line-height: 1.6;
}

.dr-why-components {
    display: grid;
    gap: var(--dr-space-3);
    margin-bottom: var(--dr-space-4);
}

.dr-why-component {
    padding: var(--dr-space-3);
    border: 1px solid var(--dr-line);
    border-radius: var(--dr-radius-sm);
    background: var(--dr-navy-850);
}

.dr-why-component-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--dr-space-3);
    margin-bottom: var(--dr-space-2);
}

.dr-why-component-head strong {
    font-size: var(--dr-text-sm);
    font-weight: 600;
}

.dr-why-points {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* The meter repeats the points figure visually; the figure itself is always
   present as text, so the bar is decoration rather than the only signal. */
.dr-why-meter {
    -webkit-appearance: none;
    appearance: none;
    display: block;
    width: 100%;
    height: 3px;
    margin-bottom: var(--dr-space-2);
    border: 0;
    border-radius: 2px;
    background: var(--dr-line);
    overflow: hidden;
    color: var(--dr-green);
}

.dr-why-meter::-webkit-progress-bar {
    border-radius: 2px;
    background: var(--dr-line);
}

.dr-why-meter::-webkit-progress-value {
    border-radius: 2px;
    background: var(--dr-green);
}

.dr-why-meter::-moz-progress-bar {
    border-radius: 2px;
    background: var(--dr-green);
}

.dr-why-component p {
    margin: 0;
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    line-height: 1.55;
}

.dr-why-evidence,
.dr-why-disclaimer,
.dr-why-version {
    margin: 0 0 var(--dr-space-2);
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    line-height: 1.55;
}

.dr-why-evidence strong {
    color: var(--dr-text-soft);
}

.dr-why-version code {
    color: var(--dr-text-soft);
    font-size: 0.95em;
}

/* Scroll lock while the drawer is open. */
body.dr-drawer-open {
    overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
    :root[data-motion="running"] .dr-why-meter > span {
        transition: none;
    }
}

/* =========================================================================
   12. The product's real data tables
   -------------------------------------------------------------------------
   Market Explorer, Inventory and Analytics each had their own table styling.
   They now share the dense-table treatment: a sticky header so the column
   meaning survives a long scroll, tabular numerals so figures line up, and a
   contained horizontal scroll so columns keep readable widths at 390px
   instead of being crushed.
   ========================================================================= */

.market-explorer-table-wrap,
.inventory-table-wrap,
.analytics-table-wrap {
    position: relative;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    border: 1px solid var(--dr-line);
    border-radius: var(--dr-radius-md);
    background: var(--dr-navy-850);
}

.market-explorer-table,
.inventory-table,
.analytics-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--dr-text-sm);
}

.market-explorer-table,
.inventory-table {
    min-width: 760px;
}

.analytics-table {
    min-width: 560px;
}

.market-explorer-table thead th,
.inventory-table thead th,
.analytics-table thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    padding: var(--dr-space-3) var(--dr-space-4);
    background: var(--dr-navy-800);
    border-bottom: 1px solid var(--dr-line-strong);
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-align: left;
    text-transform: uppercase;
    white-space: nowrap;
}

.market-explorer-table tbody td,
.market-explorer-table tbody th,
.inventory-table tbody td,
.inventory-table tbody th,
.analytics-table tbody td,
.analytics-table tbody th {
    padding: var(--dr-space-3) var(--dr-space-4);
    border-bottom: 1px solid var(--dr-line);
    color: var(--dr-text-soft);
    text-align: left;
    vertical-align: middle;
}

.market-explorer-table tbody tr:last-child :is(td, th),
.inventory-table tbody tr:last-child :is(td, th),
.analytics-table tbody tr:last-child :is(td, th) {
    border-bottom: 0;
}

.market-explorer-table tbody tr,
.inventory-table tbody tr,
.analytics-table tbody tr {
    transition: background-color var(--dr-motion-fast) var(--dr-ease);
}

.market-explorer-table tbody tr:hover,
.inventory-table tbody tr:hover,
.analytics-table tbody tr:hover {
    background: rgba(248, 250, 252, 0.028);
}

/* Money and counts line up when the figures share a width. */
.market-explorer-table td,
.inventory-table td,
.analytics-table td {
    font-variant-numeric: tabular-nums;
}

/* The first column identifies the row, so it stays put while the rest of the
   table scrolls sideways on a narrow screen. */
.market-explorer-table tbody th:first-child,
.inventory-table tbody th:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--dr-navy-850);
    border-right: 1px solid var(--dr-line);
    color: var(--dr-text);
    font-weight: 600;
}

/* A scrollable region is focusable so it can be reached and scrolled by
   keyboard; it needs a visible ring when it is. */
.market-explorer-table-wrap:focus-visible,
.inventory-table-wrap:focus-visible,
.analytics-table-wrap:focus-visible {
    outline: 2px solid var(--dr-green);
    outline-offset: 2px;
}

/* =========================================================================
   13. Compact metric strip
   -------------------------------------------------------------------------
   Replaces the oversized KPI cards with a single bordered strip, so the
   numbers read as a summary rather than as the page's main content.
   ========================================================================= */

.opportunity-summary-grid,
.overview-summary-grid,
.analytics-summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 0;
    margin-bottom: var(--dr-space-6);
    border: 1px solid var(--dr-line);
    border-radius: var(--dr-radius-md);
    background: var(--dr-navy-850);
    overflow: hidden;
}

.opportunity-summary-card,
.overview-summary-card,
.analytics-summary-card {
    display: flex;
    flex-direction: column;
    gap: var(--dr-space-1);
    min-width: 0;
    padding: var(--dr-space-4) var(--dr-space-5);
    border-right: 1px solid var(--dr-line);
    background: transparent;
}

.opportunity-summary-card:last-child,
.overview-summary-card:last-child,
.analytics-summary-card:last-child {
    border-right: 0;
}

.opportunity-summary-card > span,
.overview-summary-card > span,
.analytics-summary-card > span {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.opportunity-summary-card > strong,
.overview-summary-card > strong,
.analytics-summary-card > strong {
    color: var(--dr-text);
    font-size: 1.5rem;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    letter-spacing: -0.02em;
}

@media (max-width: 640px) {
    .opportunity-summary-grid,
    .overview-summary-grid,
    .analytics-summary-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .opportunity-summary-card,
    .overview-summary-card,
    .analytics-summary-card {
        border-bottom: 1px solid var(--dr-line);
        padding: var(--dr-space-3) var(--dr-space-4);
    }

    .opportunity-summary-card:nth-child(2n),
    .overview-summary-card:nth-child(2n),
    .analytics-summary-card:nth-child(2n) {
        border-right: 0;
    }
}

/* =========================================================================
   14. Filters
   ========================================================================= */

.opportunity-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: var(--dr-space-3);
    margin-bottom: var(--dr-space-5);
    padding: var(--dr-space-4);
    border: 1px solid var(--dr-line);
    border-radius: var(--dr-radius-md);
    background: var(--dr-navy-850);
}

.opportunity-filters label {
    display: grid;
    gap: var(--dr-space-1);
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.opportunity-filters :is(input, select) {
    min-height: 38px;
    padding: var(--dr-space-2) var(--dr-space-3);
    border: 1px solid var(--dr-line-strong);
    border-radius: var(--dr-radius-sm);
    background: var(--dr-midnight-900);
    color: var(--dr-text);
    font-size: var(--dr-text-sm);
}

@media (max-width: 640px) {
    .opportunity-filters {
        flex-direction: column;
        align-items: stretch;
    }

    .opportunity-filters :is(input, select, button) {
        width: 100%;
        min-height: var(--dr-touch-min);
    }
}

/* =========================================================================
   15. Perpetual motion: one gate for all of it
   -------------------------------------------------------------------------
   Ten looping animations were scattered across five stylesheets: radar
   sweeps, signal pings, a terminal scan line and a shimmer. Their gating was
   inconsistent. dealradar-motion-integration.css honoured the paused state
   for four of them, brand-assets.css honoured only prefers-reduced-motion for
   one, and .v2-radar > div in v2.css honoured neither, so the sweep behind the
   How It Works story kept turning after the visitor pressed "Pause motion"
   and kept turning for a visitor who had asked their system for reduced
   motion.

   Everything that loops is now listed once and gated on the document motion
   state that v2.js maintains, which covers the toggle, reduced motion, a
   hidden tab and an off-screen section together. Only looping animations are
   named here: a blanket rule would also freeze one-shot entrance animations
   mid-way and leave their content stuck at opacity zero.
   ========================================================================= */

:root[data-motion="paused"] :is(
    .v2-radar::before,
    .v2-radar > div,
    .v2-home .v2-hero::after,
    .v2-home .v2-signal-dot::after,
    .v2-home .v2-radar i
) {
    animation-play-state: paused;
}

/* Reduced motion removes them outright rather than freezing a half-drawn
   sweep, so the page settles into a legible resting state. */
@media (prefers-reduced-motion: reduce) {
    .v2-radar::before,
    .v2-radar > div,
    .v2-home .v2-hero::after,
    .v2-home .v2-signal-dot::after,
    .v2-home .v2-radar i {
        animation: none !important;
    }
}

/* =========================================================================
   16. One motion language
   -------------------------------------------------------------------------
   Legacy transitions used .15s, .16s, .18s and 0.15s with default easing.
   The differences were not meaningful, so hover and press feedback across
   the product resolves to the shared fast duration and shared curve.
   ========================================================================= */

:where(a, button, .button, summary, input, select, textarea, [role="button"]) {
    transition-duration: var(--dr-motion-fast);
    transition-timing-function: var(--dr-ease);
}

/* A pressed control should acknowledge the press immediately. */
:where(.button, button):active:not(:disabled) {
    transform: translateY(1px);
}

@media (prefers-reduced-motion: reduce) {
    :where(.button, button):active:not(:disabled) {
        transform: none;
    }
}

/* ---- Active filter chips ------------------------------------------------ */
.dr-active-filters {
    align-items: center;
    margin-bottom: var(--dr-space-4);
}

.dr-active-filters-label {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
}

.dr-chip-remove {
    color: var(--dr-text-muted);
    font-size: 1rem;
    line-height: 1;
}

.dr-chip:hover .dr-chip-remove {
    color: var(--dr-text);
}

.dr-chip-clear {
    border-style: dashed;
}

.dr-chip-clear::before {
    content: none;
}

/* Reference-product preview. object-fit keeps the chosen photo's aspect ratio
   inside the box rather than stretching it. */
[data-reference-preview] {
    max-width: 100%;
    max-height: 280px;
    object-fit: contain;
    border: 1px solid var(--dr-line);
    border-radius: var(--dr-radius-md);
}

[data-reference-preview][hidden] {
    display: none;
}

/* =========================================================================
   17. Analytics: monthly profit
   -------------------------------------------------------------------------
   Real backend figures. The bar length is scaled from the absolute value, so
   a losing month is marked by a hatched fill and a signed figure rather than
   by colour alone.
   ========================================================================= */

.analytics-bar-list {
    display: grid;
    gap: var(--dr-space-2);
}

.analytics-bar-row {
    display: grid;
    grid-template-columns: 96px minmax(0, 1fr) 100px;
    align-items: center;
    gap: var(--dr-space-3);
}

.analytics-bar-row > span {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    white-space: nowrap;
}

.analytics-bar-track {
    -webkit-appearance: none;
    appearance: none;
    display: block;
    width: 100%;
    height: 10px;
    border: 0;
    border-radius: var(--dr-radius-pill);
    background: var(--dr-line);
    overflow: hidden;
    color: var(--dr-green);
}

/* The bar is a <progress>, so its fill is a pseudo-element rather than a
   child. Each engine names that pseudo-element differently and they cannot
   be combined in one selector list: a browser that does not recognise one of
   them drops the whole rule. A losing month keeps the hatched fill it had,
   and the signed figure beside it still carries the direction. */
.analytics-bar-track::-webkit-progress-bar {
    border-radius: var(--dr-radius-pill);
    background: var(--dr-line);
}

.analytics-bar-track::-webkit-progress-value {
    border-radius: var(--dr-radius-pill);
    background: var(--dr-green);
}

.analytics-bar-track::-moz-progress-bar {
    border-radius: var(--dr-radius-pill);
    background: var(--dr-green);
}

.analytics-bar-track--negative::-webkit-progress-value {
    background: repeating-linear-gradient(
        135deg,
        var(--dr-danger) 0 5px,
        rgba(255, 92, 114, 0.5) 5px 10px
    );
}

.analytics-bar-track--negative::-moz-progress-bar {
    background: repeating-linear-gradient(
        135deg,
        var(--dr-danger) 0 5px,
        rgba(255, 92, 114, 0.5) 5px 10px
    );
}

.analytics-bar-row > strong {
    color: var(--dr-text);
    font-size: var(--dr-text-sm);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.analytics-value--negative {
    color: var(--dr-danger);
}

@media (max-width: 640px) {
    .analytics-bar-row {
        grid-template-columns: 72px minmax(0, 1fr) 82px;
        gap: var(--dr-space-2);
    }
}

/* =========================================================================
   18. Sidebar geometry
   -------------------------------------------------------------------------
   The sidebar is position:fixed, so the main column's left offset has to be
   derived from the sidebar's own width and inset. Three files were declaring
   these independently and disagreeing: v2.css paired an 18px inset with a
   218px sidebar and a 236px offset, which is consistent, but brand-system.css
   then widened the sidebar to 232px without touching the offset, putting its
   right edge 14px over the content. Below 1150px it was worse: v2.css
   narrowed the sidebar to 192px and the offset to 210px, but brand-system's
   more specific rule kept the width at 232px, overlapping by 40px.

   Both values now come from the same tokens, at a specificity that settles it.
   ========================================================================= */

.v2-app .v2-sidebar {
    left: var(--dr-sidebar-gap);
    width: var(--dr-sidebar-w);
}

.v2-app .site-main,
.v2-app .site-footer {
    margin-left: var(--dr-sidebar-offset);
}

@media (max-width: 1100px) {
    .v2-app .v2-sidebar {
        width: var(--dr-sidebar-w-compact);
    }

    .v2-app .site-main,
    .v2-app .site-footer {
        margin-left: var(--dr-sidebar-offset-compact);
    }
}

/* Below the tablet breakpoint the sidebar becomes a static disclosure, so the
   offset must go away entirely. */
@media (max-width: 860px) {
    .v2-app .v2-sidebar {
        position: static;
        width: 100%;
        left: auto;
    }

    .v2-app .site-main,
    .v2-app .site-footer {
        margin-left: 0;
    }
}

/* A page with no sidebar (the unlinked-account screen) must not be indented. */
.v2-app:not(:has(.v2-sidebar)) .site-main,
.v2-app:not(:has(.v2-sidebar)) .site-footer {
    margin-left: 0;
}

/* =========================================================================
   19. Authenticated app chrome
   -------------------------------------------------------------------------
   The workspace previously rendered inside the public marketing shell: the
   full Features / How It Works / Pricing / FAQ / Contact navigation sat above
   every dashboard page and the four-column marketing footer sat below it, so
   the product read as a marketing page that happened to contain an app.

   The app header carries branding and the command palette only. Workspace
   navigation is in the sidebar and is not repeated here. The marketing
   navigation is not rendered on these routes at all, so this styling is
   presentation for what is there rather than a way of hiding what is not.
   ========================================================================= */

/* brand-system.css styles ".v2-app .site-header", which outranks a bare
   ".app-header", so these match at the same depth to settle it. */
.v2-app .site-header.app-header {
    position: sticky;
    top: 0;
    z-index: 960;
    border-bottom: 1px solid var(--dr-line);
    background: rgba(8, 11, 24, 0.86);
    backdrop-filter: blur(14px);
}

.v2-app .app-header-bar {
    display: flex;
    align-items: center;
    gap: var(--dr-space-4);
    min-height: var(--dr-app-header-h);
}

.v2-app .app-header .site-brand {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: var(--dr-space-2);
    color: var(--dr-text);
    font-weight: 600;
    letter-spacing: -0.02em;
    text-decoration: none;
}

.v2-app .app-header .site-brand img {
    width: 26px;
    height: 26px;
}

.v2-app .app-header .site-nav-command {
    margin-left: auto;
    margin-right: 0;
}

/* The sidebar hangs below the sticky header; its offset comes from the same
   token so changing the header height cannot leave a gap or an overlap. */
.v2-app .v2-sidebar {
    top: calc(var(--dr-app-header-h) + var(--dr-space-3));
}

/* ---- Compact app footer ------------------------------------------------- */
.v2-app .site-footer.app-footer {
    margin-top: var(--dr-space-10);
    border-top: 1px solid var(--dr-line);
    background: transparent;
}

.v2-app .app-footer .site-container {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--dr-space-2) var(--dr-space-5);
    padding-block: var(--dr-space-4);
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
}

.v2-app .app-footer-legal {
    display: inline-flex;
    gap: var(--dr-space-4);
    margin-left: auto;
}

.v2-app .app-footer-legal a {
    color: var(--dr-text-muted);
    text-decoration: none;
}

.v2-app .app-footer-legal a:hover {
    color: var(--dr-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

@media (max-width: 640px) {
    /* Keep the header to one line on a phone: the palette collapses to its
       icon. The button keeps its aria-label, so its name is unchanged. */
    .v2-app .app-header .site-nav-command span:not(.site-nav-command-icon),
    .v2-app .app-header .site-nav-command kbd {
        display: none;
    }

    .v2-app .app-header .site-nav-command {
        min-width: var(--dr-touch-min);
        min-height: var(--dr-touch-min);
        justify-content: center;
    }

    .v2-app .app-footer .site-container {
        flex-direction: column;
        align-items: flex-start;
    }

    .v2-app .app-footer-legal {
        margin-left: 0;
    }

    .v2-app .app-footer-legal a {
        display: inline-flex;
        align-items: center;
        min-height: var(--dr-touch-min);
    }
}

/* =========================================================================
   20. Command palette control icon
   -------------------------------------------------------------------------
   The decorative icon was a hardcoded Command glyph while the shortcut hint
   beside it correctly swapped to "Ctrl K" off macOS, so Windows read
   "Command, Jump to, Ctrl K". On a phone, where the label and the hint are
   hidden, the Command glyph was the only thing left. It is a magnifier now,
   which means the same thing on every platform. The hint still carries the
   real shortcut and is still set from the platform at runtime.
   ========================================================================= */

.site-nav-command-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
}

.site-nav-command-icon svg {
    display: block;
    width: 15px;
    height: 15px;
}

/* =========================================================================
   21. Page-level controls inside the shared toolbar
   -------------------------------------------------------------------------
   Inventory, Market Explorer, Notifications and review moderation each had a
   genuine page-level control sitting in the body: an add form, an observation
   window, a mark-all action and a status filter. They now render in the
   shell toolbar beside the page heading, so the same kind of control lives in
   the same place across the product.

   Only controls that act on the whole page moved. Section-level form submits
   stayed with their forms, where they belong.
   ========================================================================= */

.dr-toolbar-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--dr-space-2);
    margin: 0;
}

.dr-toolbar-form label {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    white-space: nowrap;
}

.dr-toolbar-form :is(select, input:not([type="hidden"])) {
    min-height: 34px;
    padding: var(--dr-space-1) var(--dr-space-3);
    border: 1px solid var(--dr-line-strong);
    border-radius: var(--dr-radius-sm);
    background: var(--dr-midnight-900);
    color: var(--dr-text);
    font-size: var(--dr-text-sm);
}

.dr-toolbar .button {
    min-height: 34px;
    padding-inline: var(--dr-space-4);
    font-size: var(--dr-text-sm);
    white-space: nowrap;
}

/* The toolbar wraps to its own rows on a phone; every control becomes full
   width and reaches the 44px target rather than being squeezed beside the
   heading. */
@media (max-width: 860px) {
    .dr-toolbar-form {
        width: 100%;
    }

    .dr-toolbar-form :is(select, button) {
        flex: 1 1 auto;
        min-height: var(--dr-touch-min);
    }

    .dr-toolbar .button {
        min-height: var(--dr-touch-min);
    }

    /* The review status filter scrolls sideways rather than wrapping into
       three cramped rows. */
    .dr-toolbar .dr-chips {
        width: 100%;
    }
}

/* =========================================================================
   22. Opportunity detail surface
   -------------------------------------------------------------------------
   The opportunity card used to stack four detail panels beneath every row:
   the score explanation, observed pricing windows, seller activity and offer
   guidance. Each one is real backend data worth reading, but together they
   made a single opportunity taller than the viewport, so the list could not
   be scanned.

   They are now one disclosure per opportunity, upgraded into the drawer. The
   card keeps identity, price, score and actions; the evidence moves one click
   away. Nothing was removed and nothing is computed in the browser.
   ========================================================================= */

/* Wider than the score-only drawer was: these panels carry labelled figures
   in columns and were cramped at the old width. */
.dr-drawer-panel {
    width: min(540px, 100%);
}

.dr-why-label--noscore strong {
    font-size: var(--dr-text-base);
}

/* Inside the detail surface the panels are sections of one document, not
   four separate cards, so they lose their own borders and backgrounds and
   are separated by a rule instead. */
.dr-why-body :is(
    .pricing-intelligence-panel,
    .seller-intelligence-panel,
    .offer-finder-panel
) {
    margin: var(--dr-space-5) 0 0;
    padding: var(--dr-space-5) 0 0;
    border: 0;
    border-top: 1px solid var(--dr-line);
    border-radius: 0;
    background: none;
    box-shadow: none;
}

.dr-why-body :is(
    .pricing-intelligence-kicker,
    .seller-intelligence-kicker,
    .offer-finder-kicker
) {
    margin-bottom: var(--dr-space-1);
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    letter-spacing: 0.08em;
    opacity: 1;
}

/* The panels are laid out for a full-width page. The drawer is a fixed
   column, so the fixed three-column grids are re-flowed by available width
   rather than by viewport width, which a media query cannot see here. */
.dr-why-body .pricing-intelligence-grid {
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}

.dr-why-body :is(.seller-intelligence-grid, .offer-finder-range) {
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
}

.dr-why-body :is(
    .seller-intelligence-grid,
    .offer-finder-range
) > div {
    min-width: 0;
    border-color: var(--dr-line);
    background: var(--dr-navy-850);
}

.dr-why-body :is(
    .seller-intelligence-grid,
    .offer-finder-range
) span {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
}

.dr-why-body :is(
    .seller-intelligence-grid,
    .offer-finder-range
) strong {
    font-variant-numeric: tabular-nums;
}

.dr-why-body .pricing-intelligence-grid article {
    border-color: var(--dr-line);
    background: var(--dr-navy-850);
}

.dr-why-body .pricing-intelligence-grid h3 {
    font-size: var(--dr-text-sm);
}

.dr-why-body .pricing-intelligence-grid dt {
    color: var(--dr-text-muted);
}

.dr-why-body .pricing-intelligence-grid dd {
    font-variant-numeric: tabular-nums;
}

/* Every panel ends with a limitation statement from the backend. They stay
   visible and quiet rather than being hidden as fine print. */
.dr-why-body :is(
    .pricing-intelligence-disclaimer,
    .seller-intelligence-disclaimer,
    .offer-finder-disclaimer,
    .pricing-intelligence-warning,
    .seller-intelligence-reason,
    .offer-finder-reason
) {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    line-height: 1.55;
    opacity: 1;
}

.dr-why-body .pricing-intelligence-warning {
    color: var(--dr-warning);
}


/* =========================================================================
   23. Product states: metrics, alerts, validation, empty
   -------------------------------------------------------------------------
   An audit of every class used in markup against every class defined in CSS
   found several that were never styled at all. Three of them matter:

     .dashboard-stat-card   17 uses — the metric strips on Analytics,
                            Inventory and the admin overview rendered as bare
                            text in a grid.
     .dashboard-alert /     the success and failure messages on Inventory,
     .dashboard-error /     Sourcing, Image Studio and the admin pages were
     .dashboard-success     visually identical to body copy, so a failed
                            action read as ordinary prose.
     .field-validation-error  ASP.NET validation messages had no styling,
                            so a rejected field said nothing in particular.

   Status is never carried by colour alone here: each state has its own
   marker glyph and its own wording, and colour only reinforces them.
   ========================================================================= */

.dr-stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--dr-space-3);
    margin-bottom: var(--dr-space-5);
}

.dashboard-stat-card {
    display: grid;
    gap: 2px;
    align-content: start;
    min-width: 0;
    padding: var(--dr-space-4);
    border: 1px solid var(--dr-line);
    border-radius: var(--dr-radius-md);
    background: var(--dr-surface);
}

.dashboard-stat-card > span {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.dashboard-stat-card > strong {
    color: var(--dr-text);
    font-size: 1.375rem;
    font-weight: 600;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.dashboard-stat-card > small {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    line-height: 1.45;
}

/* One alert component. The modifier decides the marker and the accent; the
   base carries the layout so an unmodified .dashboard-alert still reads as a
   message rather than as a paragraph. */
.dashboard-alert,
.dashboard-error,
.dashboard-success,
.admin-review-notice {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--dr-space-3);
    align-items: start;
    margin: var(--dr-space-4) 0;
    padding: var(--dr-space-4);
    border: 1px solid var(--dr-line);
    border-left-width: 3px;
    border-radius: var(--dr-radius-md);
    background: var(--dr-surface);
    color: var(--dr-text);
    font-size: var(--dr-text-base);
    line-height: 1.55;
}

.dashboard-alert::before,
.dashboard-error::before,
.dashboard-success::before,
.admin-review-notice::before {
    content: "i";
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    margin-top: 1px;
    border: 1px solid currentColor;
    border-radius: var(--dr-radius-pill);
    color: var(--dr-text-secondary);
    font-size: var(--dr-text-xs);
    font-weight: 700;
    font-style: italic;
}

.dashboard-alert-error,
.dashboard-error,
.admin-review-notice--error {
    border-color: var(--dr-danger);
    background: var(--dr-danger-wash);
}

.dashboard-alert-error::before,
.dashboard-error::before,
.admin-review-notice--error::before {
    content: "!";
    color: var(--dr-danger);
    font-style: normal;
}

.dashboard-alert-success,
.dashboard-success {
    border-color: var(--dr-green-600);
    background: var(--dr-green-wash-soft);
}

.dashboard-alert-success::before,
.dashboard-success::before {
    content: "\2713";
    color: var(--dr-green-600);
    font-style: normal;
}

/* Model validation. A rejected field said nothing in particular before; it
   now names itself as an error and sits directly under its control. */
.field-validation-error,
.validation-summary-errors {
    display: block;
    margin-top: var(--dr-space-2);
    color: var(--dr-danger);
    font-size: var(--dr-text-sm);
    line-height: 1.45;
}

.field-validation-error:not(:empty)::before {
    content: "Error: ";
    font-weight: 600;
}

.validation-summary-errors ul {
    margin: 0;
    padding-left: 1.1rem;
}

.input-validation-error {
    border-color: var(--dr-danger);
}

/* Labelled facts, two columns on a wide panel and stacked when narrow. */
.dr-kv {
    display: grid;
    gap: 0;
    margin: 0;
}

.dr-kv > div {
    display: grid;
    grid-template-columns: minmax(120px, 34%) minmax(0, 1fr);
    gap: var(--dr-space-3);
    padding: var(--dr-space-3) 0;
    border-top: 1px solid var(--dr-line);
}

.dr-kv > div:first-child {
    border-top: 0;
    padding-top: 0;
}

.dr-kv dt {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-sm);
}

.dr-kv dd {
    margin: 0;
    color: var(--dr-text);
    font-size: var(--dr-text-sm);
    overflow-wrap: anywhere;
}

.dr-admin-columns {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: var(--dr-space-5);
    align-items: start;
}

.dr-admin-columns > .dashboard-panel {
    margin-top: 0;
}

.dr-admin-links {
    display: grid;
    gap: var(--dr-space-3);
    margin: var(--dr-space-4) 0 0;
    padding: 0;
    list-style: none;
}

.dr-admin-links > li {
    display: grid;
    gap: 2px;
    padding: var(--dr-space-3) 0;
    border-top: 1px solid var(--dr-line);
}

.dr-admin-links > li > span {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-sm);
    line-height: 1.5;
}

@media (max-width: 520px) {
    .dr-kv > div {
        grid-template-columns: minmax(0, 1fr);
        gap: 2px;
    }
}

/* Empty states are a designed state, not an absence. Inventory and the
   Listing Assistant both used this class with nothing behind it, so "No
   inventory yet" read as a stray heading in the middle of a panel. */
.dashboard-empty-state {
    display: grid;
    gap: var(--dr-space-2);
    justify-items: start;
    padding: var(--dr-space-8) var(--dr-space-5);
    border: 1px dashed var(--dr-line);
    border-radius: var(--dr-radius-md);
    background: var(--dr-bg-app);
    text-align: left;
}

.dashboard-empty-state h3 {
    margin: 0;
    color: var(--dr-text);
    font-size: var(--dr-text-base);
    font-weight: 600;
}

.dashboard-empty-state p {
    margin: 0;
    max-width: 52ch;
    color: var(--dr-text-muted);
    font-size: var(--dr-text-sm);
    line-height: 1.55;
}

/* =========================================================================
   24. Dense tables
   -------------------------------------------------------------------------
   Inventory, Analytics and Market Explorer each grew their own table styles,
   and the three drifted: cell padding was 0.85rem, 0.75rem and 0.75rem, and
   the row rule was a faint grey on two of them and full-strength currentColor
   on the third, which read as a much heavier table for no reason. None of
   them distinguished the header row from the body, and none used tabular
   figures, so columns of money did not line up.

   This gives all three one treatment. It changes no markup and adds no
   sorting: the order of every table here is decided by the backend, and a
   header that offered to sort would be claiming something the page cannot do.
   ========================================================================= */

.inventory-table,
.analytics-table,
.market-explorer-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--dr-text-sm);
    font-variant-numeric: tabular-nums;
}

.inventory-table :is(th, td),
.analytics-table :is(th, td),
.market-explorer-table :is(th, td) {
    padding: var(--dr-space-3);
    border-bottom: 1px solid var(--dr-line);
    text-align: left;
    vertical-align: top;
}

.inventory-table thead th,
.analytics-table thead th,
.market-explorer-table thead th {
    border-bottom-color: var(--dr-line-strong);
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
}

.inventory-table tbody tr:last-child :is(th, td),
.analytics-table tbody tr:last-child :is(th, td),
.market-explorer-table tbody tr:last-child :is(th, td) {
    border-bottom: 0;
}

/* Secondary lines inside a cell are metadata, not body copy. */
.inventory-table td > span,
.market-explorer-table td span {
    display: block;
    margin-top: 2px;
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
}

/* Each table sits in a region that is focusable so it can be scrolled from
   the keyboard. That was already true, but the focus was invisible, so a
   keyboard user could not tell the table had taken focus. */
.inventory-table-wrap,
.analytics-table-wrap,
.market-explorer-table-wrap {
    overflow-x: auto;
    border-radius: var(--dr-radius-sm);
}

.inventory-table-wrap:focus-visible,
.analytics-table-wrap:focus-visible,
.market-explorer-table-wrap:focus-visible {
    outline: 2px solid var(--dr-teal);
    outline-offset: 2px;
}

/* Administrative record rows. The community page rendered up to 500 referral
   records and 200 audit records as full bordered panels, all open, so the page
   was over a thousand cards long. They are rows inside a disclosure now, the
   same pattern the members list on that page already used. */
.admin-record {
    padding: var(--dr-space-3) 0;
    border-top: 1px solid var(--dr-line);
    list-style: none;
}

.admin-record:first-child {
    border-top: 0;
}

.admin-record :is(h3, strong) {
    margin: 0;
    font-size: var(--dr-text-sm);
    font-weight: 600;
}

.admin-record p {
    margin: 2px 0 0;
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    line-height: 1.55;
}

/* On a narrow screen these tables scroll sideways, and the column that says
   which row you are reading scrolls away with everything else. It stays put
   instead. Only tables whose first column is the row's identity get this:
   Inventory and Analytics lead with the item, Market Explorer with the niche.
   The background has to be opaque or the scrolled columns show through. */
@media (max-width: 860px) {
    .inventory-table :is(thead th, tbody td):first-child,
    .analytics-table :is(thead th, tbody td):first-child,
    .market-explorer-table :is(thead th, tbody td):first-child {
        position: sticky;
        left: 0;
        z-index: 1;
        background: var(--dr-surface-raised);
    }

    .inventory-table :is(thead th, tbody td):first-child::after,
    .analytics-table :is(thead th, tbody td):first-child::after,
    .market-explorer-table :is(thead th, tbody td):first-child::after {
        content: "";
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        width: 1px;
        background: var(--dr-line);
    }
}

/* =========================================================================
   25. Status badges
   -------------------------------------------------------------------------
   Five families of pill badge had grown up separately: search state, review
   moderation state, inventory state, the offer candidate mark and the
   pricing scope mark. They used four different font sizes (0.76, 0.8, 0.85,
   0.85rem) and three different weights (600, 700, 750), so the same idea
   looked like three different components depending on the page. Review
   status had no base rule at all — only its colour modifiers.

   One shape and one type treatment for all of them. Colour is deliberately
   left to each family's own modifiers, and every badge still carries its
   state as words, so none of them depends on colour to be read.
   ========================================================================= */

.search-status-badge,
.search-mode-badge,
.review-status,
.inventory-status,
.offer-finder-candidate,
.pricing-intelligence-scope {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
    padding: 2px var(--dr-space-2);
    border-radius: var(--dr-radius-pill);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

/* =========================================================================
   26. Command palette: server-backed results
   -------------------------------------------------------------------------
   Results the server returned for the typed query sit above the static
   navigation, separated by a rule so it is obvious which part of the list is
   this account's own records and which is the fixed set of pages.

   The state line is one element for all three states — searching, nothing
   found, unavailable — because they are mutually exclusive and a reader
   should only ever have one of them to interpret.
   ========================================================================= */

.command-live:not([hidden]) {
    display: block;
    padding-bottom: var(--dr-space-2);
    border-bottom: 1px solid var(--dr-line);
    margin-bottom: var(--dr-space-2);
}

.command-live-item {
    /* Inherits the option layout from .command-results a. */
    min-height: var(--dr-touch-min);
}

.command-live-state {
    display: flex;
    align-items: center;
    gap: var(--dr-space-2);
    margin: 0 0 var(--dr-space-2);
    padding: var(--dr-space-3) var(--dr-space-3) var(--dr-space-4);
    border-bottom: 1px solid var(--dr-line);
    color: var(--dr-text-muted);
    font-size: var(--dr-text-sm);
    line-height: 1.5;
}

/* Never colour alone: each state also has its own marker and its own words. */
.command-live-state::before {
    content: "\2022";
    color: var(--dr-text-muted);
    font-size: 1.1em;
    line-height: 1;
}

.command-live-state[data-tone="loading"]::before {
    content: "\2026";
    color: var(--dr-teal);
}

.command-live-state[data-tone="empty"]::before {
    content: "\2205";
}

.command-live-state[data-tone="error"] {
    color: var(--dr-danger);
}

.command-live-state[data-tone="error"]::before {
    content: "!";
    color: var(--dr-danger);
    font-weight: 700;
}

/* The ordering the server confirmed applying. It sits with the active filter
   chips because it narrows the same list, but it is stated rather than
   removable: there is always some ordering, so there is nothing to clear. */
.dr-applied-sort {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--dr-space-2);
    margin: 0 0 var(--dr-space-3);
    color: var(--dr-text-secondary);
    font-size: var(--dr-text-sm);
}

.dr-applied-sort-label {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.dr-applied-sort-note {
    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
}

/* The inventory ordering control. It shares the toolbar form treatment so a
   page-level control looks the same wherever it sits. */
.inventory-sort {
    margin: var(--dr-space-4) 0 var(--dr-space-3);
}

/* Billing actions on Plan & Usage. Each button is its own POST form, so they
   are laid out as a row of forms rather than a row of buttons. */
.billing-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--dr-space-3);
    margin-top: var(--dr-space-4);
}

.billing-action {
    margin: 0;
}

.billing-action .button {
    min-height: var(--dr-touch-min);
}

/* A plan already in force stays readable rather than fading out of contrast:
   it is information, not a broken control. */
.billing-action .button[disabled] {
    cursor: default;
    opacity: 0.75;
}

@media (max-width: 520px) {
    .billing-actions {
        flex-direction: column;
        align-items: stretch;
    }

    .billing-action .button {
        width: 100%;
    }
}

/* A pricing call to action is a POST form now, not a link. The form must not
   introduce its own spacing where the link had none. */
.plan-cta {
    margin: 0;
}

.plan-cta .button {
    width: 100%;
    min-height: var(--dr-touch-min);
}


/* =========================================================
   27. Saved table layout

   The layout panel and the compact density it can select.

   Density is a class on the table rather than an inline style, so the
   Content-Security-Policy stays style-src 'self'. The value it comes from
   is server-chosen and already validated against a two-value allow-list,
   so there is nothing here a stored preference could widen.
   ========================================================= */

.dr-layout-panel {
    margin: 0 0 0.85rem;

    border: 1px solid var(--dr-navy-700);
    border-radius: 10px;

    background: var(--dr-navy-850);
}

.dr-layout-panel > summary {
    display: flex;
    gap: 0.55rem;
    align-items: center;

    padding: 0.6rem 0.85rem;

    /* 44px is the mobile touch-target floor the rest of the product holds. */
    min-height: 44px;

    color: var(--dr-text);
    font-size: 0.86rem;
    font-weight: 600;

    cursor: pointer;
}

.dr-layout-panel > summary:focus-visible {
    outline: 2px solid var(--dr-cyan);
    outline-offset: -2px;

    border-radius: 10px;
}

.dr-layout-badge {
    padding: 0.1rem 0.42rem;

    border: 1px solid rgba(44, 247, 107, 0.34);
    border-radius: 999px;

    color: var(--dr-green);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    letter-spacing: 0.02em;
}

.dr-layout-form {
    display: flex;
    flex-wrap: wrap;
    gap: 1.1rem;

    padding: 0 0.85rem 0.85rem;

    border-top: 1px solid var(--dr-navy-700);
}

.dr-layout-group {
    margin: 0.85rem 0 0;
    padding: 0;

    border: 0;
}

.dr-layout-group > legend {
    padding: 0;

    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.dr-layout-option {
    display: flex;
    gap: 0.45rem;
    align-items: center;

    /* Keeps the whole row a comfortable target, not just the box. */
    min-height: 32px;

    color: var(--dr-text);
    font-size: 0.84rem;

    cursor: pointer;
}

.dr-layout-option input:focus-visible {
    outline: 2px solid var(--dr-cyan);
    outline-offset: 2px;
}

.dr-layout-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: flex-end;

    margin-top: 0.85rem;
}

.dr-layout-note {
    flex-basis: 100%;

    margin: 0.6rem 0 0;

    color: var(--dr-text-muted);
    font-size: 0.76rem;
    line-height: 1.5;
}

/* Compact density. Only spacing and type scale change: no column is
   removed and no value is abbreviated, so a compact table says exactly
   what a comfortable one says. */
.dr-table-compact th,
.dr-table-compact td {
    padding-top: 0.38rem;
    padding-bottom: 0.38rem;

    /* The product's 12px floor. Compact must not cross it. */
    font-size: 0.78rem;
}

@media (max-width: 640px) {
    .dr-layout-form {
        flex-direction: column;
        gap: 0.35rem;
    }
}

/* Compact density on the opportunity list. Cards, not columns: only the
   gap between them and their internal padding tighten. No evidence is
   removed — a compact card says exactly what a comfortable one says. */
.opportunity-list.dr-table-compact {
    gap: 0.5rem;
}

.opportunity-list.dr-table-compact .opportunity-card {
    padding: 0.7rem 0.85rem;
}

/* The observed-window caveat on Opportunities. Stated plainly rather than
   as a warning: it is a fact about the data, not a problem to fix. */
.opportunity-window-note {
    margin: 0 0 0.7rem;
    padding: 0.5rem 0.7rem;

    border-left: 2px solid var(--dr-navy-700);
    border-radius: 0 6px 6px 0;

    background: var(--dr-navy-850);

    color: var(--dr-text-muted);
    font-size: var(--dr-text-xs);
    line-height: 1.55;
}
