/* Design tokens live in _content/Clyffe.DesignSystem/clyffe-tokens.css (single
   source of truth). Only app-specific layout variables belong here. */
:root {
    /* Bottom command bar height (used as scroll padding) */
    --clyffe-command-bar-height: 72px;
}

html,
body {
    margin: 0;
    font-family: var(--font-body);
    color: var(--clyffe-ink);
    background: var(--clyffe-white);
}

/* Suppress focus outline when an element is focused programmatically (e.g. Blazor's
   FocusOnNavigate puts focus on the page h1 for screen readers). Keep it visible
   for keyboard navigation so a11y remains intact. */
:focus:not(:focus-visible) {
    outline: none;
}

.mud-main-content {
    min-height: calc(100vh - 56px);
    padding-top: var(--appbar-height, 48px) !important;
}

/* Cards are flat per the design system: hairline border + spacing, never shadow.
   Shadows remain on genuinely floating layers (popover, dialog, snackbar). */
.mud-card {
    border: var(--border-card);
    border-radius: var(--radius-xs);
    box-shadow: none;
}

.clyffe-appbar {
    border-bottom: none;
    box-shadow: none;
    color: var(--clyffe-ink);
    padding: 0 12px;
    height: var(--appbar-height, 48px);
    min-height: var(--appbar-height, 48px);
}

.clyffe-drawer {
    border-right: none;
}

.clyffe-drawer .mud-drawer-content {
    display: flex;
    flex-direction: column;
    height: 100%;
}

/* Drawer width tokens — used by the bottom bar / chat overlay so they
   sit beside the drawer rather than under it. Values match MudBlazor's
   default mini (56px) and open (240px) drawer widths. */
.clyffe-drawer-mini {
    --clyffe-drawer-width-left: 56px;
}

.clyffe-drawer-open {
    --clyffe-drawer-width-left: 240px;
}

@media (max-width: 959px) {
    .clyffe-drawer-mini,
    .clyffe-drawer-open {
        --clyffe-drawer-width-left: 0px;
    }
}

.clyffe-drawer-header {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    text-align: left;
    height: 48px;
    padding: 0 16px;
    border: none;
    background: transparent;
    box-sizing: border-box;
    cursor: pointer;
    user-select: none;
    transition: padding 0.2s ease;
    width: 100%;
    color: inherit;
    font: inherit;
}

.clyffe-drawer-header:hover .clyffe-drawer-brand,
.clyffe-drawer-header:hover .clyffe-drawer-icon {
    opacity: 0.78;
    transition: opacity 0.15s ease;
}

.clyffe-drawer-brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}

.clyffe-drawer-brand-icon {
    width: 26px;
    height: 26px;
    object-fit: contain;
    display: block;
    flex-shrink: 0;
}

.clyffe-drawer-brand-text {
    font-family: var(--font-heading);
    font-weight: 500;
    font-size: 22px;
    color: var(--parchment);
    letter-spacing: 0.01em;
    line-height: 1;
}

.clyffe-drawer-icon {
    width: 26px;
    height: 26px;
    object-fit: contain;
    display: block;
    margin: 0 auto;
}


/* Mini (collapsed) drawer adjustments */
.mud-drawer--closed .clyffe-drawer-header {
    padding: 0;
    justify-content: center;
}

.mud-drawer--closed .clyffe-nav-menu {
    padding: 4px 4px 12px;
}

