/* 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) */
    --app-command-bar-height: 72px;

    /* How tall the assistant sheet stands over the page when it is open. Below --bp-md it is
       the whole viewport under the app bar instead. */
    --app-assistant-sheet-height: min(70vh, 720px);
}

html,
body {
    margin: 0;
    font-family: var(--font-body);
    color: var(--ink);
    background: var(--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(--mud-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(--ink);
    padding: 0 12px;
    height: var(--mud-appbar-height, 48px);
    min-height: var(--mud-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 {
    --app-drawer-width-left: 56px;
}

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

/* Tap-anywhere-to-dismiss behind the expanded drawer. Declared before the media
   query that reveals it: both rules set `display` at the same specificity, so
   whichever comes last wins, and a base rule written afterwards would keep the
   scrim hidden at every width. */
.clyffe-drawer-scrim {
    display: none;
    position: fixed;
    inset: 0;
    border: none;
    padding: 0;
    background: var(--scrim);
    animation: clyffe-scrim-in var(--duration-micro) var(--ease-out);
}

@keyframes clyffe-scrim-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

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

    /* Below the breakpoint the expanded drawer floats over the page instead of
       pushing it across (#584). MudBlazor's mini drawer moves .mud-main-content
       from the rail width to the full width when it opens; on a 375px screen that
       shoves the content 240px off-stage. Holding the margin at the rail width
       leaves the content where it is and lets the drawer — already fixed — cover
       it. Hung off .clyffe-drawer-open rather than MudBlazor's
       .mud-drawer-open-mini-md-left, whose name encodes the breakpoint and would
       stop matching the day the drawer's Breakpoint changed. */
    .clyffe-drawer-open.mud-layout .mud-main-content {
        margin-left: var(--mud-drawer-width-mini-left);
    }

    /* It is a floating layer now, so it casts one. */
    .clyffe-drawer-open .clyffe-drawer {
        z-index: 1310;
        box-shadow: var(--shadow-overlay);
    }

    /* Above the command bar (1300) so the nav is not underlapped by it, and the
       scrim sits between the two so both dim together. */
    .clyffe-drawer-open .clyffe-drawer-scrim {
        display: block;
        z-index: 1305;
    }
}

/* The drawer's signature, not a control (#966) — so no pointer, no hover response, and nothing
   that invites the click the reader used to have to guess at. */
.clyffe-drawer-header {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    text-align: left;
    height: 48px;
    padding: 0 16px;
    box-sizing: border-box;
    user-select: none;
    transition: padding var(--duration-micro) var(--ease-out);
    width: 100%;
    color: inherit;
}

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


/* The organisation's row beneath the lockup (epic #1043): their logo tile and their name, on the
   drawer's navy. The ring's colour is the customer's accent, set as a value on the ring's own
   element; with none it falls back to the quiet on-navy hairline. */
.clyffe-org-badge {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-1) var(--space-4) var(--space-3);
    min-width: 0;
    color: var(--text-on-navy);
}

.clyffe-org-badge-ring {
    display: inline-flex;
    flex: 0 0 auto;
    border-radius: var(--radius-sm);
    box-shadow: 0 0 0 2px var(--org-accent, var(--cream-30));
}

.clyffe-org-badge-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: var(--weight-body-medium);
}

.clyffe-org-badge--collapsed {
    justify-content: center;
    padding: var(--space-1) 0 var(--space-3);
}

/* 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);
}

/* Parchment, not a cream tint: 50% cream over the navy drawer resolves to a pale lavender,
   which is what the 26 Aug walkthrough saw. The brand's on-navy mark colour is the full
   token, and the active item is told apart by its highlight and rule, not by its icon. */
.clyffe-nav-menu .mud-nav-link .mud-nav-link-icon {
    color: var(--parchment);
}

.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) {
    position: relative;
    background-color: var(--white-08);
    color: var(--parchment);
    border-radius: var(--radius-sm);
    font-weight: var(--weight-body-semibold);
}

/* The 2px rule the design system asks for beside the highlight, inset from the ends so it reads
   as a marker rather than a border on the block. */
.clyffe-nav-menu .mud-nav-link.active::before,
.clyffe-nav-menu .clyffe-nav-active .mud-nav-link::before {
    content: "";
    position: absolute;
    left: 0;
    top: var(--space-2);
    bottom: var(--space-2);
    width: 2px;
    border-radius: var(--radius-xs);
    background: var(--parchment);
}

.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);
}

/* The two footer actions that are buttons rather than links: "Send feedback" opens a dialog and
   "Account" opens a menu. Both wear the nav link's own metrics so they read as part of the list. */
.clyffe-nav-action {
    padding: 4px 10px 0;
}

.clyffe-nav-action-trigger {
    display: flex;
    align-items: center;
    /* MudBlazor's base button rule centres its content; a full-width item lines up with the links. */
    justify-content: flex-start;
    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 var(--duration-instant) var(--ease-out);
}

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

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

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

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

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

/* The collapse chevron sits below the account action, separated from it so it reads as the
   drawer's own control rather than one more place to go (#966). */
.clyffe-nav-collapse {
    margin-top: 6px;
}

.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));
}

/* The page keeps the command bar's height clear at its foot, so the last row is never under the
   bar. The assistant sheet floats over the page rather than beside it, so nothing here makes
   room for it: the page is exactly where it was when the sheet closes. */
.clyffe-shell {
    min-width: 0;
    padding: 24px 28px calc(var(--app-command-bar-height) + 32px);
}

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

/* 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(--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;
}

/* The "whose machine is this?" question. A warm surface so it reads as Clyffe asking rather
   than as a warning, and its own class so the markup never leans on a MudBlazor internal. */
/* The #481 question card: one thing Clyffe cannot settle on its own, asked in plain words with
   two answers. Both the device question and the "same person?" question wear it, so the shape is
   declared once rather than twice with the same tokens. */
.clyffe-owner-question,
.clyffe-person-question {
    border: var(--border-card);
    border-radius: var(--radius-xs);
    background: var(--parchment);
    padding: var(--space-4);
}

/* The two accounts a "same person?" question is about: one row each, in the order the question
   names them, with the workspace beside the address rather than adrift at the far edge of a wide
   card. Each row keeps its own box and borrows the container's columns through subgrid, so both
   workspaces line up under each other without flattening the row away with display: contents —
   which some assistive tech historically mishandles (the same reason the nav wrapper avoids it). */
.clyffe-person-question-accounts {
    display: grid;
    grid-template-columns: auto auto;
    justify-content: start;
    column-gap: var(--space-4);
    row-gap: var(--space-1);
}

.clyffe-person-question-account {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    align-items: center;
}

/* One of the other people the same evidence named: who, why, and the way to pick them. */
.clyffe-owner-alternative {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-top: var(--border-card);
}

/* Keeps the confirm affordance from pushing the row's line height around. */
.clyffe-owner-confirm-link {
    margin-left: -8px;
    padding-left: 8px;
    padding-right: 8px;
}

/* A health check's message and its remedy, each on its own line. MudBlazor draws a caption as an
   inline <span>, so two of them in a row sat against each other with no separator and the firewall
   check read "DisabledHow to fix: …" (#583). */
