/* Phase 12 Design System — tokens + base + component classes.
   Shared across Admin (Blazor Server) and Client (WASM) via RCL static web assets.
   Per D-11 no component CSS file may contain hex literals — everything resolves here. */

:root {
    /* Spacing scale */
    --space-0: 0;
    --space-1: 0.25rem;  /* 4px */
    --space-2: 0.5rem;   /* 8px */
    --space-3: 0.75rem;  /* 12px */
    --space-4: 1rem;     /* 16px */
    --space-5: 1.5rem;   /* 24px */
    --space-6: 2rem;     /* 32px */
    --space-7: 3rem;     /* 48px */
    --space-8: 4rem;     /* 64px */

    /* Type scale */
    --text-xs: 0.75rem;
    --text-sm: 0.875rem;
    --text-base: 1rem;
    --text-lg: 1.125rem;
    --text-xl: 1.25rem;
    --text-2xl: 1.5rem;
    --text-3xl: 1.875rem;
    --text-4xl: 2.25rem;

    --leading-tight: 1.2;
    --leading-normal: 1.5;
    --leading-loose: 1.7;

    --weight-regular: 400;
    --weight-medium: 500;
    --weight-semibold: 600;
    --weight-bold: 700;

    /* Surfaces */
    --surface-primary: #ffffff;
    --surface-secondary: #f8f9fc;
    --surface-tertiary: #f0f2f7;

    /* Text */
    --text-primary: #1a1d29;
    --text-secondary: #4a5065;
    --text-muted: #6b7280;

    /* Borders */
    --border-subtle: #e5e7ef;
    --border-strong: #cfd3df;

    /* Radius */
    --radius-sm: 0.5rem;
    --radius-md: 0.75rem;
    --radius-lg: 1rem;
    --radius-xl: 1.25rem;

    /* Modal max-width — Xl is the shared home for the image-dense dossier width
       (Phase 40); Sm/Md/Lg siblings are brand-overridable in each app's app.css. */
    --ds-modal-max-w-xl: min(64rem, 92vw);

    /* Shadows */
    --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
    --shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08);
    --shadow-lg: 0 12px 24px rgba(15, 23, 42, 0.12);
    --shadow-hover: 0 6px 16px rgba(15, 23, 42, 0.12);

    /* Semantic */
    --success: #059669;
    --success-bg: #ecfdf5;
    --success-fg: #065f46;
    --warning: #d97706;
    --warning-bg: #fffbeb;
    --warning-fg: #92400e;
    /* 2026-05-19 — toned the danger token from Tailwind red-600 (#dc2626) to
       Bootstrap's red so DsButton/Variant=danger reads at the same intensity
       as the legacy `btn btn-danger` (Fee Scenarios Delete). Brokers flagged
       the Clients-page Archive/Cancel buttons as overwhelming next to the
       Fee Scenarios Delete; this brings both surfaces into one palette. */
    --danger: #dc3545;
    --danger-bg: #f8d7da;
    --danger-fg: #bb2d3b;
    --info: #0284c7;
    --info-bg: #f0f9ff;
    --info-fg: #075985;

    /* Motion (declared, sparingly used) */
    --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
    --dur-fast: 120ms;
    --dur-base: 200ms;

    /* Z-index */
    --z-nav: 100;
    --z-modal-backdrop: 900;
    --z-modal: 1000;
    --z-toast: 1100;

    /* Focus ring (with fallback below) */
    --focus-ring: 0 0 0 3px color-mix(in srgb, var(--brand-accent-focus, #2572FB) 40%, transparent);

    /* Breakpoints (reference only — use in media queries directly) */
    --bp-sm: 640px;
    --bp-md: 768px;
    --bp-lg: 1024px;
    --bp-xl: 1280px;
}

@supports not (color: color-mix(in srgb, red, blue)) {
    :root { --focus-ring: 0 0 0 3px rgba(37, 140, 251, 0.4); }
}

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

body {
    font-family: var(--font-body);
    color: var(--text-primary);
    background: var(--surface-secondary);
    line-height: var(--leading-normal);
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-heading);
    color: var(--text-primary);
    line-height: var(--leading-tight);
}

a {
    color: var(--brand-accent);
}

/* ============ Component classes (Plan 12-02) ============
   Full rule bodies for every ds-* class. Every property resolves to a token. */