.clyffe-nav-shell {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.clyffe-nav-menu-top {
    flex: 1 1 auto;
    overflow-y: auto;
    min-height: 0;
}

.clyffe-nav-footer {
    flex: 0 0 auto;
    padding-bottom: 12px;
}

.clyffe-nav-footer .clyffe-nav-menu {
    padding-bottom: 0;
    padding-top: 0;
}

.clyffe-nav-spacer {
    height: 18px;
    pointer-events: none;
}

.clyffe-nav-menu {
    padding: 4px 10px 12px;
}

/* Per-link wrapper that carries the area-active class (issue #143). A plain block box: all
   MudBlazor .mud-nav-link styling is descendant-based (its only direct-child selectors target
   .mud-nav-group), so the wrapper doesn't disturb layout and needs no display: contents —
   which some assistive tech historically mishandled. */

.clyffe-nav-menu .mud-nav-link {
    border-radius: var(--radius-sm);
    margin: 2px 0;
    color: var(--cream-90);
}

.clyffe-nav-menu .mud-nav-link .mud-nav-link-icon {
    color: var(--cream-50);
}

.clyffe-nav-menu .mud-nav-link:hover {
    background: var(--white-08);
}

.clyffe-nav-menu .mud-divider {
    display: none;
}

/* Active nav item: subtle cream highlight on navy, not a bold block.
   Selector must out-specify MudBlazor's own `.mud-nav-link.active:not(
   .mud-nav-link-disabled)` (which forces the primary/navy colour — invisible
   on a navy drawer), so we qualify with the menu class and the same :not().
   The sidebar's own highlight is area-driven (issue #143): Blazor's NavLink
   manages the built-in `active` class from the href and drops any injected
   class, so it can't light up cross-prefix configuration pages. Instead each
   link is wrapped in `.clyffe-nav-item`, and the area map adds `.clyffe-nav-active`
   to that wrapper; we style the anchor within it identically to `active`. */
.clyffe-nav-menu .mud-nav-link.active,
.clyffe-nav-menu .clyffe-nav-active .mud-nav-link,
.clyffe-nav-menu .mud-nav-link.active:not(.mud-nav-link-disabled),
.clyffe-nav-menu .clyffe-nav-active .mud-nav-link:not(.mud-nav-link-disabled) {
    background-color: rgba(253, 240, 213, 0.12);
    color: var(--parchment);
    border-radius: var(--radius-sm);
    font-weight: 600;
}

.clyffe-nav-menu .mud-nav-link.active:not(.mud-nav-link-disabled) .mud-nav-link-icon,
.clyffe-nav-menu .clyffe-nav-active .mud-nav-link:not(.mud-nav-link-disabled) .mud-nav-link-icon,
.clyffe-nav-menu .mud-nav-link.active:not(.mud-nav-link-disabled) .mud-nav-link-text,
.clyffe-nav-menu .clyffe-nav-active .mud-nav-link:not(.mud-nav-link-disabled) .mud-nav-link-text {
    color: var(--parchment);
}

.clyffe-nav-account {
    padding: 4px 10px 0;
}

.clyffe-nav-account-trigger {
    display: flex;
    align-items: center;
    gap: 16px;
    width: 100%;
    padding: 8px 16px;
    border: none;
    background: transparent;
    border-radius: var(--radius-sm);
    color: var(--cream-90);
    font-family: var(--font-body);
    font-size: 14px;
    cursor: pointer;
    text-align: left;
    margin: 2px 0;
    transition: background 0.12s ease;
}

.clyffe-nav-account-trigger:hover {
    background: var(--white-08);
}

.clyffe-nav-account-icon {
    color: var(--cream-50);
    flex-shrink: 0;
    width: 24px;
    height: 24px;
}

.mud-drawer--closed .clyffe-nav-account-label {
    display: none;
}

.mud-drawer--closed .clyffe-nav-account {
    padding: 0 4px;
    display: flex;
    justify-content: center;
}

.mud-drawer--closed .clyffe-nav-account-trigger {
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
}

.clyffe-nav-account-header {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 16px 12px;
}

.clyffe-nav-account-header-name {
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 600;
    color: var(--text-strong);
}

.clyffe-nav-account-header-email {
    font-family: var(--font-body);
    font-size: 12px;
    color: var(--text-muted);
}

/* The live line on a connector card, which stands in for the "Updated ..." caption while a scan is
   running. Sized to match that caption so the card does not shift as it swaps between them. */
.clyffe-connector-activity {
    min-height: 24px;
}

/* Sign-out is a form post, not a link, so the session cannot be ended by a cross-site GET
   (issue #303). MudMenuItem has no submit button type, so these rules dress a real submit button
   to sit flush with the menu items around it — same padding, type, and hover as MudBlazor gives
   its own, without reaching into .mud-* classes to get there. */
.clyffe-nav-account-signout-form {
    margin: 0;
}

.clyffe-nav-account-signout {
    display: block;
    width: 100%;
    padding: 10px 16px;
    border: none;
    background: none;
    text-align: left;
    cursor: pointer;
    font-family: var(--font-body);
    font-size: 14px;
    color: var(--text-strong);
}

.clyffe-nav-account-signout:hover,
.clyffe-nav-account-signout:focus-visible {
    background: var(--surface-hover, rgba(0, 0, 0, 0.04));
}

.clyffe-shell {
    padding: 24px 28px calc(var(--clyffe-command-bar-height) + 32px);
}

.clyffe-page-content {
    min-width: 0;
}

/* Cards are flat — structure from the hairline border and padding, not shadow. */
.clyffe-page-hero {
    border: var(--border-card);
    border-radius: var(--radius-xs);
    background: var(--clyffe-white);
    box-shadow: none;
}

/* Stat cards sit in a grid row and must read as one band, so every card fills the row's
   height rather than shrinking to its own content — otherwise a card that carries a
   caption leaves the one beside it floating short. */
.clyffe-stat {
    border: var(--border-card);
    border-radius: var(--radius-xs);
    background: var(--clyffe-white);
    box-shadow: none;
    height: 100%;
}

/* The label line above the figure. Fixed height so a label carrying a chip ("From an
   invoice") and a bare one ("People") still drop their figures onto the same line. */
.clyffe-stat-label {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    min-height: var(--stat-label-height);
}

/* The chip rides the label line rather than pushing it taller. */
.clyffe-stat-label .mud-chip {
    margin: 0;
}

.clyffe-secondary-tabs {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.clyffe-secondary-tab {
    padding: 10px 14px;
    font-size: 13px;
    font-weight: 600;
    color: var(--clyffe-muted);
    border: 1px solid var(--clyffe-border);
    background: rgba(255, 255, 255, 0.8);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: var(--transition-micro);
    font-family: inherit;
}

.clyffe-secondary-tab:hover {
    border-color: var(--clyffe-teal);
    color: var(--clyffe-ink);
}

.clyffe-secondary-tab-active {
    color: var(--clyffe-white);
    background: var(--clyffe-teal);
    border-color: var(--clyffe-teal);
}

/* Pending-invitations disclosure above the Team member list (issue #143 / decision 8) — a
   calm link, not a second table. */
.clyffe-pending-invites-link {
    cursor: pointer;
    display: inline-flex;
    padding: 4px 8px;
}

.loading-overlay {
    position: fixed;
    inset: 0;
    background: rgba(255, 255, 255, 0.9);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 9999;
}

@media (max-width: 768px) {
    .clyffe-notice-bar {
        display: none;
    }

    .clyffe-layout-with-notice .mud-appbar {
        top: 0;
    }

    .clyffe-layout-with-notice .mud-drawer {
        top: 0 !important;
        height: 100vh !important;
    }

    .clyffe-layout-with-notice .mud-main-content {
        padding-top: 0;
    }

    .clyffe-shell {
        padding: 14px 14px calc(var(--clyffe-command-bar-height) + 24px);
    }
}

/* ── Bottom command bar (Sotto-style) ── */
.clyffe-command-bar {
    position: fixed;
    bottom: 0;
    left: var(--clyffe-drawer-width-left, 0px);
    right: 0;
    z-index: 1300;
    padding: 10px 24px 14px;
    background: transparent;
    pointer-events: none;
    transition: left 0.25s ease;
}

.clyffe-command-bar-inner {
    pointer-events: auto;
}

.clyffe-command-bar-inner {
    max-width: 880px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px 6px 18px;
    background: var(--clyffe-white);
    border: 1px solid var(--clyffe-border);
    border-radius: 999px;
    box-shadow: var(--clyffe-shadow-sm);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    cursor: text;
}

.clyffe-command-bar-inner:hover,
.clyffe-command-bar-inner:focus-within {
    border-color: var(--clyffe-navy);
    box-shadow: var(--clyffe-shadow-md);
}

.clyffe-command-bar-icon {
    color: var(--clyffe-navy);
    flex-shrink: 0;
}

.clyffe-command-bar-input {
    flex: 1;
    border: none;
    outline: none;
    background: transparent;
    font-family: var(--font-body);
    font-size: 14px;
    color: var(--clyffe-ink);
    padding: 8px 0;
    min-width: 0;
}

.clyffe-command-bar-input::placeholder {
    color: var(--clyffe-muted);
    opacity: 0.85;
}

.clyffe-command-bar-input:disabled {
    cursor: text;
    color: var(--clyffe-muted);
}

.clyffe-command-bar-hint {
    font-family: var(--font-mono);
    font-size: var(--text-mono-size);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    flex-shrink: 0;
    padding: 0 6px;
}

.clyffe-command-bar-send {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
    border: none;
    background: var(--clyffe-navy);
    color: var(--clyffe-white);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
    opacity: 0.45;
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.clyffe-command-bar-send:hover {
    opacity: 0.7;
}

/* ── Chat overlay (slide-up from bottom) ── */
.clyffe-chat-overlay {
    position: fixed;
    left: var(--clyffe-drawer-width-left, 0px);
    right: 0;
    bottom: 0;
    height: min(72vh, 640px);
    z-index: 1400;
    background: var(--clyffe-white);
    border-top: 1px solid var(--clyffe-border);
    box-shadow: var(--shadow-overlay);
    border-top-left-radius: var(--radius-lg);
    border-top-right-radius: var(--radius-lg);
    transform: translateY(110%);
    transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1), visibility 0s linear 280ms;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    visibility: hidden;
    pointer-events: none;
}

.clyffe-chat-overlay.open {
    transform: translateY(0);
    visibility: visible;
    pointer-events: auto;
    transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1), visibility 0s linear 0s;
}

.clyffe-chat-overlay-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--clyffe-border);
    background: var(--navy-03);
}