.clyffe-device-check-message,
.clyffe-device-check-remedy {
    display: block;
}

.clyffe-device-check-remedy {
    margin-top: var(--space-1);
}

/* A stat card that is also the way in. Every headline number has somewhere to go (R7, #583), and
   the whole card is the control rather than a link buried under it — a figure and the page that
   explains it are one thing to click. */
.clyffe-stat-link {
    display: block;
    text-decoration: none;
    color: inherit;
    transition: var(--transition-micro);
}

.clyffe-stat-link:hover {
    border-color: var(--border-strong);
    background: var(--navy-03);
}

/* Where the card goes, said out loud. Hover alone is not an affordance on a touch screen.
   Block-level, because MudBlazor draws a caption as an inline <span> and the line above it would
   otherwise run straight into this one — the same defect as the firewall row (#583). */
.clyffe-stat-cta {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: var(--space-2);
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 600;
    color: var(--navy);
    letter-spacing: var(--tracking-ui);
}

/* One line of small print under a stat card's figure. Captions are inline spans, so two of them
   in a row need saying that they are lines. */
.clyffe-stat-note {
    display: block;
}

/* A count that is a to-do list: it filters the table below rather than just reporting. Declared
   as a real <button>, so the rules here are what stop it looking like one. */
.clyffe-stat-action {
    cursor: pointer;
    display: block;
    width: 100%;
    text-align: left;
    font: inherit;
    color: inherit;
}

.clyffe-stat-active {
    border-color: var(--navy);
}

/* The line a view-only member reads where a control would have been (#850). Calm and quiet: it
   is a fact about their access, not a warning, so it takes the page's own muted text colour and
   adds nothing but the space a hidden control left behind. */
.clyffe-view-only-notice {
    display: block;
    padding: 4px 0;
}

/* 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: 960px) {
    .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(--app-command-bar-height) + 24px);
    }
}

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

/* While the sheet is open its footer is the composer, standing exactly where the bar stood, so
   the bar itself steps out of the way rather than showing a second box to type into. */
.clyffe-assistant-dock--open .clyffe-command-bar {
    opacity: 0;
    visibility: hidden;
    transition: left var(--duration-micro) var(--ease-out), opacity var(--duration-micro) var(--ease-out), visibility 0s linear var(--duration-micro);
}

.clyffe-command-bar-inner {
    pointer-events: auto;
    width: 100%;
    max-width: 880px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px 6px 18px;
    background: var(--white);
    border: 1px solid var(--border-hairline);
    border-radius: 999px;
    box-shadow: var(--shadow-raised);
    transition: border-color var(--duration-instant) var(--ease-out), box-shadow var(--duration-instant) var(--ease-out);
    cursor: text;
}

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

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

/* The bar's mark is also its handle: one press opens the sheet with nothing typed. */
.clyffe-command-bar-toggle {
    width: 32px;
    height: 32px;
    margin-left: -8px;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
    transition: background var(--duration-instant) var(--ease-out);
}

.clyffe-command-bar-toggle:hover,
.clyffe-command-bar-toggle:focus-visible {
    background: var(--navy-05);
}

/* A conversation they closed but did not finish sits on the bar as one chip: its name, and the
   word that says what pressing it does. It goes with the sheet when the sheet opens. */
.clyffe-command-bar-continue {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 40%;
    padding: 4px 10px 4px 8px;
    border: 1px solid var(--navy-08, rgba(30, 29, 121, 0.08));
    border-radius: var(--radius-pill);
    background: var(--parchment-50);
    font-family: var(--font-body);
    font-size: 12px;
    color: var(--navy);
    cursor: pointer;
    flex-shrink: 1;
    min-width: 0;
    transition: border-color var(--duration-instant) var(--ease-out), background var(--duration-instant) var(--ease-out);
}

.clyffe-command-bar-continue:hover,
.clyffe-command-bar-continue:focus-visible {
    border-color: var(--navy);
    background: var(--parchment);
}

.clyffe-command-bar-continue-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.clyffe-command-bar-continue-verb {
    font-weight: var(--weight-body-semibold);
    flex-shrink: 0;
}

/* A phone's bar has room for the word and not the name: the chip's title still carries it. */
@media (max-width: 960px) {
    .clyffe-command-bar-continue {
        max-width: none;
        padding-right: 10px;
    }

    .clyffe-command-bar-continue-name {
        display: none;
    }
}

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

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

/* ── The eyebrow ──
   The small label above a figure or a section: a stat card's "Apps", the setup rail's
   "Setup progress", the assistant panel's "Try asking". Every one of these
   used to declare its own JetBrains Mono capitals with its own tracking — six copies of
   a style that reads as a terminal readout rather than an advisor (design system
   README §2 Casing, amended 27 Aug 2026). One rule owns the type now; the rules below
   carry only the colour and spacing that genuinely differ. */
.clyffe-assistant-examples-label,
.clyffe-landing-brandfoot,
.clyffe-setup-rail-title,
.clyffe-continue-setup-eyebrow,
.hc-card-eyebrow {
    font-family: var(--font-body);
    font-size: var(--text-eyebrow-size);
    font-weight: var(--weight-body-semibold);
    line-height: var(--leading-ui);
    letter-spacing: var(--tracking-ui);
    text-transform: none;
}

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

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

/* ── The assistant sheet ──
   The conversation stands up out of the command bar: a sheet the bar's own width, rising from
   the bar's own place at the foot of the page, whose footer is the same composer the bar was.
   Nothing about the page beside it changes, so the page is where they left it when the sheet
   closes, and the one box they type into never moves. A floating layer, so it wears the
   overlay shadow that cards never do. */
.clyffe-assistant-sheet {
    position: fixed;
    left: var(--app-drawer-width-left, 0px);
    right: 0;
    bottom: 0;
    z-index: 1400;
    padding: 0 24px 14px;
    pointer-events: none;
    visibility: hidden;
    transition: left var(--duration-micro) var(--ease-out), visibility 0s linear var(--duration-panel);
}

.clyffe-assistant-sheet.open {
    visibility: visible;
    transition: left var(--duration-micro) var(--ease-out), visibility 0s linear 0s;
}

.clyffe-assistant-sheet-inner {
    width: 100%;
    max-width: 880px;
    height: var(--app-assistant-sheet-height);
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--white);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-overlay);
    pointer-events: auto;
    transform: translateY(calc(100% + 24px));
    opacity: 0;
    transition: transform var(--duration-panel) var(--ease-out), opacity var(--duration-panel) var(--ease-out);
}

.clyffe-assistant-sheet.open .clyffe-assistant-sheet-inner {
    transform: none;
    opacity: 1;
}

/* No room for a page around a sheet below the medium breakpoint: it is the whole viewport under
   the app bar, square to the edges, and rises the same way. */
@media (max-width: 960px) {
    .clyffe-assistant-sheet {
        top: var(--mud-appbar-height, 48px);
        left: 0;
        padding: 0;
    }

    .clyffe-assistant-sheet-inner {
        max-width: none;
        height: 100%;
        border: none;
        border-radius: 0;
        box-shadow: none;
    }
}