/* Page shell */
.ds-page {
    max-width: 1280px;
    margin: 0 auto;
    padding: var(--space-6) var(--space-5) var(--space-8);
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.ds-page-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.ds-page-header h1 {
    font-family: var(--font-heading);
    font-size: var(--text-3xl);
    font-weight: var(--weight-regular);
    color: var(--text-primary);
    line-height: var(--leading-tight);
    margin: 0;
}

/* Card */
.ds-card {
    background: var(--surface-primary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: var(--space-5);
    box-shadow: var(--shadow-sm);
}

.ds-card--compact {
    padding: var(--space-4);
}

/* Button */
.ds-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-tight);
    cursor: pointer;
    transition: background-color var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
}

.ds-btn:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

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

.ds-btn--primary {
    background: var(--brand-accent);
    color: var(--surface-primary);
    border-color: var(--brand-accent-border);
}

.ds-btn--primary:hover:not(:disabled) {
    background: var(--brand-accent-hover);
}

.ds-btn--secondary {
    background: var(--surface-primary);
    color: var(--text-primary);
    border-color: var(--border-strong);
}

.ds-btn--secondary:hover:not(:disabled) {
    background: var(--surface-tertiary);
}

.ds-btn--danger {
    background: var(--danger);
    color: var(--surface-primary);
    border-color: var(--danger);
}

.ds-btn--danger:hover:not(:disabled) {
    background: var(--danger-fg);
    border-color: var(--danger-fg);
}

.ds-btn--ghost {
    background: transparent;
    color: var(--brand-accent);
    border-color: transparent;
}

.ds-btn--ghost:hover:not(:disabled) {
    background: var(--surface-tertiary);
}

.ds-btn--sm {
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
    min-height: 2rem;
}

.ds-btn--md {
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-base);
    min-height: 2.5rem;
}

.ds-btn--lg {
    padding: var(--space-3) var(--space-5);
    font-size: var(--text-base);
    min-height: 2.75rem;
}

/* Row actions overflow ("kebab") menu — one consistent control per table row.
   Item styles must be global (not CSS-isolated) because RowActionsMenu renders
   its items via ChildContent owned by the parent component's scope. */
.row-actions {
    position: relative;
    display: inline-flex;
}

.row-actions__trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-size: var(--text-lg);
    line-height: 1;
    cursor: pointer;
    transition: background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
}

.row-actions__trigger:hover {
    background: var(--surface-tertiary);
    color: var(--text-primary);
}

.row-actions__trigger:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

.row-actions__backdrop {
    /* Invisible full-viewport surface that closes the popover on any outside
       click. Sits below the popover so item clicks land first. */
    position: fixed;
    inset: 0;
    z-index: 39;
    background: transparent;
}

.row-actions__popover {
    position: absolute;
    top: calc(100% + 0.25rem);
    right: 0;
    z-index: 40;
    min-width: 12rem;
    padding: var(--space-1);
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    background: var(--surface-primary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md, 0 8px 24px rgba(0, 0, 0, 0.12));
}

.row-actions__item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    text-align: left;
    padding: var(--space-2) var(--space-3);
    min-height: 2.5rem;
    background: transparent;
    border: 0;
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--text-primary);
    cursor: pointer;
    white-space: nowrap;
}

.row-actions__item:hover,
.row-actions__item:focus-visible {
    background: var(--surface-tertiary);
    outline: none;
}

.row-actions__item--danger {
    color: var(--danger);
}

.row-actions__item--danger:hover,
.row-actions__item--danger:focus-visible {
    background: var(--danger-bg, var(--surface-tertiary));
    color: var(--danger-fg, var(--danger));
}

/* Badge */
.ds-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-2);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-tight);
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
}

.ds-badge--neutral {
    background: var(--surface-tertiary);
    color: var(--text-secondary);
    border-color: var(--border-subtle);
}

.ds-badge--success {
    background: var(--success-bg);
    color: var(--success-fg);
    border-color: var(--success-bg);
}

.ds-badge--warning {
    background: var(--warning-bg);
    color: var(--warning-fg);
    border-color: var(--warning-bg);
}

.ds-badge--danger {
    background: var(--danger-bg);
    color: var(--danger-fg);
    border-color: var(--danger-bg);
}

.ds-badge--info {
    background: var(--info-bg);
    color: var(--info-fg);
    border-color: var(--info-bg);
}

.ds-badge--brand {
    background: var(--surface-primary);
    color: var(--brand-accent);
    border-color: var(--brand-accent);
}

/* Field (Input) */
.ds-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    font-family: var(--font-body);
}