.clyffe-chat-overlay-title {
    font-family: var(--font-heading);
    font-size: 18px;
    font-weight: 500;
    color: var(--clyffe-navy);
    letter-spacing: 0.005em;
}

.clyffe-chat-overlay-context {
    font-size: 12px;
    color: var(--clyffe-muted);
    margin-left: auto;
    margin-right: 8px;
}

.clyffe-chat-overlay-close {
    width: 32px;
    height: 32px;
    border: none;
    background: transparent;
    color: var(--clyffe-muted);
    border-radius: var(--radius-sm);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s ease, color 0.15s ease;
}

.clyffe-chat-overlay-close:hover {
    background: var(--navy-05);
    color: var(--clyffe-ink);
}

.clyffe-chat-overlay-body {
    flex: 1;
    overflow-y: auto;
    padding: 20px 24px 12px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.clyffe-chat-overlay-suggestions-label {
    font-family: var(--font-mono);
    font-size: var(--text-mono-size);
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--text-label);
    font-weight: var(--weight-mono);
}

.clyffe-chat-overlay-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.clyffe-chat-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: var(--clyffe-white);
    border: 1px solid var(--clyffe-border);
    border-radius: 999px;
    font-family: var(--font-body);
    font-size: 13px;
    color: var(--clyffe-ink);
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.clyffe-chat-chip:hover {
    border-color: var(--clyffe-navy);
    background: var(--navy-05);
}

.clyffe-chat-chip-icon {
    color: var(--clyffe-cove);
    font-size: 16px;
}

.clyffe-chat-overlay-empty {
    color: var(--clyffe-muted);
    font-size: 13px;
    line-height: 1.55;
    padding: 20px 0;
    border-top: 1px dashed var(--clyffe-border);
    margin-top: 4px;
}

.clyffe-chat-overlay-footer {
    border-top: 1px solid var(--clyffe-border);
    padding: 12px 20px 16px;
    background: var(--parchment-30);
}

.clyffe-chat-overlay-coming-soon {
    font-size: 12px;
    color: var(--clyffe-muted);
    margin-top: 6px;
    text-align: center;
}

/* ── Landing (split hero) ──
   The first screen anyone sees, so it carries the brand rather than a centred block of text on
   cream: a full-bleed navy panel (with the logo's concentric arcs at a few percent white) against
   a warm content column. Nothing here is a MudBlazor class — the shell is ours end to end. */
.clyffe-landing-shell {
    min-height: 100vh;
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    background: var(--surface-warm);
}

.clyffe-landing-brand {
    position: relative;
    overflow: hidden;
    background: var(--navy);
    color: var(--cream-90);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: var(--space-6);
    padding: var(--space-6) var(--space-6) var(--space-5);
}

/* Two thin arcs echoing the logo's intertwined geometry. Decorative only, hence no markup. */
.clyffe-landing-brand::before,
.clyffe-landing-brand::after {
    content: "";
    position: absolute;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.05);
    pointer-events: none;
}

.clyffe-landing-brand::before {
    top: -25%;
    right: -20%;
    width: 70%;
    padding-bottom: 70%;
}

.clyffe-landing-brand::after {
    bottom: -30%;
    left: -12%;
    width: 55%;
    padding-bottom: 55%;
    border-color: rgba(255, 255, 255, 0.04);
}

.clyffe-landing-brand > * {
    position: relative;
}

.clyffe-landing-brandmark {
    display: flex;
    align-items: center;
    gap: 12px;
}

.clyffe-landing-brandmark-icon {
    width: 34px;
    height: 34px;
}

.clyffe-landing-brandmark-text {
    font-family: var(--font-display);
    font-size: 24px;
    font-weight: var(--weight-display-medium);
    color: var(--parchment);
}

.clyffe-landing-brandbody {
    max-width: 420px;
}

.clyffe-landing-brandline {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--text-display-size);
    font-weight: var(--weight-display-light);
    line-height: 1.2;
    letter-spacing: var(--tracking-display);
    color: var(--parchment);
}

.clyffe-landing-brandsub {
    margin: var(--space-3) 0 0;
    font-size: var(--text-body-size);
    font-weight: var(--weight-body);
    line-height: var(--leading-body);
    color: var(--cream-50);
}

.clyffe-landing-brandfoot {
    margin: 0;
    font-family: var(--font-mono);
    font-size: var(--text-mono-size);
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--cream-30);
}

.clyffe-landing-content {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-7) var(--space-6);
}

.clyffe-landing-panel {
    width: 100%;
    max-width: 520px;
    animation: clyffe-landing-enter var(--duration-panel) var(--ease-out) both;
}