.clyffe-assistant-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border-hairline);
    background: var(--white);
}

.clyffe-assistant-title {
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 500;
    color: var(--navy);
    letter-spacing: 0.005em;
    white-space: nowrap;
}

/* The name is the one thing in the header that never wraps; on a phone the context label folds
   under itself instead. */
.clyffe-assistant-context {
    font-size: 12px;
    color: var(--text-body);
    margin-left: auto;
    margin-right: 8px;
    min-width: 0;
    text-align: right;
}

/* The panel below its header: the history column, then the conversation. Both scroll in their
   own right, so a long history never pushes the composer off the panel. */
.clyffe-assistant-main {
    flex: 1;
    display: flex;
    min-height: 0;
}

.clyffe-assistant-column {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
}

.clyffe-assistant-icon-button {
    width: 32px;
    height: 32px;
    border: none;
    background: transparent;
    color: var(--text-body);
    border-radius: var(--radius-sm);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: background var(--duration-instant) var(--ease-out), color var(--duration-instant) var(--ease-out);
}

.clyffe-assistant-icon-button:hover {
    background: var(--navy-05);
    color: var(--ink);
}

/* ── The history column ──
   Every conversation they have had (#591). In the rail it takes the conversation's place while it is
   open rather than sitting beside it (#873): there is one column's width, and the list is what
   they asked to see. Quiet by construction: the panel's own surfaces and no colour of its own. */
.clyffe-chat-history {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    background: var(--parchment-30);
    overflow-y: auto;
}

.clyffe-chat-history-top {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.clyffe-chat-history-new {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: var(--white);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: 13px;
    color: var(--ink);
    cursor: pointer;
    transition: border-color var(--duration-instant) var(--ease-out), background var(--duration-instant) var(--ease-out);
}

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

.clyffe-chat-history-search {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 10px;
    background: var(--white);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-md);
}

.clyffe-chat-history-search-icon {
    color: var(--text-body);
    flex-shrink: 0;
}

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

.clyffe-chat-history-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.clyffe-chat-history-row {
    display: flex;
    align-items: center;
    gap: 4px;
    border-radius: var(--radius-md);
}

.clyffe-chat-history-row:hover {
    background: var(--navy-05);
}

.clyffe-chat-history-row--current {
    background: var(--navy-05);
}

.clyffe-chat-history-open {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-width: 0;
    padding: 8px 10px;
    border: none;
    background: transparent;
    font-family: var(--font-body);
    font-size: 13px;
    color: var(--ink);
    text-align: left;
    cursor: pointer;
}

.clyffe-chat-history-headline {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    min-width: 0;
}

.clyffe-chat-history-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.clyffe-chat-history-when {
    font-size: 11px;
    color: var(--text-body);
}

/* Unread is a mark, not a count: they want to know there is something here, not how much. */
.clyffe-chat-history-unread {
    width: 7px;
    height: 7px;
    flex-shrink: 0;
    border-radius: 999px;
    background: var(--cove);
    align-self: center;
}

.clyffe-chat-history-row-actions {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    padding-right: 4px;
}

/* Narrower than the header's, because two of them sit beside every row and the name is what they
   are reading. */
.clyffe-chat-history-row-actions .clyffe-assistant-icon-button {
    width: 26px;
    height: 26px;
    opacity: 0.5;
}

.clyffe-chat-history-row-actions .clyffe-assistant-icon-button:hover,
.clyffe-chat-history-row-actions .clyffe-assistant-icon-button:focus-visible {
    opacity: 1;
}

/* A pinned row's pin is the one that reads as on: full strength navy against the muted pins of
   the rows they have not pinned. */
.clyffe-chat-history-row-actions .clyffe-chat-history-pinned {
    color: var(--navy);
    opacity: 1;
}

.clyffe-chat-history-rename {
    display: flex;
    align-items: center;
    gap: 4px;
    width: 100%;
    padding: 4px;
}

.clyffe-chat-history-rename-input {
    flex: 1;
    min-width: 0;
    padding: 6px 8px;
    border: 1px solid var(--navy);
    border-radius: var(--radius-md);
    outline: none;
    background: var(--white);
    font-family: var(--font-body);
    font-size: 13px;
    color: var(--ink);
}

.clyffe-chat-history-rename-save,
.clyffe-chat-history-rename-cancel {
    flex-shrink: 0;
    padding: 6px 8px;
    border: none;
    background: transparent;
    font-family: var(--font-body);
    font-size: 12px;
    color: var(--navy);
    cursor: pointer;
    border-radius: var(--radius-sm);
}

.clyffe-chat-history-rename-cancel {
    color: var(--text-body);
}

.clyffe-chat-history-rename-save:hover,
.clyffe-chat-history-rename-cancel:hover {
    background: var(--navy-05);
}

.clyffe-chat-history-empty {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 4px;
    color: var(--text-body);
}

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

.clyffe-assistant-examples-label {
    color: var(--text-label);
}

.clyffe-assistant-intro {
    color: var(--ink);
    max-width: 60ch;
}

/* The transcript grows up off the composer, like the setup conversation's does. */
.clyffe-assistant-transcript {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.clyffe-assistant-transcript > :first-child {
    margin-top: auto;
}

.clyffe-assistant-line {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* ── Clyffe's words, drawn (#871) ──
   The model writes Markdown and the panel renders it: a paragraph, a dash list, a bold name, now
   and then a small table. The type is the body's; only the rhythm between blocks is set here, and
   a table inside an answer wears the same frame as a tool result so the two never look like
   different kinds of table. */
.clyffe-assistant-line--rendered {
    white-space: normal;
    font-size: var(--text-body-size);
    font-weight: var(--weight-body);
    line-height: var(--leading-body);
}

.clyffe-assistant-line--rendered > :first-child {
    margin-top: 0;
}

.clyffe-assistant-line--rendered > :last-child {
    margin-bottom: 0;
}

.clyffe-assistant-line--rendered p {
    margin: 0 0 var(--space-2);
}

.clyffe-assistant-line--rendered ul,
.clyffe-assistant-line--rendered ol {
    margin: 0 0 var(--space-2);
    padding-left: var(--space-4);
}

.clyffe-assistant-line--rendered li {
    margin: 0 0 var(--space-1);
}

.clyffe-assistant-line--rendered li > p {
    margin: 0;
}

.clyffe-assistant-line--rendered strong {
    font-weight: var(--weight-body-medium);
    color: var(--text-strong);
}

.clyffe-assistant-line--rendered code {
    font-family: var(--font-mono);
    font-size: var(--text-caption-size);
    letter-spacing: var(--tracking-mono);
}

/* A heading in an answer is a bold line, not a page title: the panel is a conversation. */
.clyffe-assistant-line--rendered h1,
.clyffe-assistant-line--rendered h2,
.clyffe-assistant-line--rendered h3,
.clyffe-assistant-line--rendered h4 {
    margin: 0 0 var(--space-1);
    font-family: var(--font-body);
    font-size: var(--text-body-size);
    font-weight: var(--weight-body-medium);
    line-height: var(--leading-body);
    color: var(--text-strong);
}

.clyffe-assistant-line--rendered table {
    width: 100%;
    margin: 0 0 var(--space-2);
    border-collapse: separate;
    border-spacing: 0;
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-lg);
    background: var(--white);
    font-size: var(--text-caption-size);
    overflow: hidden;
}

.clyffe-assistant-line--rendered th,
.clyffe-assistant-line--rendered td {
    padding: var(--space-2) var(--space-3);
    text-align: left;
    vertical-align: top;
    border-top: 1px solid var(--border-hairline);
}

.clyffe-assistant-line--rendered th {
    border-top: 0;
    background: var(--navy-03);
    font-weight: var(--weight-body-semibold);
}

/* A tool result drawn rather than read out (#593): the same quiet table the app pages use, on
   Clyffe's side of the transcript at the panel's full width, and scrolling sideways inside its
   own frame before it clips so a wide answer never makes the panel scroll. */
.clyffe-bubble-row--widget {
    align-self: stretch;
    max-width: 100%;
}

.clyffe-assistant-widget {
    width: 100%;
    min-width: 0;
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-lg);
    background: var(--white);
    overflow: hidden;
}