.ds-field__label {
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    color: var(--text-primary);
    line-height: var(--leading-tight);
}

.ds-field__input {
    font-family: var(--font-body);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    padding: var(--space-3);
    background: var(--surface-primary);
    color: var(--text-primary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    min-height: 2.5rem;
}

.ds-field__input:focus-visible {
    outline: none;
    border-color: var(--brand-accent);
    box-shadow: var(--focus-ring);
}

.ds-field__hint {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--text-muted);
    line-height: var(--leading-normal);
}

.ds-field__error {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--danger);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-normal);
}

/* Table */
.ds-table {
    width: 100%;
    border-collapse: collapse;
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--text-primary);
    background: var(--surface-primary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.ds-table thead th {
    text-align: left;
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    color: var(--text-secondary);
    background: var(--surface-secondary);
    border-bottom: 1px solid var(--border-subtle);
}

.ds-table tbody td {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border-subtle);
}

.ds-table tbody tr:last-child td {
    border-bottom: none;
}

.ds-table-row-clickable {
    cursor: pointer;
    transition: background-color var(--dur-fast) var(--ease-out);
}

.ds-table-row-clickable:hover {
    background: var(--surface-tertiary);
}

.ds-table-row-clickable:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* Empty state */
.ds-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-7) var(--space-5);
    color: var(--text-secondary);
    text-align: center;
}

/* Skeleton */
.ds-skeleton {
    background: var(--surface-tertiary);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.ds-skeleton--row {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--surface-primary);
    border: 1px solid var(--border-subtle);
}

.ds-skeleton__cell {
    display: block;
    height: var(--space-4);
    background: var(--surface-tertiary);
    border-radius: var(--radius-sm);
    animation: ds-skeleton-pulse 1.4s ease-in-out infinite;
}

@keyframes ds-skeleton-pulse {
    0% { opacity: 1; }
    50% { opacity: 0.5; }
    100% { opacity: 1; }
}

/* Error panel */
.ds-error-panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-6) var(--space-5);
    background: var(--danger-bg);
    color: var(--danger-fg);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    text-align: center;
}

/* Filter chip */
.ds-filter-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-2) var(--space-3);
    background: var(--surface-primary);
    color: var(--text-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-xl);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    cursor: pointer;
    transition: background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out);
}

.ds-filter-chip:hover {
    background: var(--surface-tertiary);
}

.ds-filter-chip:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

.ds-filter-chip--active {
    background: var(--brand-accent);
    color: var(--surface-primary);
    border-color: var(--brand-accent-border);
}

/* Modal */
.ds-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    z-index: var(--z-modal-backdrop);
}

.ds-modal-card {
    background: var(--surface-primary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    max-width: 560px;
    width: 100%;
    z-index: var(--z-modal);
}

.ds-modal-card__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--border-subtle);
}

.ds-modal-card__body {
    padding: var(--space-5);
    color: var(--text-primary);
}

.ds-modal-card__actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    padding: var(--space-4) var(--space-5);
    border-top: 1px solid var(--border-subtle);
}

/* Avatar */
.ds-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Never let a flex parent (e.g. .ds-table--cards card rows) compress the
       avatar — a non-square box + border-radius:50% renders as an ellipse. */
    flex-shrink: 0;
    aspect-ratio: 1 / 1;
    border-radius: 50%;
    background: var(--surface-tertiary);
    color: var(--text-secondary);
    font-family: var(--font-body);
    font-weight: var(--weight-semibold);
    line-height: 1;
}

.ds-avatar--sm {
    width: var(--space-6);
    height: var(--space-6);
    font-size: var(--text-sm);
}

.ds-avatar--md {
    width: var(--space-7);
    height: var(--space-7);
    font-size: var(--text-base);
}

.ds-avatar--lg {
    width: var(--space-8);
    height: var(--space-8);
    font-size: var(--text-xl);
}

/* Tabs */
.ds-tabs {
    display: flex;
    gap: var(--space-2);
    border-bottom: 1px solid var(--border-subtle);
    /* 2026-05-17 — mobile cleanup: tab strips with 7-8 entries (ClientDetail,
       CaseDetail) overflow the viewport at narrow widths. Allow horizontal
       scroll instead of pushing the page wider than the viewport. Touch
       devices get native swipe-to-pan; -webkit-overflow-scrolling makes it
       feel momentum-y on iOS Safari. */
    overflow-x: auto;
    flex-wrap: nowrap;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}