@keyframes clyffe-landing-enter {
    from {
        opacity: 0;
        transform: translateY(8px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

.clyffe-landing-heading {
    margin: 0;
    font-family: var(--font-display);
    font-size: 34px;
    font-weight: var(--weight-display);
    line-height: var(--leading-heading);
    letter-spacing: var(--tracking-display);
    color: var(--text-heading);
}

/* Blazor's FocusOnNavigate (Routes.razor) focuses the page h1 for screen-reader announcement, and
   the autofocus it sets counts as focus-visible in Chrome — so the global :focus:not(:focus-visible)
   suppression above misses it and the heading loads inside a ring. Same treatment as .hc-title. */
.clyffe-landing-heading:focus,
.clyffe-landing-heading:focus-visible {
    outline: none;
    box-shadow: none;
}

.clyffe-landing-lede {
    margin: var(--space-3) 0 0;
    font-size: var(--text-body-size);
    font-weight: var(--weight-body);
    line-height: var(--leading-body);
    color: var(--text-body);
}

.clyffe-landing-highlights {
    list-style: none;
    margin: var(--space-5) 0 0;
    padding: var(--space-4) 0 0;
    border-top: var(--border-card);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.clyffe-landing-highlight {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.clyffe-landing-highlight-icon {
    color: var(--cove);
    flex: 0 0 auto;
    margin-top: 2px;
}

.clyffe-landing-highlight-copy {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.clyffe-landing-highlight-title {
    font-size: 14px;
    font-weight: var(--weight-body-semibold);
    letter-spacing: var(--tracking-ui);
    color: var(--text-strong);
}

.clyffe-landing-highlight-detail {
    font-size: 13px;
    font-weight: var(--weight-body);
    line-height: var(--leading-ui);
    color: var(--text-body);
}

.clyffe-landing-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: var(--space-5);
}

.clyffe-landing-note {
    margin: var(--space-3) 0 0;
    font-size: var(--text-caption-size);
    color: var(--text-muted);
}

/* Stacked: the brand panel becomes a banner above the content rather than a half-height column. */
@media (max-width: 959px) {
    .clyffe-landing-shell {
        grid-template-columns: 1fr;
    }

    .clyffe-landing-brand {
        gap: var(--space-4);
        padding: var(--space-5) var(--space-4);
    }

    .clyffe-landing-brandline {
        font-size: 28px;
    }

    .clyffe-landing-brandfoot {
        display: none;
    }

    .clyffe-landing-content {
        padding: var(--space-5) var(--space-4) var(--space-6);
    }

    .clyffe-landing-heading {
        font-size: 28px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .clyffe-landing-panel {
        animation: none;
    }
}

/* ── Onboarding shell (full-screen wizard) ── */
.clyffe-onboarding-shell {
    min-height: 100vh;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    background: var(--surface-warm);
    padding: 64px 24px 64px;
}

/* Setup conversation: the screen fits the window, so the transcript is the only thing that
   scrolls. Letting the card grow instead left the customer scrolling the chat and then the page
   again to reach the button at the end of setup. */
.clyffe-setup-screen {
    display: flex;
    flex-direction: column;
    /* 128px of shell padding (64 top + 64 bottom) plus the container's 48px (py-6). */
    max-height: calc(100vh - 176px);
    min-height: 0;
}

.clyffe-setup-grid {
    flex: 1 1 auto;
    min-height: 0;
}

.clyffe-setup-grid > .mud-grid-item {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* A constant-size panel: it is the same height on the first question as on the last, so the
   screen never grows or jumps as the conversation fills it. The height is set here rather than
   inherited, because the MudBlazor wrappers above resolve to height:auto. */
.clyffe-setup-conversation {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
    height: calc(100vh - 176px);
}

.clyffe-setup-transcript {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* Answers stay put beneath the transcript, scrolling inside their own box when long. */
.clyffe-setup-answers {
    flex: 0 0 auto;
    max-height: 45vh;
    overflow-y: auto;
}

/* Setup finished: the chat is gone and the summary is the whole panel, so it gets the height
   rather than sharing it — one scrollbar on the screen, not two. */
.clyffe-setup-answers--only {
    flex: 1 1 auto;
    max-height: none;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* Targets a class we own: MudStack renders utility classes (d-flex flex-column gap-3), so there
   is no MudBlazor class here to hook, and a selector guessing at one silently matches nothing. */
.clyffe-setup-answers--only > .clyffe-directive-renderer {
    flex: 1 1 auto;
    min-height: 0;
}

/* The answers take the space and the button sits on the bottom edge, where a closing action
   belongs — rather than floating halfway up a mostly empty panel. */
.clyffe-setup-summary-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

.clyffe-setup-summary-finish {
    flex: 0 0 auto;
    margin-top: auto;
}

/* On a phone the columns stack, and a window-height card would squash the conversation into a
   sliver — there, the page scrolling normally is the right behaviour. */
@media (max-width: 959px) {
    .clyffe-setup-screen,
    .clyffe-setup-conversation {
        height: auto;
        max-height: none;
    }

    .clyffe-setup-transcript,
    .clyffe-setup-answers,
    .clyffe-setup-summary-list {
        max-height: none;
        overflow-y: visible;
    }

    .clyffe-setup-summary-finish {
        margin-top: 0;
    }
}

/* ── Setup: header strip ──
   Navy, echoing the sign-in hero, so the screen has one piece of structure carrying the brand
   instead of three white boxes floating on cream. */
.clyffe-setup-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 14px var(--space-4);
    border-radius: var(--radius-lg);
    background: var(--navy);
    color: var(--parchment);
}

.clyffe-setup-header-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.clyffe-setup-header-icon {
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
}

.clyffe-setup-header-tick {
    color: var(--parchment);
    flex: 0 0 auto;
}

.clyffe-setup-header-stage {
    font-size: 14px;
    font-weight: var(--weight-body-semibold);
    letter-spacing: var(--tracking-ui);
    color: var(--parchment);
}

.clyffe-setup-header-progress {
    flex: 1 1 auto;
    max-width: 480px;
    margin-left: auto;
    height: 4px;
    border-radius: var(--radius-pill);
    background: var(--white-25);
    overflow: hidden;
}

.clyffe-setup-header-progress-fill {
    height: 100%;
    border-radius: var(--radius-pill);
    background: var(--parchment);
    transition: width var(--duration-panel) var(--ease-out);
}

/* Queued behind a worker the scan reports nothing for a while, so the bar paces rather than
   sitting at zero — a still bar reads as stuck. */
.clyffe-setup-header-progress-fill--waiting {
    width: 30%;
    animation: clyffe-setup-waiting 1.8s var(--ease-in-out) infinite;
}

@keyframes clyffe-setup-waiting {
    0% {
        transform: translateX(-100%);
    }

    100% {
        transform: translateX(333%);
    }
}

.clyffe-setup-header-percent {
    font-family: var(--font-mono);
    font-size: var(--text-mono-size);
    letter-spacing: var(--tracking-mono);
    color: var(--cream-50);
    flex: 0 0 auto;
}

/* ── Setup: progress rail ──
   A connected rail rather than a bare list, so it reads as a journey with a position in it.
   The line runs the full column and each dot masks it with the card's own background. */
/* Full height, so the two columns square off instead of a stubby card sitting beside a
   window-tall panel. */
.clyffe-setup-rail {
    flex: 1 1 auto;
}

.clyffe-setup-rail-title {
    margin: 0 0 var(--space-4);
    font-family: var(--font-mono);
    font-size: var(--text-mono-size);
    font-weight: var(--weight-mono);
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--cove);
}

.clyffe-setup-steps {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.clyffe-setup-steps::before {
    content: "";
    position: absolute;
    /* Dead centre of a 20px dot, so the line runs through it rather than beside it. */
    left: 9.5px;
    top: 10px;
    bottom: 10px;
    width: 1px;
    background: var(--navy-10);
}

.clyffe-setup-step {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--navy-15);
}

.clyffe-setup-step-dot {
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--surface-card);
}

.clyffe-setup-step-label {
    font-size: 14px;
    font-weight: var(--weight-body);
    line-height: var(--leading-ui);
    color: var(--text-body);
}

.clyffe-setup-step--done {
    color: var(--cove);
}

.clyffe-setup-step--done .clyffe-setup-step-label {
    font-weight: var(--weight-body-medium);
    color: var(--text-strong);
}

/* ── Setup: transcript ──
   The panel is a fixed height, so a one-line opening question used to leave a window of empty
   card between it and the answer box. Growing the conversation up off the answer box is both the
   chat convention and the only way that first screen doesn't read as broken. */
.clyffe-setup-transcript > :first-child {
    margin-top: auto;
}

.clyffe-bubble-row {
    display: flex;
}

.clyffe-bubble-row--clyffe {
    align-self: flex-start;
    max-width: 85%;
}

.clyffe-bubble-row--you {
    align-self: flex-end;
    max-width: 70%;
}

/* Clyffe speaks on parchment, you answer on navy — the two brand surfaces, so the transcript
   reads at a glance without either side needing a label. */
.clyffe-bubble {
    border-radius: var(--radius-lg);
}

.clyffe-bubble--clyffe {
    background: var(--parchment);
    color: var(--ink);
    border-bottom-left-radius: var(--radius-xs);
}

.clyffe-bubble--you {
    background: var(--navy);
    color: var(--parchment);
    border-bottom-right-radius: var(--radius-xs);
}

/* An answer button is the size of its label, not the width of the panel. */
.clyffe-directive-action {
    align-self: flex-start;
}

@media (max-width: 599px) {
    .clyffe-setup-header {
        flex-wrap: wrap;
        gap: var(--space-2);
    }

    .clyffe-setup-header-progress {
        margin-left: 0;
        max-width: none;
    }
}

.clyffe-onboarding-card {
    width: 100%;
    max-width: 580px;
    background: var(--clyffe-white);
    border: var(--border-card);
    border-radius: var(--radius-lg);
    box-shadow: none;
    padding: var(--pad-card-lg) 44px 36px;
}

.clyffe-onboarding-card-body {
    margin-top: 4px;
}

.clyffe-step-title {
    font-family: var(--font-heading);
    font-size: var(--text-h1-size);
    font-weight: var(--weight-display);
    color: var(--clyffe-navy);
    line-height: 1.2;
    margin: 0 0 8px;
    letter-spacing: 0.005em;
}

.clyffe-step-description {
    font-family: var(--font-body);
    font-size: 14px;
    color: var(--clyffe-muted);
    line-height: 1.55;
    margin: 0 0 12px;
}

.clyffe-step-subheading {
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 600;
    color: var(--clyffe-ink);
    margin: 0 0 6px;
}

.clyffe-step-title-suffix {
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 500;
    color: var(--clyffe-muted);
    margin-left: 8px;
    letter-spacing: 0.005em;
}

.clyffe-onboarding-brand {
    text-align: center;
    margin-bottom: 28px;
}

.clyffe-onboarding-brand-mark {
    display: inline-flex;
    align-items: center;
    gap: 14px;
}

.clyffe-onboarding-brand-icon {
    width: 44px;
    height: 44px;
    object-fit: contain;
}

.clyffe-onboarding-brand-text {
    font-family: var(--font-heading);
    font-weight: 500;
    font-size: 36px;
    color: var(--clyffe-navy);
    letter-spacing: 0.005em;
    line-height: 1;
}

/* ── Continue setup card (returning user, dashboard) ── */
.clyffe-continue-setup {
    display: flex;
    align-items: center;
    gap: 24px;
    padding: 22px var(--pad-card);
    background: var(--surface-inverse);
    color: var(--clyffe-white);
    border-radius: var(--radius-lg);
    box-shadow: none;
    flex-wrap: wrap;
}

.clyffe-continue-setup-text {
    flex: 1;
    min-width: 240px;
}

.clyffe-continue-setup-eyebrow {
    font-family: var(--font-mono);
    font-size: var(--text-mono-size);
    text-transform: uppercase;
    letter-spacing: 0.18em;
    opacity: 0.78;
    margin-bottom: 6px;
}

.clyffe-continue-setup-title {
    font-family: var(--font-heading);
    font-size: 22px;
    font-weight: var(--weight-display-medium);
    margin: 0 0 4px;
    letter-spacing: 0.005em;
}

.clyffe-continue-setup-subtitle {
    font-family: var(--font-body);
    font-size: 14px;
    opacity: 0.85;
    margin: 0;
}

.clyffe-continue-setup-cta {
    background: var(--action-attention);
    color: var(--clyffe-white);
    border: none;
    border-radius: var(--radius-sm);
    padding: 11px 22px;
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    transition: var(--transition-micro);
}

.clyffe-continue-setup-cta:hover {
    opacity: var(--hover-opacity);
}

/* ── Home (Clean) ── */
.hc-page {
    max-width: 1080px;
    margin: 0 auto;
    padding: 0 4px 32px;
    display: flex;
    flex-direction: column;
    gap: 28px;
}

.hc-greeting {
    display: block;
    padding: 4px 4px 0;
}

.hc-title {
    font-family: var(--font-heading);
    font-size: var(--text-display-size);
    font-weight: var(--weight-display-light);
    color: var(--text-display);
    margin: 0;
    letter-spacing: var(--tracking-display);
    line-height: var(--leading-display);
}

/* Headings are non-interactive — Blazor's FocusOnNavigate puts focus on h1 for
   screen-reader announcement, but we don't want a visible focus ring. */
.hc-title:focus,
.hc-title:focus-visible {
    outline: none;
    box-shadow: none;
}

.hc-subtitle {
    font-family: var(--font-body);
    font-size: 15px;
    color: var(--clyffe-muted);
    margin: 8px 0 0;
    max-width: 60ch;
    line-height: 1.55;
}

.hc-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    background: var(--clyffe-white);
    border: var(--border-card);
    border-radius: var(--radius-pill);
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 600;
    color: var(--clyffe-ink);
    cursor: pointer;
    text-decoration: none;
    transition: var(--transition-micro);
    box-shadow: none;
}

.hc-chip:hover {
    border-color: var(--border-strong);
    background: var(--navy-03);
}

.hc-cards {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 16px;
}

.hc-card {
    background: var(--clyffe-white);
    border: var(--border-card);
    border-radius: var(--radius-xs);
    padding: var(--pad-card) var(--pad-card) 24px;
    box-shadow: none;
    text-decoration: none;
    color: inherit;
    display: flex;
    flex-direction: column;
    gap: 6px;
    transition: var(--transition-micro);
    min-height: 220px;
    position: relative;
}

.hc-card:hover {
    border-color: var(--border-strong);
    background: var(--navy-03);
}

.hc-card-skeleton {
    background: var(--surface-sunken);
    pointer-events: none;
}

.hc-card-eyebrow {
    font-family: var(--font-mono);
    font-size: var(--text-mono-size);
    font-weight: var(--weight-mono);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-label);
    margin: 0;
}

.hc-card-headline {
    font-family: var(--font-heading);
    font-size: var(--text-display-size);
    font-weight: var(--weight-display);
    color: var(--clyffe-navy);
    margin: 4px 0 0;
    line-height: 1.05;
    letter-spacing: var(--tracking-display);
}

.hc-card-label {
    font-family: var(--font-body);
    font-size: 13px;
    color: var(--clyffe-muted);
    margin: 0 0 12px;
    line-height: 1.4;
}

.hc-card-detail {
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-family: var(--font-body);
    font-size: 12.5px;
    color: var(--clyffe-ink);
    margin-top: auto;
    margin-bottom: 14px;
}

.hc-card-cta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 600;
    color: var(--clyffe-navy);
    letter-spacing: var(--tracking-ui);
}

.hc-card-progress {
    width: 100%;
    height: 6px;
    border-radius: 999px;
    background: var(--navy-08);
    overflow: hidden;
    margin-bottom: 4px;
}

.hc-card-progress-fill {
    height: 100%;
    background: var(--clyffe-cove);
    border-radius: var(--radius-pill);
    transition: width 0.4s ease;
}

.hc-section {
    background: var(--clyffe-white);
    border: var(--border-card);
    border-radius: var(--radius-xs);
    padding: var(--pad-card) var(--pad-card) 24px;
    box-shadow: none;
}

.hc-section-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: 14px;
    gap: 16px;
}

.hc-section-title {
    font-family: var(--font-heading);
    font-size: 22px;
    font-weight: var(--weight-display);
    color: var(--text-heading);
    margin: 0;
    letter-spacing: 0.005em;
}

.hc-section-meta {
    font-family: var(--font-body);
    font-size: 12px;
    color: var(--clyffe-muted);
}

.hc-section-link {
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 600;
    color: var(--clyffe-navy);
    text-decoration: none;
    letter-spacing: var(--tracking-ui);
}

.hc-section-link:hover {
    text-decoration: underline;
    text-underline-offset: 2px;
}

.hc-handle-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

/* Constant padding + negative margin keeps the text stationary on hover — the highlight
   grows into the gutter instead of pushing the row content around. */
.hc-handle-item {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 10px;
    margin: 0 -6px;
    text-decoration: none;
    color: inherit;
    border-radius: 8px;
    transition: background 0.12s ease;
}

.hc-handle-item:hover {
    background: var(--navy-05);
}

.hc-handle-list li + li {
    border-top: 1px solid var(--border-hairline);
}

.hc-handle-marker {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

.hc-handle-marker-high {
    background: var(--clyffe-ember);
    box-shadow: 0 0 0 3px rgba(214, 99, 32, 0.18);
}

.hc-handle-marker-medium {
    background: var(--clyffe-navy);
    box-shadow: 0 0 0 3px rgba(30, 29, 121, 0.14);
}

.hc-handle-marker-low {
    background: var(--clyffe-cove);
    box-shadow: 0 0 0 3px rgba(70, 129, 137, 0.18);
}

.hc-handle-text {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.hc-handle-title {
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 600;
    color: var(--clyffe-ink);
    line-height: 1.35;
}

.hc-handle-subtitle {
    font-family: var(--font-body);
    font-size: 12.5px;
    color: var(--clyffe-muted);
    line-height: 1.45;
}

.hc-handle-arrow {
    color: var(--clyffe-muted);
    transition: transform 0.15s ease, color 0.15s ease;
}

.hc-handle-item:hover .hc-handle-arrow {
    color: var(--clyffe-navy);
    transform: translateX(2px);
}

.hc-empty {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 18px 4px;
    color: var(--clyffe-muted);
    font-family: var(--font-body);
    font-size: 13px;
}

.hc-empty-icon {
    color: var(--clyffe-cove);
}

/* One read fell back. Deliberately quieter than .hc-error — the page still works, and the brand
   reserves ember for things that are actually wrong. */
.hc-partial {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    background: var(--surface-sunken);
    border-radius: var(--radius-sm);
    color: var(--clyffe-ink);
    font-family: var(--font-body);
    font-size: 13px;
}

.hc-partial-icon {
    color: var(--clyffe-muted);
    flex-shrink: 0;
}

/* Apps that turned up recently. Same row rhythm as the handle list — a logo where the
   severity dot sits, so the two sections read as one page rather than two widgets. */
.hc-new-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.hc-new-list li + li {
    border-top: 1px solid var(--border-hairline);
}

.hc-new-item {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 10px;
    margin: 0 -6px;
    text-decoration: none;
    color: inherit;
    border-radius: 8px;
    transition: background 0.12s ease;
}

.hc-new-item:hover {
    background: var(--navy-05);
}

.hc-new-item:hover .hc-handle-arrow {
    color: var(--clyffe-navy);
    transform: translateX(2px);
}

.hc-new-text {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.hc-new-title {
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 600;
    color: var(--clyffe-ink);
    line-height: 1.35;
}

.hc-new-subtitle {
    font-family: var(--font-body);
    font-size: 12.5px;
    color: var(--clyffe-muted);
    line-height: 1.45;
}

.hc-error {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px 22px;
    background: var(--ember-08);
    border-radius: var(--radius-sm);
    color: var(--clyffe-ink);
}

.hc-error-icon {
    color: var(--clyffe-ember);
    flex-shrink: 0;
}

.hc-error-title {
    margin: 0;
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 600;
}

.hc-error-detail {
    margin: 2px 0 0;
    font-family: var(--font-body);
    font-size: 13px;
    color: var(--clyffe-muted);
}

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

    .hc-greeting {
        flex-direction: column;
        align-items: flex-start;
    }

    .hc-title {
        font-size: 32px;
    }
}

/* ── Products list (Phase D) ──────────────────────────────────────────────
   One row per product the customer would name. Flat per the design system:
   hairline border, 2px radius, never a shadow — the row is a surface, not a
   floating layer. All colour, spacing and type come from the tokens. */
.clyffe-product {
    /* Logo width + head gap: everything below the head hangs off this so the
       facts, bar and detail align under the product name, not under the logo. */
    --product-indent: calc(24px + var(--space-3));
    /* Chevron width + head gap: the head's cost stops this far short of the row's right
       edge, so the detail stops there too and every price shares one right edge. */
    --product-cost-inset: calc(20px + var(--space-3));
    border: var(--border-card);
    border-radius: var(--radius-xs);
    background: var(--surface-card);
    padding: var(--space-3) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.clyffe-product + .clyffe-product {
    margin-top: var(--space-2);
}

.clyffe-product-open {
    border-color: var(--border-strong);
}

/* A real <button>, so it needs the browser's button chrome stripped back to a plain row. */
.clyffe-product-head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    cursor: pointer;
    width: 100%;
    padding: 0;
    border: none;
    background: transparent;
    font: inherit;
    color: inherit;
    text-align: left;
}

.clyffe-product-head:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

.clyffe-product-identity {
    flex: 1 1 auto;
    min-width: 0;
}

.clyffe-product-cost {
    text-align: right;
    white-space: nowrap;
}

/* Headline facts: seats, activity, the date it can be acted on by. Separated
   by a hairline dot so the row reads as one sentence of facts, not a table. */
.clyffe-product-facts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-3);
    margin-left: var(--product-indent);
    font-family: var(--font-body);
    font-size: var(--text-caption-size);
    color: var(--text-body);
}

.clyffe-product-facts > span + span::before {
    content: "·";
    margin-right: var(--space-3);
    color: var(--text-muted);
}

/* Utilisation: how much of what this product reaches is actually being used. Cove when it is
   healthy, Ember when it is not — the two status tokens, never red or green. */
.clyffe-product-bar {
    width: 120px;
    height: 4px;
    margin-left: var(--product-indent);
    background: var(--navy-08);
    border-radius: var(--radius-pill);
    overflow: hidden;
}

.clyffe-product-bar-fill {
    height: 100%;
    background: var(--status-good);
}

.clyffe-product-bar-fill-low {
    background: var(--status-attention);
}

/* The one thing worth doing. Warm surface rather than an alert colour: this is
   an advisor's note, never an alarm. */
.clyffe-product-insight {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    background: var(--surface-warm);
    border-radius: var(--radius-xs);
    padding: var(--space-2) var(--space-3);
}

.clyffe-product-detail {
    border-top: 1px solid var(--border-hairline);
    padding-top: var(--space-3);
    padding-left: var(--product-indent);
    padding-right: var(--product-cost-inset);
    margin-top: var(--space-1);
}

.clyffe-product-account + .clyffe-product-account {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border-hairline);
}

.clyffe-product-account-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
}