/* What the table is, in the assistant's words, above its first row. */
.clyffe-assistant-widget-caption {
    padding: var(--space-2) var(--space-4);
    border-bottom: 1px solid var(--border-hairline);
    font-weight: var(--weight-body-semibold);
}

/* The frame above is the table's edge; the table draws none of its own. */
.clyffe-assistant-widget-table {
    border: none;
}

/* A product's mark beside its name, the way the Apps list draws it. */
.clyffe-assistant-widget-product {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.clyffe-assistant-widget-scroll {
    overflow-x: auto;
    max-width: 100%;
}

.clyffe-assistant-widget-table th {
    font-weight: var(--weight-body-semibold);
    white-space: nowrap;
}

.clyffe-assistant-widget-table td {
    white-space: nowrap;
}

/* A row about one thing opens that thing's page: the same hover the history rows wear. */
.clyffe-assistant-widget-row--link {
    cursor: pointer;
}

.clyffe-assistant-widget-row--link:hover,
.clyffe-assistant-widget-row--link:focus-visible {
    background: var(--navy-05);
}

.clyffe-assistant-widget-list {
    margin: 0;
    padding: var(--space-2) var(--space-4);
    list-style: none;
}

.clyffe-assistant-widget-list li {
    padding: var(--space-1) 0;
    border-top: 1px solid var(--border-hairline);
}

.clyffe-assistant-widget-list li:first-child {
    border-top: 0;
}

.clyffe-assistant-pending {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    background: var(--parchment-50);
    color: var(--text-body);
    border-radius: var(--radius-lg);
    font-size: 13px;
}

.clyffe-assistant-note {
    font-size: 13px;
    line-height: 1.55;
    color: var(--text-body);
}

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

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

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

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

/* The chip as a link: the screen an answer opened (#976). */
.clyffe-assistant-screen-action {
    text-decoration: none;
}

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

/* ── Landing (split hero) ──
   The first screen anyone sees, so it carries the brand rather than a centred block of text: a
   full-bleed navy panel (with the logo's concentric arcs at a few percent white) against a quiet
   off-white content column. Parchment is a warm accent in the brand, not a page's ground colour —
   a whole column of it is the one thing that made this read as a different product from the door.
   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-canvas);
}

.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-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;
    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 the page
   header's 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: 960px) {
    .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) ──
   Layout only. The surface is .clyffe-brand-canvas from the design system — the navy the sign-in
   door stands on — so setup reads as the far side of the same doorway. */
.clyffe-onboarding-shell {
    min-height: 100vh;
    display: flex;
    justify-content: center;
    padding: 64px 24px 64px;
}

/* Centred the way the door centres its card — a short screen floating at the top of a tall navy
   field reads as unfinished. Auto margins rather than align-items: center, because a centred flex
   item taller than the viewport (the conversation, on a short window) has its overflowing top
   clipped beyond reach; auto margins simply collapse to nothing instead. */
.clyffe-onboarding-shell > * {
    margin-block: auto;
}

/* Every setup screen puts its content in one of these: on navy there is no such thing as a bare
   paragraph, so a page that forgets the card is a page of ink on ink. */
.clyffe-onboarding-card {
    width: 100%;
    max-width: 580px;
    background: var(--surface-card);
    border: var(--border-card);
    border-radius: var(--radius-lg);
    box-shadow: none;
    padding: var(--pad-card-lg) 44px 36px;
}

/* The lockup on the device-setup card. Placement only — the brand itself is the RCL's. */
.clyffe-setup-lockup {
    align-self: flex-start;
}

/* 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: 960px) {
    .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 ──
   The page is navy now, so the strip stops being a navy box on it and simply sits on the canvas —
   mark, stage and bar above the cards, the way the door puts the brand above its card. Its own
   fill would only read as a slightly different navy. */
.clyffe-setup-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0 var(--space-1) var(--space-2);
    color: var(--cream-90);
}

.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);
    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: 92%;
}

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

/* An answer carries its two thumbs under it (#900): quiet until one is wanted, like the history
   row's pin, and the tapped one reads as on in full-strength navy. */
.clyffe-assistant-answer {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
}

.clyffe-assistant-rating {
    display: flex;
    gap: 2px;
}

.clyffe-assistant-rating .clyffe-assistant-icon-button {
    width: 26px;
    height: 26px;
    opacity: 0.5;
}

.clyffe-assistant-rating .clyffe-assistant-icon-button:hover,
.clyffe-assistant-rating .clyffe-assistant-icon-button:focus-visible {
    opacity: 1;
}

.clyffe-assistant-rating .clyffe-assistant-rating-lit {
    color: var(--navy);
    background: var(--navy-05);
    opacity: 1;
}

/* Where there is a pointer to hover with, a thumb nobody has tapped waits for its answer to be
   hovered or keyboard-focused (epic #965 decision 17), so a long conversation is not a column of
   thumbs. A touch screen has no hover to wait for, so there they stay as they are. The lit thumb
   never waits: a rating given is a fact about the answer. Faded rather than removed, so revealing
   them never moves the answer. */
@media (hover: hover) {
    .clyffe-assistant-rating--reveal .clyffe-assistant-icon-button {
        transition: opacity var(--duration-instant) var(--ease-out), background var(--duration-instant) var(--ease-out), color var(--duration-instant) var(--ease-out);
    }

    .clyffe-assistant-rating--reveal .clyffe-assistant-icon-button:not(.clyffe-assistant-rating-lit) {
        opacity: 0;
    }

    .clyffe-assistant-answer:hover .clyffe-assistant-rating--reveal .clyffe-assistant-icon-button:not(.clyffe-assistant-rating-lit),
    .clyffe-assistant-answer:focus-within .clyffe-assistant-rating--reveal .clyffe-assistant-icon-button:not(.clyffe-assistant-rating-lit) {
        opacity: 0.5;
    }

    .clyffe-assistant-rating--reveal .clyffe-assistant-icon-button:not(.clyffe-assistant-rating-lit):hover,
    .clyffe-assistant-rating--reveal .clyffe-assistant-icon-button:not(.clyffe-assistant-rating-lit):focus-visible {
        opacity: 1;
    }
}