.ds-tabs::-webkit-scrollbar {
    /* Hide the scrollbar on WebKit / Blink — the underline + active-tab
       state communicate enough that there's more to the right. */
    display: none;
}

.ds-tabs__tab {
    padding: var(--space-3) var(--space-4);
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    font-family: var(--font-body);
    font-size: var(--text-base);
    font-weight: var(--weight-semibold);
    color: var(--text-secondary);
    cursor: pointer;
    flex: 0 0 auto;
    white-space: nowrap;
    transition: color var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out);
}

.ds-tabs__tab:hover {
    color: var(--text-primary);
}

.ds-tabs__tab:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

.ds-tabs__tab--active {
    color: var(--brand-accent);
    border-bottom-color: var(--brand-accent);
}

/* Step indicator */
.ds-step-indicator {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    overflow-x: auto;
}

.ds-step {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    color: var(--text-muted);
    border-bottom: 2px solid transparent;
    line-height: var(--leading-tight);
}

.ds-step--current {
    color: var(--brand-accent);
    border-bottom-color: var(--brand-accent);
}

.ds-step--done {
    color: var(--success-fg);
}

/* Auth card (moved from per-app app.css, re-tokenised) */
.auth-page {
    min-height: calc(100vh - 3.5rem);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-7) var(--space-4);
    background: var(--surface-secondary);
}

.auth-card {
    max-width: 420px;
    width: 100%;
    padding: var(--space-6);
    background: var(--surface-primary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
}

.auth-card__hero {
    font-family: var(--font-heading);
    font-size: var(--text-3xl);
    font-weight: var(--weight-regular);
    line-height: var(--leading-tight);
    color: var(--text-primary);
    margin: 0 0 var(--space-4);
}

.auth-card__subheading {
    color: var(--text-secondary);
    margin: 0 0 var(--space-5);
    line-height: var(--leading-normal);
}

.auth-card__info {
    background: var(--info-bg);
    color: var(--info-fg);
    border: 1px solid var(--info-bg);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-4);
}

.auth-card__form > * + * {
    margin-top: var(--space-4);
}

.auth-card__actions {
    margin-top: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    align-items: stretch;
}

.auth-card__link {
    text-align: center;
    font-size: var(--text-sm);
}

/* Phase 45 Plan 05 — an ALTERNATIVE sign-in path rendered beside the primary form,
   not behind a disclosure and not above it. The rule this styling encodes is that the
   email path is never downgraded: the alternative sits below the form, separated by a
   neutral "or", rather than competing for the primary affordance. */
.auth-card__alt {
    margin-top: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    align-items: stretch;
}

.auth-card__alt-divider {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: 0;
    color: var(--text-secondary);
    font-size: var(--text-sm);
}

.auth-card__alt-divider::before,
.auth-card__alt-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--border-subtle);
}

/* Phase 45 Plan 06 — the in-app-webview hint. Deliberately quiet: it is information, not an
   affordance, and must never read as something to tap. No border, no background, no button
   styling — the whole point of D-45-05 is that an in-app browser is offered nothing it cannot
   honour. Token-only, no hex literals (Phase12.TokenLintTests). */
.auth-card__alt-hint {
    margin: 0;
    text-align: center;
    color: var(--text-secondary);
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
}

/* Unified /login — identifier-first entry point. One card resolves the
   entered email to a broker (password) or applicant (magic link) step. */
.auth-card--unified .auth-card__hero {
    /* Scale down so typical 3-4 word brand names stay on one line inside
       the auth-card's constrained width. Falls back gracefully on long
       names via balanced wrapping. */
    font-size: var(--text-2xl);
    text-wrap: balance;
    margin-bottom: var(--space-3);
}

.auth-card--unified .auth-card__subheading {
    margin-bottom: var(--space-5);
}

.auth-card__panel {
    min-height: 220px;
}

.auth-card__hero--small {
    font-size: var(--text-xl);
    margin-bottom: var(--space-2);
}

.auth-card__footnote {
    color: var(--text-muted);
    font-size: var(--text-sm);
    margin-top: var(--space-3);
    text-align: center;
}

/* ============ Onboarding chapter palette (Phase 13 v2 layout) ============
   Per-chapter accent rail colours on the unified onboarding panel.
   Muted, desaturated, professional. WCAG AA at --text-lg label size.
   Tenants override via app.css the same way they override --brand-accent. */