/* The figure and its caveat share the price column's right edge — left-ragged, the
   caption's width would push the figure out of line with the rows around it. */
.clyffe-product-account-cost {
    text-align: right;
}

/* Accounts with nobody named on them, and the way to the page that fixes that. */
.clyffe-product-account-unnamed {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

.clyffe-product-plan {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-1) 0 var(--space-1) var(--space-3);
    border-left: 2px solid var(--border-hairline);
    margin-top: var(--space-2);
}

.clyffe-product-components {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border-hairline);
}

@media (max-width: 700px) {
    .clyffe-product-head {
        flex-wrap: wrap;
    }

    .clyffe-product-cost {
        text-align: left;
        width: 100%;
    }

    /* The name no longer sits beside the logo once the head wraps, so the indent stops meaning anything. */
    .clyffe-product-facts,
    .clyffe-product-bar {
        margin-left: 0;
    }

    .clyffe-product-detail {
        padding-left: 0;
        padding-right: 0;
    }
}

/* One email domain awaiting or holding the customer's confirmation. */
.clyffe-domain-row {
    padding: var(--space-2) 0;
}

.clyffe-domain-row + .clyffe-domain-row {
    border-top: 1px solid var(--border-hairline);
}

.clyffe-product-ladder,
.clyffe-product-detail-action {
    margin-top: var(--space-2);
}