/* 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. Every corner is the panel radius: the
   one square "tail" corner each side used to carry read as a hard edge in a panel that is
   otherwise all soft ones (#871), and the parchment is halved so a long answer is a page they read
   rather than a block they look at. */
.clyffe-bubble {
    border-radius: var(--radius-lg);
}

.clyffe-bubble--clyffe {
    background: var(--parchment-50);
    color: var(--ink);
}

.clyffe-bubble--you {
    background: var(--navy);
    color: var(--parchment);
}

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

/* ── Setup: the logo step (epic #1043) ──
   Up to three of their own logos side by side, the first already picked, with a preview of where
   the chosen one lands. The tiles are the card treatment every other surface uses; picking one
   swaps the hairline for the navy rule rather than adding a fill, so the logo itself stays the
   loudest thing in the tile. */
.clyffe-brand-pick {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.clyffe-brand-pick-tiles {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-3);
}

.clyffe-brand-tile {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--pad-card);
    background: var(--surface-card);
    border: var(--border-card);
    border-radius: var(--radius-lg);
    color: var(--text-body);
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: var(--transition-micro);
}

.clyffe-brand-tile:hover:not(:disabled) {
    border-color: var(--navy-40);
}

.clyffe-brand-tile:focus-visible {
    outline: none;
    box-shadow: var(--focus-shadow);
}

.clyffe-brand-tile--selected,
.clyffe-brand-tile--selected:hover:not(:disabled) {
    border-color: var(--navy);
    box-shadow: inset 0 0 0 1px var(--navy);
}

.clyffe-brand-tile:disabled {
    cursor: default;
}

/* The logo sits on the warm surface so a white logo and a dark one both read. */
.clyffe-brand-tile-preview {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: var(--control-height-lg);
    padding: var(--space-2);
    background: var(--surface-warm);
    border-radius: var(--radius-sm);
}

/* A logo made for a dark background is previewed on ink, because the warm ground would swallow a
   white mark (#1116). Its logo tile elsewhere is the RCL's .clyffe-logo-on-ink. */
.clyffe-brand-tile-preview--on-ink {
    background-color: var(--ink);
}

.clyffe-brand-card-logo,
.clyffe-brand-pick-preview-logo {
    display: inline-flex;
}

.clyffe-brand-tile-img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.clyffe-brand-tile-swatches {
    display: flex;
    gap: var(--space-1);
}

.clyffe-brand-tile-swatch {
    width: var(--space-4);
    height: var(--space-4);
    border: var(--border-card);
    border-radius: var(--radius-pill);
}

.clyffe-brand-tile-name {
    font-weight: var(--weight-body-semibold);
    color: var(--text-strong);
}

.clyffe-brand-tile-source {
    font-size: var(--text-caption-size);
    color: var(--text-muted);
}

/* Where the logo lands: the organisation row under the menu's lockup, drawn on the menu's navy. */
.clyffe-brand-pick-preview {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.clyffe-brand-pick-preview-label {
    font-size: var(--text-caption-size);
    color: var(--text-muted);
}

.clyffe-brand-pick-preview-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    align-self: flex-start;
    padding: var(--space-3) var(--space-4);
    background: var(--surface-inverse);
    border-radius: var(--radius-lg);
    color: var(--text-on-navy);
}

.clyffe-brand-pick-preview-name {
    font-weight: var(--weight-body-medium);
}