:root {
    --ob-chapter-1: #0071c1;   /* About you        — brand-accent blue */
    --ob-chapter-2: #0f766e;   /* Your home        — teal */
    --ob-chapter-3: #b45309;   /* Your partner     — warm amber */
    --ob-chapter-4: #4338ca;   /* Work & money     — indigo */
    --ob-chapter-5: #166534;   /* Property & loan  — forest */
    --ob-chapter-6: #475569;   /* Review & submit  — slate */
}

/* ============ .ds-input — global form-control fallback ============
   Applies to any raw <input class="ds-input">, <select class="ds-input">,
   <textarea class="ds-input"> that hasn't migrated to <DsField>/<DsSelect>/<DsTextarea>.
   Matches the .ds-field__input visual contract byte-for-byte so mixed-markup pages
   still look uniform. Safe on scoped pages — scoped rules always win. */

.ds-input {
    font-family: var(--font-body, 'Plus Jakarta Sans', system-ui, sans-serif);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    color: var(--text-primary);
    background: var(--surface-primary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
    min-height: 48px;
    width: 100%;
    max-width: 480px;
    box-sizing: border-box;
    transition: border-color var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-fast) var(--ease-out);
}

.ds-input::placeholder {
    color: var(--text-muted);
}

.ds-input:hover:not(:disabled) {
    border-color: var(--border-strong);
}