/* "Add a bill" / "Add the agreement" upload controls in the app detail pane: MudFileUpload's
   block wrapper would otherwise break the section header row.
   MudFileUpload is a MudInputControl, so it stacks its children in a column and keeps an
   empty selected-files list under the button with a 4px top margin. In a row of buttons that
   made the wrapper 4px taller than the button inside it, and every sibling button stretched
   to match — which is why "Add a bill" and "Set cost" came out different heights. Laying the
   wrapper out in a row takes the empty list out of the vertical measure. */
.clyffe-invoice-upload,
.clyffe-agreement-upload {
    margin: 0;
    display: inline-flex;
    flex-direction: row;
    align-items: center;
    flex: 0 0 auto;
}

/* Evidence captions in the agreement review dialog sit tight under their field, reading as a
   footnote to it rather than a row of their own */
.clyffe-agreement-evidence {
    margin-top: -6px;
}

/* The agreement's name heading in the app page's Agreement tab */
.clyffe-agreement-terms + .clyffe-agreement-terms {
    border-top: 1px solid var(--border-hairline);
    padding-top: var(--space-2);
}

/* Level 3: the bill history ledger — raw lines, categorised, never overwritten. Cells run tight
   and the table scrolls sideways before it clips */
.clyffe-cost-ledger {
    overflow-x: auto;
}