/* Settings' "Your logo" card: the chosen logo at the tile's largest step, its source beside it. */
.clyffe-brand-card-chosen {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.clyffe-brand-pick-upload {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}

.clyffe-brand-pick-hint {
    color: var(--text-muted);
}

.clyffe-brand-pick-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

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

    /* Three tiles across a phone are thumbnails nobody can tell apart; one per row they read. */
    .clyffe-brand-pick-tiles {
        grid-template-columns: minmax(0, 1fr);
    }

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

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

.clyffe-step-title {
    font-family: var(--font-display);
    font-size: var(--text-h1-size);
    font-weight: var(--weight-display);
    color: var(--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(--text-body);
    line-height: 1.55;
    margin: 0 0 12px;
}

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

.clyffe-step-title-suffix {
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 500;
    color: var(--text-body);
    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-display);
    font-weight: 500;
    font-size: 36px;
    color: var(--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(--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 {
    opacity: 0.78;
    margin-bottom: 6px;
}

.clyffe-continue-setup-title {
    font-family: var(--font-display);
    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(--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);
}

/* The report's own narrative, inside the page header card (#681). */
.clyffe-report-narrative {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-width: 640px;
}

.clyffe-report-summary {
    font-family: var(--font-body);
    font-size: 15px;
    color: var(--ink);
    margin: 0;
    line-height: 1.5;
}

.clyffe-report-meta {
    font-family: var(--font-body);
    font-size: 13px;
    color: var(--text-body);
    margin: 0;
    line-height: 1.5;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* The coverage reading as a metric: the figure, what it measures beside it, and the one step that
   would raise it under it. It was a percentage inside a sentence, which is the number the Numbers
   rule keeps out of prose and the grade R7 says the reader cannot interpret on its own. */
.clyffe-report-coverage {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 8px;
    margin: 2px 0 0;
}

.clyffe-report-coverage-figure {
    font-family: var(--font-display);
    font-size: var(--text-h1-size);
    font-weight: var(--weight-display);
    letter-spacing: var(--tracking-display);
    line-height: var(--leading-display);
    color: var(--navy);
}

.clyffe-report-coverage-label {
    font-family: var(--font-body);
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-body);
}

.clyffe-report-coverage-step {
    flex-basis: 100%;
    font-family: var(--font-body);
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-body);
}

.clyffe-report-coverage-step a {
    font-weight: var(--weight-body-semibold);
    color: var(--navy);
    text-decoration: none;
}

.clyffe-report-coverage-step a:hover {
    text-decoration: underline;
}

/* ── Home (Clean) ── */

/* What is reporting, part by part, inside the greeting card. Replaced the single coverage
   percentage and its bar (#966): four named statements the reader can act on, rather than one
   number over four unlike things. Each row is a name, how it stands, and — when it is open — the
   one thing that would fix it. */
.hc-health {
    display: grid;
    /* Four across, because there are four and they read as one row. Stepped at the two sanctioned
       breakpoints rather than left to auto-fit, which reflowed the fourth onto a line of its own. */
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 8px 20px;
    list-style: none;
    margin: 0;
    padding: 0;
}

@media (max-width: 960px) {
    .hc-health {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

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

.hc-health-item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 0 10px 12px;
    /* The state reads as a quiet rule down the side rather than a badge: four badges in a row is
       the alarm wall the brand exists to avoid. */
    border-left: 2px solid var(--navy-08);
}

.hc-health-name {
    font-family: var(--font-body);
    font-size: var(--text-eyebrow-size);
    font-weight: var(--weight-body-semibold);
    letter-spacing: var(--tracking-ui);
    color: var(--text-label);
}

.hc-health-reading {
    font-family: var(--font-body);
    font-size: 14px;
    color: var(--ink);
    line-height: 1.4;
}

.hc-health-detail {
    font-family: var(--font-body);
    font-size: 12.5px;
    color: var(--text-body);
    line-height: 1.45;
}

.hc-health-link {
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: var(--weight-body-semibold);
    color: var(--navy);
    text-decoration: none;
    align-self: flex-start;
    margin-top: 2px;
}

.hc-health-link:hover {
    text-decoration: underline;
}

/* Answering. Cove is the brand's secure colour, and the only signal needed is "this one is fine". */
.hc-health-good {
    border-left-color: var(--cove);
}

/* Not answering, and there is something to do. Ember is the brand's one action colour and is kept
   scarce, which is why it marks only this state. */
.hc-health-open {
    border-left-color: var(--ember);
}

/* Blocked on another row, or unread. Neither is the reader's problem to act on here, so neither
   takes a colour. */
.hc-health-waiting,
.hc-health-unknown {
    border-left-color: var(--navy-08);
}

.hc-page {
    max-width: 1080px;
    margin: 0 auto;
    padding: 0 4px 32px;
    display: flex;
    flex-direction: column;
    gap: 28px;
}

.hc-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    background: var(--white);
    border: var(--border-card);
    border-radius: var(--radius-pill);
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 600;
    color: var(--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(--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 {
    color: var(--text-label);
    margin: 0;
}

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

.hc-card-headline-count {
    display: block;
}

/* The rest of the headline's sentence, set at the label's size beneath the count: "2 of 3" is the
   figure and "working fine" is what it counts, and they are one statement rather than a number and
   a caption that could drift apart (#966). */
.hc-card-headline-qualifier {
    display: block;
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: var(--weight-body);
    color: var(--text-body);
    letter-spacing: var(--tracking-body);
    line-height: 1.4;
    margin-top: 6px;
}

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

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

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

.hc-section {
    background: var(--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-display);
    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(--text-body);
}

.hc-section-link {
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 600;
    color: var(--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 var(--duration-instant) var(--ease-out);
}

.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(--ember);
    box-shadow: 0 0 0 3px rgba(214, 99, 32, 0.18);
}

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

.hc-handle-marker-low {
    background: var(--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(--ink);
    line-height: 1.35;
}

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

.hc-handle-arrow {
    color: var(--text-body);
    transition: transform var(--duration-instant) var(--ease-out), color var(--duration-instant) var(--ease-out);
}

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

/* 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(--ink);
    font-family: var(--font-body);
    font-size: 13px;
}

.hc-partial-icon {
    color: var(--text-body);
    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 var(--duration-instant) var(--ease-out);
}

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

.hc-new-item:hover .hc-handle-arrow {
    color: var(--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(--ink);
    line-height: 1.35;
}

.hc-new-subtitle {
    font-family: var(--font-body);
    font-size: 12.5px;
    color: var(--text-body);
    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(--ink);
}

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

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

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

/* ── Products list ────────────────────────────────────────────────
   One card per product the customer would name. Flat per the design system: hairline
   border, 2px radius, never a shadow — the card is a surface, not a floating layer. All
   colour, spacing and type come from the tokens. */

/* Four across on a desktop, two on a tablet, one on a phone (#967). The column counts are
   the only numbers here; the widths they change at are the design system's two
   breakpoints, and nothing else on this page names a width. */
.clyffe-product-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-3);
    /* Cards stretch to their row, which is the grid default and is deliberately not overridden.
       It was `align-items: start` when the grid shipped, and over a real estate that read as
       broken rather than as a list of different-sized things: an app carrying a finding is nearly
       twice the height of one without, so every row had a ragged bottom edge and a gap under the
       short cards. Row by row rather than one height for the whole grid — `grid-auto-rows: 1fr`
       would let the one card with a finding set the height of every other card on the page. */
}

@media (max-width: 960px) {
    .clyffe-product-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

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

.clyffe-product {
    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);
}

/* What a card says is pinned to its two edges: the name and the price at the top, the facts and
   any finding at the bottom. Uniform height alone would leave each card's content floating at a
   different depth, which is the same raggedness one level in; with both ends anchored the slack
   lands in one place and the grid reads as a grid. */
.clyffe-product-grid .clyffe-product-facts {
    margin-top: auto;
}

/* Outside the grid — /finance stacks the same cards in a full-width column — they still
   need the space between them the grid's gap would have given. */
.clyffe-product + .clyffe-product {
    margin-top: var(--space-2);
}

.clyffe-product-grid .clyffe-product + .clyffe-product {
    margin-top: 0;
}

/* A real <a>, so it needs the browser's link chrome stripped back to a plain card head. */
.clyffe-product-head {
    display: flex;
    /* Top, not centre. The logo and the chevron belong beside the name; centred against a stack
       that also carries the caption and the price they drifted down level with the money, which
       reads as a mark against the figure rather than against the app. */
    align-items: flex-start;
    gap: var(--space-3);
    width: 100%;
    color: inherit;
    text-decoration: none;
}

/* A product with no page to open is not a link, so nothing should suggest it is. */
.clyffe-product-head-inert {
    cursor: default;
}

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

/* Everything the head says, stacked beside the logo. One column at every width: a card four
   across has no room to put a price beside a name, and the same layout keeps /finance's
   full-width rows reading the same way rather than growing a second arrangement. */
.clyffe-product-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.clyffe-product-identity {
    min-width: 0;
    display: flex;
    flex-direction: column;
}

/* The app's one line. Two lines at most in a card four across, so a long description never
   pushes the card's facts out of line with its neighbours. */
.clyffe-product-description {
    color: var(--text-muted);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* A column, because MudBlazor renders a caption as an inline <span>: the cost's source and how
   much of the price it covers are two facts, and side by side they ran together into one string
   ("From an invoice1 of 3 accounts reporting costs"). */
.clyffe-product-cost {
    min-width: 0;
    display: flex;
    flex-direction: column;
}


/* Headline facts: seats, people, who used it, the machines, the date it can be acted on by.
   Separated by space alone, not by the hairline dot the full-width row used to carry. In a card
   four across every fact takes its own line, and a dot then either starts a line under the name
   or dangles at the end of the one above — an artifact at every width the grid has. The gap is
   the generous one the design system asks for, so a wide /finance row still reads as separate
   facts. No indent either: there is no room to hang them off the logo's width. */
.clyffe-product-facts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-4);
    font-family: var(--font-body);
    font-size: var(--text-caption-size);
    color: var(--text-body);
    /* A fact that wraps must not leave its last word alone on a line. "…active in the last 14
       days, from sign-ins and use" (#968) is longer than a card four across, and broke with "use"
       stranded under it on nearly every card. Progressive: browsers that do not know the value
       ignore it and wrap as before, so this can only improve the line, never move it. */
    text-wrap: pretty;
}

/* 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);
}

/* A finding's count as a metric: the figure, then what it measures, on a line of its own above
   the sentence that says what it means for them. The count used to sit inside the sentence
   (design-system Numbers rule). The figure weight is shared with the seats-and-people line and the
   spare-seat rows on Finance, which carry their counts the same way. */
.clyffe-insight-metric {
    display: block;
}

.clyffe-insight-figure {
    font-weight: var(--weight-body-semibold);
    color: var(--navy);
}

/* The seats-and-people join on the app's own page, directly under the figures it reconciles.
   Plain surface, not the insight strip's warm one: this explains two numbers, it does not ask
   for anything. */
.clyffe-product-seat-people {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-2) var(--space-3);
}

/* 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);
}

/* "Add a bill" / "Add the agreement" upload controls on the app page: 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);
}

/* One agreement in the organisation-wide list. A hairline between rows rather than a card each:
   the page is read down the deadline column, and boxing every row would break that scan. */
.clyffe-agreement-row + .clyffe-agreement-row {
    border-top: 1px solid var(--border-hairline);
    padding-top: var(--space-2);
}

/* The shape of the deal and where it came from, on one line beneath the row. A middot between them
   rather than two floating captions, so the eye reads one sentence rather than two labels */
.clyffe-agreement-row-footer {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1);
}

.clyffe-agreement-row-footer > * + *::before {
    content: "\00b7";
    margin-right: var(--space-1);
}

/* Dates align right on wide screens and fall under the name on narrow ones, so the deadline never
   crowds the service names beside it */
.clyffe-agreement-row-when {
    text-align: right;
    min-width: 12rem;
}

@media (max-width: 600px) {
    .clyffe-agreement-row-when {
        text-align: left;
    }
}

/* One bill waiting on the arrived-bills screen. Same hairline treatment as the agreements list:
   the page is read down the "what did this pay for?" column, and a card per row would break it. */
.clyffe-arrived-bill + .clyffe-arrived-bill {
    border-top: 1px solid var(--border-hairline);
    padding-top: var(--space-2);
}

/* Who billed them and for what, stacked tightest at the top of the row: the name the supplier gave
   the bill, then the figures read off it, then where it came from. */
.clyffe-arrived-bill-identity {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-width: 0;
}

/* The one control on the row that asks nothing — it opens what the bill says. Pulled back to the
   text column so it reads as part of the bill and not as a second action beside "Check it". */
.clyffe-arrived-bill-toggle {
    margin-left: calc(var(--space-1) * -1);
    margin-top: var(--space-1);
}

/* What the bill charged for, once they open it. Indented under the row it belongs to and held to
   a readable height, because a long carrier bill would otherwise push every other bill off the
   screen. */
.clyffe-arrived-bill-detail {
    margin-top: var(--space-1);
    max-height: 40vh;
    overflow: auto;
    border: 1px solid var(--border-hairline);
    border-radius: 2px;
    padding: 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);
}

/* What the latest bill charged for, line by line (#494). Same treatment as the ledger above it —
   they are read one after the other and a second table styled differently reads as a second
   product. The identifier column never wraps: a phone number broken across two lines stops being
   a phone number. */
.clyffe-bill-services {
    overflow-x: auto;
}

.clyffe-bill-services table {
    width: 100%;
}

.clyffe-bill-services th {
    font-weight: 600;
}

.clyffe-bill-services.clyffe-bill-services tr th,
.clyffe-bill-services.clyffe-bill-services tr td {
    padding: 6px 8px;
    font-size: 0.8125rem;
}

.clyffe-bill-services td:first-child,
.clyffe-bill-services th:first-child {
    white-space: nowrap;
}

.clyffe-bill-services .clyffe-bill-services-amount {
    text-align: right;
    white-space: nowrap;
}

/* The limit of the claim, once under the table. */
.clyffe-bill-services-caveat {
    display: block;
    margin-top: var(--space-2);
}

/* ---- 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(--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;
}

/* A fact whose value is a small table rather than a line: the label sits above it, so the split
   has the full width of the card to lay its columns out in. */
.clyffe-fact-block {
    flex-direction: column;
    align-items: stretch;
}

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

/* Who pays, shown as the working: name, the people behind it, the share, the money. The money
   column is right-aligned because it is a column of figures the reader adds up by eye. */
.clyffe-allocation-review {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-top: var(--space-1);
}

.clyffe-allocation-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto auto;
    align-items: baseline;
    gap: var(--space-3);
}