.ds-input:focus-visible,
.ds-input:focus {
    outline: none;
    border-color: var(--brand-accent, #0071c1);
    box-shadow: var(--focus-ring);
}

.ds-input:disabled {
    background: var(--surface-tertiary);
    color: var(--text-muted);
    cursor: not-allowed;
}

/* Textarea variant — vertical resize, taller min-height */
textarea.ds-input {
    resize: vertical;
    min-height: 96px;
    line-height: var(--leading-normal);
}

/* Select variant — strip native chrome, paint branded chevron */
select.ds-input {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    cursor: pointer;
    padding-right: calc(var(--space-4) + 20px);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'><path d='M3 4.5l3 3 3-3' stroke='%230071c1' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat: no-repeat;
    background-position: right var(--space-4) center;
    background-size: 12px 12px;
}

select.ds-input::-ms-expand {
    display: none;
}

/* Mobile — 44px touch target, full-bleed width */
@media (max-width: 640px) {
    .ds-input {
        min-height: 44px;
        padding: var(--space-3);
        max-width: 100%;
    }
    select.ds-input {
        padding-right: calc(var(--space-3) + 20px);
    }
    textarea.ds-input {
        min-height: 88px;
    }
}

/* ===========================================================================
   DsAddress inside the AIP form (.aip-address-field)
   ---------------------------------------------------------------------------
   DsAddress is sized for the friendly onboarding wizard (large labels, ~40px
   inputs, generous spacing). Inside the dense PDF-style AIP form — the broker
   Profile tab (.aip-form-context) and the case/client AIP tabs (.aip-form) —
   those controls dwarf the surrounding fields. These rules compact the address
   block to match the AIP field metrics (0.8rem, 26px, 3px/6px padding). Scoped
   to .aip-address-field, which exists ONLY in the AIP form, so the onboarding
   wizard is unaffected. Loaded globally in both apps, so it applies wherever
   the AIP form renders regardless of CSS-isolation scope.
   ========================================================================= */
.aip-address-field .ds-address {
    gap: 4px;
}

.aip-address-field .ds-field {
    gap: 2px;
}

.aip-address-field .ds-field__label {
    font-size: 0.8rem;
    font-weight: var(--weight-semibold);
    color: var(--brand-primary);
    line-height: 1.2;
}

.aip-address-field .ds-field__input {
    font-size: 0.8rem;
    line-height: normal;
    padding: 3px 6px;
    min-height: 26px;
    height: 26px;
    border-radius: 4px;
}

.aip-address-field .ds-field__hint {
    font-size: 0.72rem;
    line-height: 1.2;
}

.aip-address-field .ds-field__error {
    font-size: 0.72rem;
    line-height: 1.2;
}

.aip-address-field .ds-address__manual-toggle {
    font-size: 0.75rem;
}

/* Force the Google autocomplete to its light theme on ALL DsAddress instances
   (onboarding + AIP). The component ships `:host { color-scheme: light dark }`
   in its closed shadow DOM, so it follows the OS preference and renders a black
   input + black suggestions dropdown on dark-mode machines. This app is
   light-only. An *inherited* color-scheme (from :root) does NOT override the
   component's own :host declaration — but a *direct* rule on the host element
   does (verified against the live component: computed color-scheme resolves to
   `light`, and the dropdown, which inherits from the element, turns white). No
   !important needed: outer-page rules on the host beat the shadow :host rule. */
.ds-address__autocomplete-host > gmp-place-autocomplete {
    color-scheme: light;
}

/* Compact the Google search box (gmp-place-autocomplete) to match the AIP
   field metrics (26px tall, like .field-input). Verified empirically against
   the live component: its shadow root is CLOSED (no ::part access) and its
   default height is 50px driven by internal Material padding — font-size has
   NO effect on height; an explicit `height` on the host element is the only
   lever that resizes it. Setting height + box-sizing: border-box gives a clean
   26px box with the search icon centred and nothing clipped. We deliberately
   do NOT set overflow:hidden — the suggestions popup renders below the box and
   must not be clipped. Border uses the same (Admin-undefined → currentColor)
   var as the neighbouring .field-input so the box matches its siblings. */
.aip-address-field .ds-address__autocomplete-host > gmp-place-autocomplete {
    height: 26px;
    box-sizing: border-box;
    width: 100%;
    font-size: 0.8rem;
    background-color: #ffffff;
    border: 1px solid var(--form-border);
    border-radius: 4px;
}

/* ===== .ds-table--cards — additive responsive collapse (Phase 25 MOBR-02) =====
   Promotes the proven RecentSessionsPanel table->card pattern (D-03) into ONE
   shared, opt-in modifier (D-04 additive-only). Apply `.ds-table--cards` to a
   table and give every <td> a `data-label="Column"` attribute; below the
   canonical mobile breakpoint each row renders as a stacked label/value card.

   Canonical breakpoint = 640px == --bp-sm (design-system.css:96). CSS custom
   properties are ILLEGAL inside @media conditions (media features cannot read
   vars), so the literal 640px is used here and --bp-sm is the documented source.

   IMPORTANT: this block is purely additive. It does NOT touch the existing
   `.ds-table` rules (above) so desktop (>640px) rendering is byte-for-byte
   unchanged. The Client WASM offline-first AipForm uses `full-width-table`,
   not `.ds-table--cards`, so it is unaffected. */
@media (max-width: 640px) {
    .ds-table--cards,
    .ds-table--cards tbody,
    .ds-table--cards tr,
    .ds-table--cards td { display: block; width: 100%; }

    .ds-table--cards thead { position: absolute; left: -9999px; top: -9999px; }

    .ds-table--cards tr {
        margin-bottom: var(--space-3);
        border: 1px solid var(--border-subtle);
        border-radius: var(--radius-md);
        padding: var(--space-3);
        background: var(--surface-primary);
    }

    .ds-table--cards td {
        display: flex;
        justify-content: space-between;
        /* flex-start (not center) keeps the data-label caption aligned to the
           first line of the value, so the label column stays consistent even
           when a long value (e.g. an email) wraps to two lines. */
        align-items: flex-start;
        gap: var(--space-4);
        padding: var(--space-2) 0;
        text-align: right;
        /* Long unbroken values (emails, URLs) must wrap instead of overflowing
           and shoving the label out of alignment. */
        overflow-wrap: anywhere;
        border-bottom: none;
    }

    .ds-table--cards td::before {
        content: attr(data-label);
        font-weight: var(--weight-semibold);
        color: var(--brand-primary);
        text-align: left;
        flex: 0 0 auto;
    }

    /* Quick-task 260809-c7t — the kebab trigger ships at 2.25rem (36px), below the
       44px tap-target floor. Raised here, inside the same 640px block the card
       collapse already uses, because that is the width at which the control is
       actually being tapped rather than clicked. The base rule keeps 2.25rem so
       desktop row density is unchanged. */
    .row-actions__trigger {
        min-width: 2.75rem;
        min-height: 2.75rem;
    }
}

/* ===== .ds-icon-btn — 44x44 tap-target utility (Phase 25 MOBR-03) =====
   Icon-only / close / kebab action controls must meet a 44x44px minimum tap
   target at ALL widths per WCAG 2.2 target-size (stricter than 2.5.8's 24px),
   so this rule is intentionally NOT gated by a media query. Token-only, no
   raw hex. (.ds-input already carries the 44px floor at <=640px.) */
.ds-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--text-secondary);
    border-radius: var(--radius-sm);
}

.ds-icon-btn:hover {
    background: var(--surface-tertiary);
}

.ds-icon-btn:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