.clyffe-cost-ledger table {
    width: 100%;
}

.clyffe-cost-ledger th {
    font-weight: 600;
}

/* Doubled class outranks MudSimpleTable's dense padding (6px 16px) without naming any
   framework class; four columns must fit the pane's width */
.clyffe-cost-ledger.clyffe-cost-ledger tr th,
.clyffe-cost-ledger.clyffe-cost-ledger tr td {
    padding: 6px 8px;
    font-size: 0.8125rem;
}

.clyffe-cost-ledger td:first-child,
.clyffe-cost-ledger th:first-child {
    white-space: nowrap;
}

.clyffe-cost-ledger .clyffe-cost-ledger-amount {
    text-align: right;
    white-space: nowrap;
}

.clyffe-cost-ledger-tax td {
    color: var(--mud-palette-text-secondary);
}

/* ---- Quick-glance pane + the full app page (#328) ---------------------------------------- */

/* One lead figure per block, with the line that says what the figure means under it. */
.clyffe-product-figure-lead {
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
}

.clyffe-product-figure-attention {
    color: var(--clyffe-ember);
}

/* The pane's blocks: one hairline between them, no boxes inside a box. */
.apps-pane-block + .apps-pane-block {
    border-top: 1px solid var(--border-hairline);
    padding-top: var(--space-3);
}

.apps-pane-pointer {
    border-top: 1px solid var(--border-hairline);
    padding-top: var(--space-3);
}

/* Labels left, values right-aligned on a shared column — the same list shape in the pane and
   in the app page's owner card and agreement tab. */
.clyffe-fact-list {
    display: flex;
    flex-direction: column;
}

.clyffe-fact {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    /* Half the section break (space-3 sits under each block divider): the last row then
       ends the same distance from the section's rule as it sits from its neighbours,
       instead of the closing rule floating below a tighter list. */
    padding: var(--space-2) 0;
}

.clyffe-fact + .clyffe-fact {
    border-top: 1px solid var(--border-hairline);
}

.clyffe-fact > :last-child {
    text-align: right;
}

/* The one date on the agreement that can still be acted on carries the single emphasis. */
.clyffe-fact-attention > :last-child {
    color: var(--clyffe-ember);
    font-weight: 600;
}

.clyffe-app-detail-actions {
    flex-shrink: 0;
}

/* Shares its grid row with the stat cards, so it fills the row's height like they do. */
.clyffe-app-ownership {
    height: 100%;
}

.clyffe-app-detail-note,
.clyffe-app-devices-section,
.clyffe-app-components-section {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border-hairline);
}

/* Only when accounts precede it — as the panel's first section it needs no divider above. */
.clyffe-app-accounts-section + .clyffe-app-usage-section {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border-hairline);
}

/* The tab panel is the full card width, but an account is one email and one figure — stretched
   across 1200px they stop reading as one row. Capped so the price sits beside what it prices. */
.clyffe-app-accounts-section {
    max-width: 720px;
}

.clyffe-app-usage-row,
.clyffe-app-device-row {
    padding: var(--space-1) 0;
}

/* The work raised about one app. Same quiet table treatment as the seats and cost ledgers, so
   the tabs read as one page rather than three. */