.clyffe-allocation-row > :last-child {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* One subscription, whatever drafted it. Stacked cards rather than one boxed list: a product can
   hold more than one deal with the same vendor, and the hairline between them is what says which
   facts belong to which. */
.clyffe-subscription-card + .clyffe-subscription-card {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border-hairline);
}

/* The value column: the fact, with either where it came from or the control that would fill it
   sitting under it. Right-aligned with the rest of the fact list's values. */
.clyffe-subscription-fact {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
}

/* An open fact's controls sit where its value would: they are the answer, not an action bar.
   Wrapped rather than truncated — a row offering three ways in on a narrow screen is still three
   ways in, and a hidden one is a route the reader never learns about. */
.clyffe-subscription-fact-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    gap: var(--space-1);
}

.clyffe-subscription-fact-action {
    margin-right: calc(var(--space-2) * -1);
}

/* The forwarding address, revealed under the row that asked for it. Left-aligned inside a
   right-aligned column because an address is read left to right and wraps badly the other way. */
.clyffe-subscription-fact-address {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
    margin-top: var(--space-2);
    padding: var(--space-2);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-sm);
    background: var(--parchment);
    text-align: left;
}

.clyffe-subscription-fact-address-value {
    word-break: break-all;
}

/* One question per row, so a form whose questions are the card's rows reads down the same way the
   card does. */
.clyffe-subscription-editor-row {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.clyffe-subscription-editor-question {
    font-weight: 600;
}

.clyffe-subscription-editor-amount {
    flex: 1 1 60%;
}

.clyffe-subscription-editor-currency {
    flex: 0 1 8rem;
}

/* Everything only the contract says, under its own heading. Indented the same way the disclosure's
   fields are, so the form reads as one column of questions with two asides rather than three
   sections competing for the eye. */
.clyffe-subscription-editor-contract {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.clyffe-subscription-editor-contract-fields {
    padding-left: var(--space-3);
    border-left: 1px solid var(--border-hairline);
}

/* The fields only a person can answer, opened only when asked for: indented under their toggle so
   the four questions above them stay the form's shape. */
.clyffe-subscription-editor-more-fields {
    margin-top: var(--space-2);
    padding-left: var(--space-3);
    border-left: 1px solid var(--border-hairline);
}

/* A cell in the "What you're paying for" table: the fact, with either where it came from or the
   link that would fill it sitting under it. Stacked rather than inline so the source caption never
   pushes a column wider than the figure it belongs to. */
.clyffe-subscription-cell {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}

/* One kind of thing worth acting on. The rule above each group after the first is what says the
   spare seats and the trials are two lists rather than one long one. */
.clyffe-attention-group + .clyffe-attention-group {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border-hairline);
}

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

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

/* What the app is and the link to it, one under the other beneath the title row. */
.clyffe-app-detail-about {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
}

/* 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-people-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-device-row {
    padding: var(--space-1) 0;
}

/* One person, why they are named, and the answer to give about them. The actions sit at the end of
   the row so the names read as a column rather than as a ragged list of buttons; capped for the
   same reason the accounts block is, since a name and two words of answer stretched across 1200px
   stop reading as one row. */
.clyffe-app-people-section {
    max-width: 720px;
}

.clyffe-app-person-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-1) 0;
}

/* One workspace's record of a person: which workspace and the address it publishes on the left,
   when it last saw them sign in on the right. */
.clyffe-person-signin-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) 0;
    border-bottom: var(--border-card);
}

.clyffe-person-signin-row:last-child {
    border-bottom: none;
}

.clyffe-person-app-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    color: inherit;
}

/* The right-hand end of that row: what the app costs on their name, and where the link between
   them stands. Two facts about the same row, so they travel together rather than pushing each
   other to opposite ends of it (#582). */
.clyffe-person-app-standing {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* Colleagues who have no computer on the workspace yet. Two lines each, so the space between
   people is a whole step wider than the space inside one — otherwise the list reads as one
   block of text rather than as one entry per person. */
.clyffe-device-coverage-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.clyffe-device-coverage-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

/* A name with the line that qualifies it underneath — a person over their address, an app over
   when it was last used. One definition, because four lists show the same two lines, and the
   People table's name is a link: an anchor is inline, so without this the address ran straight on
   from the name with nothing between them. */
.clyffe-identity-lines {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
    line-height: var(--leading-ui);
}

.clyffe-app-person-identity {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.clyffe-app-person-actions {
    display: flex;
    align-items: baseline;
    gap: var(--space-1);
    flex-shrink: 0;
}

/* The answers given the other way, sitting under the list they were taken off. Ruled apart with a
   hairline rather than a heading: these names are not a second list of the app's people, they are
   the way back from an answer about them (#696). */
.clyffe-app-people-ruled-out {
    margin-top: var(--space-3);
    padding-top: var(--space-2);
    border-top: 1px solid var(--border-hairline);
}

/* Said above the picker that answers it, so the question reads before the control rather than as a
   label on it. */
.clyffe-app-account-unknown {
    display: block;
    margin-top: var(--space-2);
}

/* 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;
}

/* The money columns hold their amounts on one line, so a caption under one has to be let out of
   that: the sentence saying a month was worked out from a year's bill is longer than the figure
   it sits beneath and would otherwise stretch the whole table (#973). */
.clyffe-seats-table .clyffe-seats-number .clyffe-seats-derived-note {
    display: block;
    white-space: normal;
    max-width: 18ch;
    margin-left: auto;
}

/* 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-entry + .clyffe-cost-trend-entry {
    margin-top: var(--space-3);
}

.clyffe-cost-trend-label {
    display: block;
}

.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(--cove);
    stroke-width: 1.5;
    stroke-linejoin: round;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;
}

.clyffe-cost-trend-point {
    fill: var(--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: 960px) {
    .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;
}

/* Waiting on the reading. Centred and generously spaced rather than a spinner in a corner: the
   dialog has one thing to say while it waits, and after the window it says what to do instead. */
.clyffe-review-reading {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-6) var(--space-4);
    text-align: center;
}

.clyffe-review-reading-detail {
    color: var(--text-muted);
    max-width: 36rem;
}

.clyffe-review-reading-progress {
    width: 12rem;
    margin-top: var(--space-2);
}

/* Said beneath a figure the reader was unsure of. A block of its own, so it starts on its own
   line instead of running onto the end of the field's label (#583). */
.clyffe-review-check {
    display: block;
    margin-top: -6px;
}

/* What is being added, asked beside the button that adds it. Narrow: it is a four-word answer,
   not a search box. */
.clyffe-document-kind {
    min-width: 11rem;
}

/* 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;
}

/* Why a charge counts towards nothing, under the charge it is about. Held to the same quiet
   caption as the rest of the row: the fact is the point, not an alarm about it. */
.clyffe-cost-ledger-not-counted {
    display: block;
}

/* The rule the dates above follow, once under the ledger rather than once per row. */
.clyffe-cost-ledger-dating {
    display: block;
    margin-top: var(--space-2);
}

/* What each charge on a shared bill is for, asked against the charge itself. A service name is
   words rather than a number, so the questions under a shared bill's line get more room than the
   count alone needs — and only there, so a single-product bill is unchanged. */
.clyffe-document-preview-ask:has(.clyffe-review-line-service) {
    max-width: 320px;
}

.clyffe-review-line-service,
.clyffe-review-line-new-service,
.clyffe-review-line-new-service-kind {
    margin-top: var(--space-1);
}

/* What a shared bill charges that nothing has been named for. Sits with the figures it is about,
   spaced away from the field above so it reads as a statement rather than another field's helper. */
.clyffe-review-unassigned,
.clyffe-review-needs-assignment {
    margin-top: var(--space-1);
}

/* 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 or a subscription belongs to. The dropdown, the address box it
   reveals and the helper stack as one block; the rows themselves are the shared picker's, so the
   name-and-address layout has one definition (#846). */
.clyffe-account-choice {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.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. The same question is asked of an unnamed account on
   Reports, so it is asked in the same shape. */
.clyffe-app-account-person,
.clyffe-claim-account,
.clyffe-ticket-assignee {
    max-width: 20rem;
}

/* Pickers that sit in a row beside the button that acts on them. Wide enough to hold a service
   name or an address without the row collapsing to a box nothing reads in, and no wider — the
   button has to stay on the same line as the question it answers. */
.clyffe-bill-subject,
.clyffe-device-primary-user {
    min-width: 15rem;
}

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

/* Marks a help request whose sender signed in on the computer before asking (#421). Cove, the
   calm secure accent — this is a reassuring fact, not an alert, and its absence on other rows
   is deliberately silent rather than a warning. */
.clyffe-requester-verified {
    color: var(--cove);
}

/* The setup page's assurance block (#464). A warm panel rather than a bordered card: it is
   reassurance, not a warning, and the page's one bordered surface is the card it sits in. */
.clyffe-setup-assurance {
    background: var(--parchment-50);
    border-radius: var(--radius-xs);
    padding: 16px;
}

/* The account menu's organisation switch (#428). Each organisation is a submit button on one
   form, dressed like the sign-out button beneath it so the menu reads as one list; the section
   label names the choice once, and the organisation the person is in carries a check. */
.clyffe-nav-account-switch {
    margin: 0;
    padding-bottom: 4px;
}

.clyffe-nav-account-section {
    display: block;
    padding: 10px 16px 4px;
    font-family: var(--font-body);
    font-size: 12px;
    color: var(--text-muted);
}

.clyffe-nav-account-organisation {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 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-organisation:hover:not(:disabled),
.clyffe-nav-account-organisation:focus-visible {
    background: var(--surface-hover, rgba(0, 0, 0, 0.04));
}

.clyffe-nav-account-organisation:disabled {
    cursor: default;
}

.clyffe-nav-account-organisation-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.clyffe-nav-account-organisation-current {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    color: var(--text-strong);
}