.clyffe-app-tasks-table {
    overflow-x: auto;
}

.clyffe-app-tasks-table table {
    width: 100%;
}

.clyffe-app-tasks-table th {
    font-weight: 600;
}

/* One row per plan across every account. Numbers right-aligned and tabular so the columns can
   be compared down the page rather than read one cell at a time. */
.clyffe-seats-table {
    overflow-x: auto;
}

.clyffe-seats-table table {
    width: 100%;
}

.clyffe-seats-table th {
    font-weight: 600;
}

.clyffe-seats-table .clyffe-seats-number {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* Warm, never alarming: a row with seats going spare is the one worth looking at. */
.clyffe-seats-row-attention td {
    background: var(--surface-warm);
}

.clyffe-cost-trend {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border-hairline);
}

.clyffe-cost-trend-chart {
    display: block;
    width: 100%;
    max-width: 420px;
    height: 64px;
    margin-top: var(--space-2);
    overflow: visible;
}

.clyffe-cost-trend-line {
    fill: none;
    stroke: var(--clyffe-cove);
    stroke-width: 1.5;
    stroke-linejoin: round;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;
}

.clyffe-cost-trend-point {
    fill: var(--clyffe-cove);
}

/* ── Review screens: the document beside the figures read from it ─────────────────────────
   Both review dialogs (a bill, an agreement) put the uploaded file on the left and the fields
   on the right, so confirming what we read never means opening the file somewhere else and
   swapping windows. Below the tablet breakpoint the two stack, document first — checking the
   paper is what the screen is for. */
.clyffe-review-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-4);
    align-items: start;
    min-width: 0;
}

@media (max-width: 959px) {
    .clyffe-review-layout {
        grid-template-columns: minmax(0, 1fr);
    }
}

.clyffe-review-fields {
    min-width: 0;
}

/* What we made of the document, in words, before any of it is recorded */
.clyffe-review-narrative {
    color: var(--text-body);
}

/* Evidence captions sit tight under their field, reading as a footnote to it rather than a
   row of their own — the same treatment the agreement review has always used */
.clyffe-review-evidence {
    margin-top: -6px;
}

.clyffe-review-add-tax {
    align-self: flex-start;
}

/* The uploaded file itself. The frame fills the pane and scrolls internally, so a long bill
   never stretches the dialog past the viewport. */
.clyffe-document-preview {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.clyffe-document-preview-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.clyffe-document-preview-frame {
    width: 100%;
    height: 60vh;
    min-height: 320px;
    border: 1px solid var(--border-hairline);
    border-radius: 2px;
    background: var(--surface-sunken);
}

.clyffe-document-preview-rows,
.clyffe-document-preview-empty {
    max-height: 60vh;
    overflow: auto;
    border: 1px solid var(--border-hairline);
    border-radius: 2px;
    padding: var(--space-2);
}

.clyffe-document-preview-amount {
    text-align: right;
    white-space: nowrap;
}

/* Charges are the content of the bill; its own tax, subtotal and total rows are arithmetic
   about them, kept but quieter so what was bought stands apart from what it added up to. */
.clyffe-document-preview-line-tax td,
.clyffe-document-preview-line-discount td,
.clyffe-document-preview-line-subtotal td,
.clyffe-document-preview-line-total td {
    color: var(--text-muted);
}

.clyffe-document-preview-line-subtotal td,
.clyffe-document-preview-line-total td {
    border-top: 1px solid var(--border-hairline);
}

/* The count and each-price the bill stated, under the charge's own words. */
.clyffe-document-preview-each {
    display: block;
    color: var(--text-muted);
    font-size: var(--text-caption-size);
}

/* Shown in place of the file when the sign-in behind the preview has gone stale. Centred in
   whatever the frame gives it, because the pane it replaces is a tall narrow column and a
   message pinned to the top of one reads as a broken page rather than a calm next step. */
.clyffe-document-signin {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 100vh;
    padding: var(--space-4);
    text-align: center;
}

.clyffe-document-signin-action {
    margin-top: var(--space-2);
}

/* The one question the bill can't answer for itself, asked against the charge it is about.
   Held to the width of a count so it reads as a small answer, not another figure to check. */
.clyffe-document-preview-ask {
    margin-top: var(--space-1);
    max-width: 220px;
}

/* A spreadsheet bill has no viewer of its own, so its rows are the pane; a PDF's rows sit under
   the viewer, and both need room to scroll without the questions falling off the bottom. The two
   share the pane rather than stacking to twice its height. */
.clyffe-document-preview-frame + .clyffe-document-preview-rows {
    max-height: 32vh;
}

.clyffe-document-preview:has(.clyffe-document-preview-rows) .clyffe-document-preview-frame {
    height: 38vh;
}

/* Where a ledger figure came from, under the line it belongs to */
.clyffe-cost-ledger-note {
    display: block;
}

/* Whose bill the line was, under the same line. Only rendered for a charge that sits under an
   account, so the column stays quiet for a business that pays one bill for everyone. */
.clyffe-cost-ledger-account {
    display: block;
}

/* Which billing profile a charge belongs to. The options stack one per line, because one person
   can hold two plans on two addresses and telling those apart is the whole job of this control —
   run inline, the addresses wrap and stop reading as the labels of their own buttons. */
.clyffe-account-choice {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.clyffe-account-choice-option {
    display: flex;
    width: 100%;
    margin-inline-end: 0;
}

.clyffe-account-choice-email {
    margin-top: var(--space-1);
}

.clyffe-account-choice-helper {
    margin-top: calc(var(--space-1) * -1);
}

/* What a price is made of, once the customer says it has more than one part. Each part is its own
   block with a hairline above it, so a run of four plans reads as four things rather than one long
   column of fields. */
.clyffe-cost-parts {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.clyffe-cost-part {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding-top: var(--space-2);
}

.clyffe-cost-part + .clyffe-cost-part {
    border-top: 1px solid var(--border-hairline);
}

/* Quiet: removing a part is a correction, not an action the eye should be drawn to. */
.clyffe-cost-part-remove {
    align-self: flex-start;
}

/* One block per account on the app page: what it is and what it costs, then whose it is, then
   whether its spend counts. Mirrors the account block in the apps list so the two never read as
   different things. */
.clyffe-app-account + .clyffe-app-account {
    padding-top: var(--space-3);
    border-top: 1px solid var(--border-hairline);
}

.clyffe-app-account-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
}

.clyffe-app-account-named,
.clyffe-app-account-matched,
.clyffe-app-account-rollup {
    margin-top: var(--space-2);
}

/* Narrow on purpose: it holds one name, and a full-width control would read as the account's
   headline rather than an answer beside it. */
.clyffe-app-account-person {
    max-width: 20rem;
}

.clyffe-agreement-notes,
.clyffe-agreement-source {
    display: block;
    margin-top: var(--space-2);
}
