/*
    The admin surface's own stylesheet.

    ══ Why this file is built on Kendo's variables ═══════════════════════════════════════════

    Specification §9.1 chose Telerik over MudBlazor for one deciding reason: Telerik UI for
    Blazor and KendoReact are the same design system, so a tenant's branding colours map once
    rather than once per surface. That argument is only worth anything if the page *around* the
    components is built from the same tokens as the components.

    So nothing here invents a colour. Every value is a `--kendo-*` custom property that the
    theme already publishes on `:root` — 280 of them, including the full primary, base, border
    and error families, the spacing scale, the radii and the elevations. When per-tenant
    branding arrives it will override those tokens in one place, and the header, the forms and
    the grid will all move together. A hand-picked hex here would be the one thing that did not.

    The `--smpl-*` layer below exists so that "which Kendo token does this role use" is answered
    once. Swapping kendo-theme-default for another theme, or renaming a token across a Telerik
    major, then touches that block rather than every rule in the file.

    What that layer does *not* mean is that the theme's own values are accepted. The primary and
    error families, the neutral ink, the borders and the whole type scale are re-declared on
    `:root` below, because the shipped defaults are a 14px body with 10px captions and a single
    grey doing the work of three. Overriding a token is using the system; picking a hex in a rule
    further down the file is leaving it. Everything here does the first.

    ══ Two things the theme does not do for you ══════════════════════════════════════════════

    `.k-body` carries the theme's typography, and App.razor puts it on <body> — but the theme
    leaves `--kendo-font-family` **undefined**, so `.k-body` alone computes to the browser
    default. That was measured, not assumed: with the theme loaded and nothing else, `<body>`
    renders in Times New Roman. The font stack is therefore ours to supply, and it is supplied
    here rather than in a component so that every page gets it.

    The stack is entirely local. Nothing here fetches a webfont, and that is deliberate: a
    stylesheet that reaches fonts.gstatic.com puts a request carrying a referrer on every page
    of a HIPAA platform, and P4c already had to deal with survey-core.css doing exactly that.

    ══ Scope ════════════════════════════════════════════════════════════════════════════════

    Only what the admin surface actually renders today: the layout shell, the two statically
    rendered forms, and the messages they show. Telerik's components style themselves and are
    left alone — there is no rule in this file targeting a `.k-` class, because a page that
    fights its own component library is a page nobody can predict.

    There is no dark mode here. The Kendo dark palette is a different stylesheet, and a page
    that went dark while its grid stayed light would be worse than one that did neither.
*/

/* ── The role each Kendo token plays here ─────────────────────────────────────────────────── */

:root {
    /* The theme publishes `.k-body { font-family: var(--kendo-font-family) }` and never defines
       the variable. Defining it here is what makes that rule do something. */
    --kendo-font-family:
        "Helvetica Neue",
        Helvetica,
        Arial,
        sans-serif;

    /*
        ── The type scale ───────────────────────────────────────────────────────────────────

        The theme ships `--kendo-font-size: 0.875rem` — 14px body, 12px `-sm`, and **10px**
        `-xs`. That was measured in the shipped stylesheet, not assumed. On a surface whose
        users include people who struggle to read, 10px meta text beside grey-on-white labels
        is the single largest accessibility problem the admin surface has, and it is one the
        design review named ahead of every layout complaint.

        The floor is therefore 15px, and it is set here rather than per rule so that Telerik's
        own components inherit it. A grid, a button and a page heading all read from this
        scale; overriding it in one place is the whole reason spec §9.1 chose a themed
        component library.

        Nothing below 0.9375rem is allowed to carry information. `--smpl-font-size-eyebrow` is
        the one exception and it is for *labels only* — an uppercase section marker above a
        control, never content a sentence depends on.
    */
    --kendo-font-size: 1.0625rem;       /* 17px — body */
    --kendo-font-size-md: 1.0625rem;    /* 17px */
    --kendo-font-size-sm: 1rem;         /* 16px — body small */
    --kendo-font-size-xs: 0.9375rem;    /* 15px — meta and captions; the floor */
    --kendo-font-size-lg: 1.1875rem;    /* 19px — section heading */
    --kendo-font-size-xl: 1.5rem;       /* 24px */
    --kendo-font-size-xxs: 0.9375rem;   /* 15px — the theme's 8px has no legitimate use here */

    --kendo-line-height: 1.5;
    --kendo-line-height-md: 1.5;

    /* Labels only, never content. 13px is legible as a word you are not required to read. */
    --smpl-font-size-eyebrow: 0.8125rem;

    /* A display number — a dashboard count — reads as a figure rather than as prose. */
    --smpl-font-size-metric: 2.25rem;

    /* Platform brand — SmplForms navy/blue, until per-tenant branding overrides these tokens.
       Declared on the Kendo primary / error families so Telerik components and the --smpl-*
       aliases below move together (spec §9.1). Default theme coral is replaced here, not fought
       component-by-component. */
    --kendo-color-primary: #1a4f8a;
    --kendo-color-primary-hover: #153f6e;
    --kendo-color-primary-active: #102f52;
    --kendo-color-primary-subtle: #E1EFFF;
    --kendo-color-primary-on-subtle: #1A1C2C;
    --kendo-color-on-primary: #FFFFFF;

    --kendo-color-error: #8a391a;
    --kendo-color-error-hover: #6e2e15;
    --kendo-color-error-active: #52220f;
    --kendo-color-error-subtle: #f5ebe6;
    --kendo-color-error-on-subtle: #8a391a;

    /*
        ── Ink and rules ────────────────────────────────────────────────────────────────────

        Declared on the Kendo neutral family for the same reason the primary family is: the
        page chrome and the components must move together.

        The theme gives `on-app-surface` and `base-on-surface` the *same* value, `#3d3d3d`, so
        "muted" text on this surface has never actually been muted — every level of emphasis
        rendered identically. Three levels are declared here instead, and the contrast ratio
        against white is stated for each because that is the number that decides whether a
        person can read it:

          #1b1d21  15.8:1  headings, values, anything scanned
          #3f4349  10.1:1  body copy inside a card
          #5b5f66   6.6:1  meta and captions — the smallest permitted for text

        Anything lighter than #5b5f66 is decoration and must not carry information. The old
        theme border at rgba(0,0,0,0.08) was too faint to read as the edge of a control, so
        border-alt is strengthened to a value that reads as one.
    */
    --kendo-color-on-app-surface: #1b1d21;
    --kendo-color-base-on-surface: #3f4349;
    --kendo-color-subtle: #5b5f66;
    --kendo-color-border: #e5e4e0;
    --kendo-color-border-alt: #c9c8c3;

    --smpl-surface: var(--kendo-color-app-surface);
    --smpl-surface-raised: var(--kendo-color-base-subtle);

    /* The page behind the cards. Distinct from --smpl-surface, which is the card itself: until
       now both were white, so a panel was bounded only by its border. A card has to sit on
       something for its edge to mean anything. */
    --smpl-page: #f6f6f4;

    --smpl-text: var(--kendo-color-on-app-surface);
    --smpl-text-body: var(--kendo-color-base-on-surface);
    --smpl-text-muted: var(--kendo-color-subtle);
    --smpl-border: var(--kendo-color-border);
    --smpl-border-strong: var(--kendo-color-border-alt);

    /* A hairline between rows inside one card — lighter than the card's own border, because a
       row separator that matches the edge makes every row look like its own card. */
    --smpl-rule: #f1f0ec;
    --smpl-accent: #1a4f8a;
    --smpl-accent-hover: var(--kendo-color-primary-hover);
    --smpl-accent-active: var(--kendo-color-primary-active);
    --smpl-on-accent: var(--kendo-color-on-primary);
    --smpl-danger: #8a391a;
    --smpl-danger-surface: var(--kendo-color-error-subtle);
    --smpl-danger-text: var(--kendo-color-error-on-subtle);

    /* An outlined destructive button: the words in red on white, not white on red. A filled red
       button competes with the primary action for attention and wins, which is the wrong way
       round for the one control on the page you would rather nobody pressed by accident. */
    --smpl-danger-ink: #8c2f2f;
    --smpl-danger-border: #c58a8a;

    /* Status. Never used alone — a colour is always paired with the word it means, because a
       reader who cannot distinguish these two gets nothing from either. */
    --smpl-ok: #3f8f5e;
    --smpl-full: #a8651f;

    /* The smallest a control may be before it stops being a comfortable target. Applied to the
       controls this file owns; Telerik's own controls take their height from the type scale
       above, because reaching inside them would mean styling `.k-` classes, which the top of
       this file rules out. */
    --smpl-control-min-height: 2.75rem;

    /* The height of every button this file draws, and of a status chip beside them: the height of
       Telerik's own medium button (.k-button-md), so a plain button and a Telerik one sitting in
       the same toolbar, row or panel are the same size. Matched from this side because styling a
       `.k-` class is ruled out at the top of this file. Text inputs keep the larger minimum above. */
    --smpl-button-height: 1.875rem;

    /* Drawer chrome — logo charcoal/navy, independent of the light content surface. */
    --smpl-drawer: #1A1C2C;
    --smpl-drawer-raised: #242636;
    --smpl-drawer-text: #E8EEF8;
    --smpl-drawer-muted: #9AA3B5;
    --smpl-drawer-hover: #2C2F42;
    --smpl-drawer-active: #2A3350;

    --smpl-radius: var(--kendo-border-radius-md);
    --smpl-elevation: var(--kendo-elevation-1);

    /* The one measurement that is not a Kendo token, because Kendo has no opinion about it:
       how wide a column of administrative content should be before it stops being readable.
       Wide enough for the forms grid and its five columns, bounded so that a paragraph on a
       large monitor is not one line. */
    --smpl-content-width: 80rem;

    /* How wide a form gets once its fields sit side by side.

       Distinct from the 80rem above, which is the shell's content column, and from
       .smpl-panel-wide's 60rem, which is a table's opt-out with nine consumers. A form laid out in
       one column wants 36rem — past that a label and its input drift apart. A form laid out in two
       wants roughly twice a field, and this is that. */
    --smpl-panel-form-width: 68rem;
}

/* ── Base ─────────────────────────────────────────────────────────────────────────────────── */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    /* The theme's own base size, so a rem here and a rem inside a component agree. */
    font-size: 100%;
}

/*
    Note the background is *not* set here, and an attempt to set it here will silently do
    nothing. The theme ships `.k-body { background-color: var(--kendo-color-app-surface) }`, and
    App.razor puts `k-body` on <body>; a class beats an element selector, so this rule loses. It
    was measured that way — the declaration was written, the page stayed white.

    Changing the token instead is not the answer either: `--kendo-color-app-surface` is what
    every card is painted with, so tinting it tints the cards too and the layering disappears.
    The page tint therefore goes on `.smpl-shell-main`, the content region this file owns.
*/
body {
    margin: 0;
    background: var(--smpl-surface);
    color: var(--smpl-text);
    font-size: var(--kendo-font-size);
    line-height: var(--kendo-line-height);

    /* Not a preference. The sign-in page is short, the forms page is long, and without this the
       scrollbar appears and disappears between them — which shifts the whole layout sideways on
       every navigation. */
    scrollbar-gutter: stable;
}

h1,
h2,
h3 {
    margin: 0 0 var(--kendo-spacing-4);
    font-weight: var(--kendo-font-weight-bold);
    line-height: 1.25;
}

/* The page title. Tightened tracking because a large heading set at normal tracking reads as
   loose; the line-height drops with it, since 1.25 on a 34px line leaves a visible gap under a
   single-line title. */
h1 {
    font-size: 2.125rem;
    line-height: 1.15;
    letter-spacing: -0.02em;
}

h2 {
    font-size: var(--kendo-font-size-lg);
}

/* A card's own sub-heading sits at body size and is distinguished by weight rather than size —
   at 17px body, a heading one step above it competes with the page title for rank. */
h3 {
    font-size: var(--kendo-font-size);
}

p {
    margin: 0 0 var(--kendo-spacing-4);
}

/* Beat Kendo `.k-grid a { color: inherit; text-decoration: none }` (0,1,1).
   Nav items live under `.smpl-shell-drawer` and keep their own undecorated rule. */
.smpl-shell-main a,
.smpl-admin-main a {
    color: var(--smpl-accent);
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

.smpl-shell-main a:hover,
.smpl-admin-main a:hover {
    color: var(--smpl-accent-hover);
}

/* Keyboard focus, everywhere, in the accent colour. `:focus-visible` rather than `:focus` so a
   mouse click does not leave a ring behind — but a keyboard user never loses their place. */
:focus-visible {
    outline: 2px solid var(--smpl-accent);
    outline-offset: 2px;
}

/* FocusOnNavigate moves focus to the page <h1> after every route change (including first load).
   That is correct for assistive tech; the decorative outline around the heading is not — it
   reads as a selected label. Interactive controls keep the ring above. */
h1:focus,
h1:focus-visible {
    outline: none;
}

/* ── Layout shell ─────────────────────────────────────────────────────────────────────────── */

/*
    What is left of the single-row header shell after P73 moved both authenticated surfaces onto
    the drawer+appbar shell further down this file (see "The admin app shell: left drawer +
    appbar"). This class alone survives, because it still backs the one thing that never became
    interactive chrome: AdminLayout's NotAuthorized branch, which is what SignIn.razor and
    SelectTenant.razor render into. Its own form-styling rules follow immediately below.
*/
.smpl-admin-main {
    flex: 1;
    width: 100%;
    max-width: var(--smpl-content-width);
    margin: 0 auto;
    padding: var(--kendo-spacing-8) var(--kendo-spacing-6);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background:
        radial-gradient(ellipse at top, #E1EFFF 0%, transparent 55%),
        var(--smpl-surface);
}

/* Sign-in / tenant-selection card: brand mark, heading and form in one bounded surface. */
.smpl-signin-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--kendo-spacing-3);
    margin-bottom: var(--kendo-spacing-4);
}

.smpl-signin-brand img {
    width: 4.5rem;
    height: 4.5rem;
    border-radius: var(--smpl-radius);
    background: #0B0D14;
}

.smpl-admin-main > h1 {
    width: 100%;
    max-width: 26rem;
    margin-bottom: var(--kendo-spacing-4);
    text-align: center;
}

.smpl-admin-main > .smpl-page-error,
.smpl-admin-main > p {
    width: 100%;
    max-width: 26rem;
}

/* The Microsoft and Google sign-in links under the password form, and the invitation page's
   "Continue with" links. Links styled as buttons (see .smpl-button), full width so the three ways
   in line up; the shell's link underline rule does not reach this region, so it is removed here. */
.smpl-signin-external {
    display: flex;
    flex-direction: column;
    gap: var(--kendo-spacing-2);
    width: 100%;
    max-width: 26rem;
    margin: var(--kendo-spacing-4) 0;
}

.smpl-admin-main a.smpl-button {
    text-decoration: none;
}

/* ── The statically rendered forms ────────────────────────────────────────────────────────── */

/*
    Sign-in and tenant selection are plain HTML rather than Telerik editors, and SignIn.razor
    explains why: issuing a cookie means writing a response header, so those pages cannot be
    interactive, and Telerik's editors are built for a circuit. They therefore get no styling
    from the theme at all, and this block is the whole of their appearance.

    Selected by element inside the main region rather than by class, because these pages carry
    no classes to hook — and adding some to the markup would be changing a page in order to
    style it, when the markup it has is already correct.
*/

.smpl-admin-main form {
    width: 100%;
    max-width: 26rem;
    padding: var(--kendo-spacing-6);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    box-shadow: var(--smpl-elevation);
}

.smpl-admin-main form label {
    display: block;
    margin-bottom: var(--kendo-spacing-1);
    font-weight: var(--kendo-font-weight-bold);
}

/*
    Selected by exclusion rather than by `input[type="text"]`, and the reason is a trap worth
    knowing about: <InputText> renders no `type` attribute at all unless the markup passes one.
    The DOM *property* still reports "text", but an attribute selector matches the attribute,
    so `input[type="text"]` silently skips it. On the sign-in form that produced exactly one
    styled field — the password, which does declare its type — and one browser-default box
    beside it, which looks like a CSS mistake rather than a selector that never matched.

    The negations are wrapped in `:where()` so they contribute no specificity, and that is not
    tidiness either. Five bare `:not([attr])` clauses score five class-level points, which put
    this rule above `input.invalid` and `input:focus-visible` below — so a rejected field kept
    its ordinary border and the rule meant to say otherwise lost silently. `:where()` is zero,
    which leaves this at one class and lets the state rules do their job.
*/
.smpl-admin-main form input:where(:not([type="hidden"]):not([type="radio"]):not([type="checkbox"]):not([type="submit"]):not([type="button"])) {
    width: 100%;
    min-height: var(--smpl-control-min-height);
    margin-bottom: var(--kendo-spacing-4);
    padding: var(--kendo-spacing-2) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border-strong);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    color: inherit;
    font: inherit;
}

.smpl-admin-main form input:focus-visible {
    border-color: var(--smpl-accent);
}

/* Blazor adds `invalid` to a field its validator rejected. It is the only feedback these forms
   currently give: neither carries a <ValidationMessage>, so nothing renders the text — which is
   a gap in the pages rather than in this file, and worth closing when they are next touched. */
.smpl-admin-main form input.invalid {
    border-color: var(--smpl-danger);
}

/* Styled ahead of a consumer, deliberately and only here. `validation-message` is the class
   Blazor emits by name, it has no styling of its own, and the moment either form gains a
   <ValidationMessage> the text would otherwise arrive as unstyled black body copy directly
   under a red-bordered field. Three lines to make that impossible. */
.validation-message {
    display: block;
    margin: calc(-1 * var(--kendo-spacing-3)) 0 var(--kendo-spacing-4);
    color: var(--smpl-danger);
}

/* The tenant radios, which are a label wrapping an input rather than the block labels above. */
/* A tick is a target as much as a button is, and the browser default is 13px square. */
.smpl-admin-main form input[type="radio"],
.smpl-admin-main form input[type="checkbox"] {
    width: 1.125rem;
    height: 1.125rem;
    accent-color: var(--smpl-accent);
}

.smpl-admin-main form label:has(input[type="radio"]) {
    display: flex;
    align-items: center;
    gap: var(--kendo-spacing-2);
    min-height: var(--smpl-control-min-height);
    margin-bottom: var(--kendo-spacing-2);
    padding: var(--kendo-spacing-2) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    font-weight: var(--kendo-font-weight-normal);
    cursor: pointer;
}

.smpl-admin-main form label:has(input[type="radio"]:checked) {
    border-color: var(--smpl-accent);
    background: var(--kendo-color-primary-subtle);
}

.smpl-admin-main form button[type="submit"] {
    min-height: var(--smpl-control-min-height);
    margin-top: var(--kendo-spacing-2);
    padding: var(--kendo-spacing-2) var(--kendo-spacing-5);
    border: 1px solid transparent;
    border-radius: var(--smpl-radius);
    background: var(--smpl-accent);
    color: var(--smpl-on-accent);
    font: inherit;
    font-weight: var(--kendo-font-weight-bold);
    cursor: pointer;
}

.smpl-admin-main form button[type="submit"]:hover {
    background: var(--smpl-accent-hover);
}

.smpl-admin-main form button[type="submit"]:active {
    background: var(--smpl-accent-active);
}

/* ── Messages ─────────────────────────────────────────────────────────────────────────────── */

/*
    The two canonical feedback classes for the whole surface, emitted by exactly one place each —
    the PageMessage and PageError components in Components/Shared. Every screen, sign-in page and
    panel routes its notice or refusal through those, so a second screen cannot drift to a
    near-duplicate spelling: before P74 this rule lived three times over as .smpl-signin-error and
    .smpl-panel-error, identical and separately maintained.

    Both carry `role="alert"` or `role="status"` in the component markup, which is what makes a
    screen reader announce them. The styling is the visual half of the same job and must not be the
    only half — never replace one with the other.
*/

/* A page's own notice: a clamped page size, a row deactivated rather than deleted, a connection
   that opened. Informational rather than a failure, so it is quiet rather than red. */
.smpl-page-message {
    margin-bottom: var(--kendo-spacing-4);
    padding: var(--kendo-spacing-3) var(--kendo-spacing-4);
    border-left: 3px solid var(--smpl-accent);
    background: var(--smpl-surface-raised);
    color: var(--smpl-text-muted);
}

/* The refusal half: a bordered-red panel. A rejected credential and a rejected connection string
   are the same kind of news and read the same. Carries role="alert" in the component markup, which
   is what makes a screen reader announce it; this is the visual half of that job and must never be
   the only half. */
.smpl-page-error {
    margin-bottom: var(--kendo-spacing-4);
    padding: var(--kendo-spacing-3) var(--kendo-spacing-4);
    border: 1px solid var(--smpl-danger);
    border-radius: var(--smpl-radius);
    background: var(--smpl-danger-surface);
    color: var(--smpl-danger-text);
}

/* ── The notifications page ───────────────────────────────────────────────────────────────── */

/*
    A plain list rather than a Telerik grid — Notifications.razor's own remarks say why: the
    screen harness needs a server-side click target for every affordance on the page, and a
    Telerik grid's popup and row templates build themselves client-side.

    Built from the same tokens as everything else here. The unread state is told apart by a left
    accent border plus a small pill badge, rather than by a background colour alone: a colour-only
    difference is the one signal a tenant palette can accidentally erase by choosing an accent
    close to the surface colour, where a border and a labelled badge both survive that.
*/
.smpl-notifications {
    list-style: none;
    margin: var(--kendo-spacing-4) 0 0;
    padding: 0;
}

.smpl-notification {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--kendo-spacing-2) var(--kendo-spacing-3);
    padding: var(--kendo-spacing-3) var(--kendo-spacing-4);
    margin-bottom: var(--kendo-spacing-2);
    border: 1px solid var(--smpl-border);
    border-left: 3px solid transparent;
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface-raised);
}

/* The one thing that tells an unread notification apart from a read one. The border carries the
   accent colour rather than the background, so the row stays readable in the same way every other
   row on the page does — only the edge changes. */
.smpl-notification-unread {
    border-left-color: var(--smpl-accent);
}

.smpl-notification-badge {
    padding: 0 var(--kendo-spacing-2);
    border-radius: 999px;
    background: var(--smpl-accent);
    color: var(--smpl-on-accent);
    font-size: var(--kendo-font-size-xs);
    font-weight: var(--kendo-font-weight-bold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.smpl-notification-title {
    font-weight: var(--kendo-font-weight-bold);
}

.smpl-notification-time {
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-sm);
    margin-left: auto;
}

.smpl-notification-link {
    font-size: var(--kendo-font-size-sm);
}

/* A small pill for a status word beside a heading — the offline marker on an agent-only pipeline's
   Schedules section. Told apart by the danger surface and a label, not by colour alone, the same
   reasoning .smpl-notification-badge carries: a labelled pill survives a tenant palette that a
   colour-only signal would not. Built from tokens like everything else here. */
.smpl-badge {
    display: inline-block;
    margin-left: var(--kendo-spacing-2);
    padding: 0 var(--kendo-spacing-2);
    border-radius: 999px;
    font-size: var(--kendo-font-size-xs);
    font-weight: var(--kendo-font-weight-bold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.smpl-badge-warning {
    background: var(--smpl-danger-surface);
    color: var(--smpl-danger-text);
    border: 1px solid var(--smpl-danger);
}

/* Same shape as .smpl-notifications-empty everywhere else this surface says "there is nothing
   here" — quiet, muted text rather than an empty box with nothing to explain it. */
.smpl-notifications-empty {
    color: var(--smpl-text-muted);
}

/* ── The page title row ───────────────────────────────────────────────────────────────────── */

/*
    Rendered by PageHeader. Wraps rather than shrinks: at a narrow width, or at 200% zoom, the
    actions drop under the title instead of squeezing it to one word per line.
*/
.smpl-page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--kendo-spacing-4);
    margin-bottom: var(--kendo-spacing-6);
}

.smpl-page-header-text h1 {
    margin-bottom: 0;
}

.smpl-page-header-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--kendo-spacing-3);
    margin-top: var(--kendo-spacing-2);
    color: var(--smpl-text-muted);
}

.smpl-page-header-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--kendo-spacing-2);
}

/*
    An anchor that reads as a button.

    A Telerik button cannot be a link, and navigation written as a button that calls NavigateTo is
    a link a person cannot middle-click, copy, or open in a new tab. So the markup stays an <a> and
    only the appearance is borrowed. Text-decoration is removed here because the base rule
    underlines every link inside the shell.
*/
.smpl-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--smpl-button-height);
    padding: var(--kendo-spacing-1) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border-strong);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    color: var(--smpl-text);
    font: inherit;
    font-weight: var(--kendo-font-weight-bold);
    cursor: pointer;
}

.smpl-button:disabled {
    opacity: 0.6;
    cursor: default;
}

.smpl-shell-main a.smpl-button {
    text-decoration: none;
}

.smpl-button:hover {
    background: var(--smpl-surface-raised);
}

.smpl-button-primary,
.smpl-shell-main a.smpl-button-primary {
    border-color: transparent;
    background: var(--smpl-accent);
    color: var(--smpl-on-accent);
}

.smpl-button-primary:hover {
    background: var(--smpl-accent-hover);
}

/* ── The Home dashboard's headline numbers ────────────────────────────────────────────────── */

/*
    Three figures across the top of Home, in an auto-fit grid so they stay side by side on a wide
    monitor and stack when there is no room for that.
*/
.smpl-stat-strip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--kendo-spacing-3);
    margin-bottom: var(--kendo-spacing-6);
}

.smpl-stat {
    display: flex;
    flex-direction: column;
    gap: var(--kendo-spacing-1);
    padding: var(--kendo-spacing-4) var(--kendo-spacing-5);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
}

.smpl-stat-label {
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-xs);
}

/*
    The figure. Tabular digits so a column of these lines up, and a tight line-height because the
    body's 1.5 leaves a visible gap under a single large number.
*/
.smpl-stat-value {
    font-size: var(--smpl-font-size-metric);
    font-weight: var(--kendo-font-weight-bold);
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
    letter-spacing: -0.02em;
}

.smpl-stat-note {
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-xs);
}

/* ── Cards side by side ───────────────────────────────────────────────────────────────────── */

/*
    A row of panels that fills the width instead of stacking in one column. `.smpl-panel` carries a
    36rem measure and a bottom margin, both right for a form standing alone and both wrong inside a
    grid track that has already decided the width — so they are unset for panels in here.
*/
.smpl-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--kendo-spacing-4);
    align-items: start;
}

.smpl-card-grid > .smpl-panel {
    max-width: none;
    margin-bottom: 0;
}

/*
    A denser track for a row of short choices rather than a row of content cards.

    The 20rem above is a measure for a card holding a list — Home's recent responses and pipeline
    runs. A card that is a heading and one sentence does not need it, and inheriting it caps the
    connection chooser at three columns on a wide screen and one column inside a panel. The
    minimum here is the width at which two lines of that sentence still read as a sentence.

    Note the two are independent of the container: a grid can only use the width its parent has,
    so a chooser in a `max-width: 36rem` panel is one column whatever this says. See
    `.smpl-panel-full`.
*/
.smpl-card-grid-compact {
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

/*
    A card whose whole job is to be chosen — the four source types on the connections screen. The
    button carries the source's name and nothing else, because the screen harness matches a button by
    its whole trimmed label and the explanatory copy is a sibling; it is styled as a heading rather
    than as a button so a grid of four does not read as a toolbar.
*/
.smpl-card-action {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: 0;
    padding: 0;
    margin: 0 0 var(--kendo-spacing-2) 0;
    font-family: inherit;
    font-size: var(--kendo-font-size-lg);
    font-weight: var(--kendo-font-weight-bold);
    color: var(--kendo-color-primary);
    cursor: pointer;
}

.smpl-card-action:hover:enabled {
    text-decoration: underline;
}

.smpl-card-action:disabled {
    color: var(--kendo-color-subtle);
    cursor: default;
}

.smpl-card-note {
    margin: 0;
    color: var(--kendo-color-subtle);
}

/*
    A button that reads as a link because what it does is navigate within the page — going back to the
    source-type step, say. A real button rather than an anchor, because it changes this component's
    state and does not address anything.
*/
.smpl-link-action {
    background: none;
    border: 0;
    padding: 0;
    margin-bottom: var(--kendo-spacing-4);
    font: inherit;
    color: var(--kendo-color-primary);
    text-decoration: underline;
    cursor: pointer;
}

.smpl-link-action:disabled {
    color: var(--kendo-color-subtle);
    cursor: default;
}

/* A card heading with something on the right of it — a "see all" link, usually. */
.smpl-card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--kendo-spacing-3);
}

.smpl-card-head h2 {
    margin-bottom: var(--kendo-spacing-4);
}

/* ── Panels, fields and facts ─────────────────────────────────────────────────────────────── */

/*
    The interactive screens are a create panel, sometimes an edit panel, and a grid. A panel is a
    bounded region with a heading, sitting above the grid it feeds.

    Nothing in this block targets a `.k-` class, which is the rule the top of this file states.
    The Telerik editors inside a `.smpl-field` style themselves; what is styled here is the label
    above them and the space around them. That is also why the labels are real <label for="">
    elements pointed at the `Id` each component renders onto its input — the theme has no opinion
    about a form's structure, only about a control's appearance.
*/

/* The card border is the lighter of the two, now that a card sits on a tinted page rather than
   on white: the tint does most of the separating, and the strong border is reserved for the edge
   of something you can type into. */
.smpl-panel {
    max-width: 36rem;
    margin-bottom: var(--kendo-spacing-6);
    padding: var(--kendo-spacing-5) var(--kendo-spacing-6);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    box-shadow: var(--smpl-elevation);
}

.smpl-panel h2 {
    margin-bottom: var(--kendo-spacing-4);
}

/*
    A panel holding a table rather than a form.

    The 36rem above is a measure for fields somebody types into, and it is right for every panel
    on this surface that is a form. The lifecycle slot table is not one: it has three columns of
    prose and a button, and at 36rem its explanations wrap to six lines each and the page becomes
    a column of paragraphs. Widening the base would make every form on the surface too wide to
    read, so the table opts out instead.
*/
.smpl-panel-wide {
    max-width: 60rem;
}

/*
    A panel that takes the width it is given.

    For a panel whose content is a grid rather than a measure of prose: the grid decides how many
    columns fit, and a cap on the panel decides it instead — silently, and in the wrong direction.
    The connection chooser is four short cards and was rendering as one column, because 36rem
    leaves 528px of content and two 20rem tracks need 656px.

    Not a replacement for the 36rem base. That measure is right for everything somebody types
    into, and this is the opt-out for the cases that are not that.
*/
.smpl-panel-full {
    max-width: none;
}

/*
    A panel whose fields sit side by side.

    Deliberately not centred. The grid below it runs the full width of the shell, and a centred
    panel above a full-width table leaves a visible jog where the two left edges disagree — so this
    one is capped and left-aligned, and the two line up.

    Not .smpl-panel-wide, which nine other panels already carry: raising that to fit a two-column
    form would rewiden every table on the surface, and AiDesignChatLayoutTests already asserts that
    one panel does not carry it.
*/
.smpl-panel-form {
    max-width: var(--smpl-panel-form-width);
}

/*
    A row of fields.

    auto-fit rather than a fixed column count, and no media query anywhere: the row collapses to one
    column when the fields would go under 18rem, which is the same idiom .smpl-card-grid uses and the
    reason neither needs a breakpoint.

    A wide field beside two narrow ones is a nested row rather than a grid-column span. A span forces
    a second track to exist at every width, which defeats the collapse above — the wide field would
    stay half-width on a phone. Nesting lets each row collapse on its own.
*/
.smpl-field-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    gap: 0 var(--kendo-spacing-5);
    align-items: start;
    margin-bottom: var(--kendo-spacing-4);
}

/* The inner row of a wide-field-plus-two arrangement. A lower floor, because these are a port and a
   database name rather than a hostname.

   It changes the floor and nothing else. The bottom margin a nested row does not want is removed by
   the nesting rule below, which is where that belongs — a row is tight because of what is in it, and
   flush because of where it is. Keeping both here made a standalone tight row butt against whatever
   followed it, which is what the slot form needs and every use in Connections happens not to. */
.smpl-field-row-tight {
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
}

/* A field inside a row keeps the row's spacing rather than adding its own beneath it. */
.smpl-field-row > .smpl-field,
.smpl-field-row > .smpl-field-row {
    margin-bottom: 0;
}

/*
    A choice made of cards rather than of bare radios.

    The fieldset is the group: it and its legend make this a native radio group, so arrow keys and
    Home/End work without a line of script or a word of ARIA. The border and padding a browser puts
    on a fieldset are removed, because the cards inside already have their own.
*/
.smpl-radio-fieldset {
    margin: 0 0 var(--kendo-spacing-4);
    padding: 0;
    border: 0;
}

.smpl-radio-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: var(--kendo-spacing-3);
}

/*
    One card.

    The label wraps its own input, which is what makes the whole card clickable — and is also why
    the screen harness cannot find these by label and every test addresses them by id.

    font-weight is set explicitly because .smpl-field label makes every label in a field bold, and a
    card is mostly a sentence.
*/
.smpl-radio-card {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--kendo-spacing-1) var(--kendo-spacing-2);
    align-items: start;
    padding: var(--kendo-spacing-3) var(--kendo-spacing-4);
    border: 1px solid var(--smpl-border-strong);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    font-weight: var(--kendo-font-weight-normal);
    cursor: pointer;
}

/* Selection is a server-rendered class rather than :has(:checked), so which card is chosen is in
   the render tree and a test can assert on it. A CSS-only highlight would look identical and be
   invisible to every test on this surface. */
.smpl-radio-card-selected {
    border-color: var(--kendo-color-primary);
    box-shadow: 0 0 0 1px var(--kendo-color-primary);
}

/* The mode that is shown and cannot be chosen. It is teaching material — somebody who used the old
   connection-string box comes looking for integrated security, and this is where they find out. */
.smpl-radio-card-disabled {
    border-style: dashed;
    background: var(--smpl-page);
    color: var(--smpl-text-muted);
    cursor: default;
}

/* Focus lands on the input inside, so the ring has to be drawn by the card around it. */
.smpl-radio-card:focus-within {
    outline: 2px solid var(--kendo-color-primary);
    outline-offset: 2px;
}

.smpl-radio-card-name {
    font-weight: var(--kendo-font-weight-bold);
}

.smpl-radio-card-note {
    grid-column: 2;
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-sm);
}

/*
    A panel holding something shown exactly once — today, an agent's enrolment token.

    Marked out rather than left to look like the panel above it, because the difference between
    "here is a form" and "this value will never be shown again" is the whole message. The border
    is the warning colour the surface already uses for a destructive action; the background stays
    the ordinary raised surface, because a token is not an error and a red block reads as one.
*/
.smpl-panel-secret {
    border-color: var(--kendo-color-warning);
    border-width: 2px;
}

/* The same warning, inside a side panel: the agents screen shows a new agent's one-time token in
   that agent's own panel, where there is no panel border of its own to colour. */
.smpl-sidepanel-secret {
    padding: var(--kendo-spacing-4);
    border: 2px solid var(--kendo-color-warning);
    border-radius: var(--smpl-radius);
}

.smpl-sidepanel-secret h3 {
    margin-top: 0;
}

/*
    The value itself. Monospaced because somebody is going to read it aloud down a telephone or
    type it into a server console, and in a proportional face an l and a 1 are the same shape.

    It wraps rather than scrolls: a token that runs off the edge of its box is one whose last
    characters nobody notices are missing.
*/
.smpl-secret {
    margin-bottom: var(--kendo-spacing-4);
    padding: var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    font-family: var(--kendo-font-family-monospace, monospace);
    font-size: var(--kendo-font-size-md);
    overflow-wrap: anywhere;
    white-space: pre-wrap;
}

/* The explanatory line under a control — why a credential cannot be read back, what an inactive
   pipeline does. Quiet, because it is context rather than instruction. */
.smpl-panel-note {
    margin-bottom: var(--kendo-spacing-4);
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-sm);
}

/* The Home dashboard's recent-activity lists and its needs-attention items. Built from the same
   tokens as every other panel; a plain list rather than a grid because each row is a link, not a
   sortable record. */
.smpl-home-feed {
    list-style: none;
    margin: 0;
    padding: 0;
}

.smpl-home-feed li {
    display: flex;
    justify-content: space-between;
    gap: var(--kendo-spacing-4);
    padding: var(--kendo-spacing-2) 0;
    border-top: 1px solid var(--smpl-border);
}

.smpl-home-feed li:first-child {
    border-top: none;
}

.smpl-home-feed-meta {
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-sm);
}

.smpl-page-attention-item {
    margin: var(--kendo-spacing-2) 0;
}

/* The tab bars — FormDetail's and the respondents screen's: plain buttons over panels (a Telerik
   tab strip is not used here for the same reason Notifications is a plain list — the screen harness
   needs a server-side click target). Built from --smpl-* / --kendo-* tokens so a tenant palette
   moves it.

   Pronounced on purpose. The first cut was muted text over a 3px rule, and on the respondents
   screen people did not notice there was a second tab at all: a tab is navigation, and it has to
   read as a place you can go before anyone will go there. So a tab is set larger and bold, the
   selected one in the accent colour on the card surface over a thick rule, and the bar has a rule
   of its own for the selected tab to sit on. */
.smpl-tab-bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--kendo-spacing-1);
    margin-bottom: var(--kendo-spacing-5);
    border-bottom: 2px solid var(--smpl-border);
}

.smpl-tab {
    appearance: none;
    display: inline-flex;
    align-items: center;
    gap: var(--kendo-spacing-2);
    margin-bottom: -2px;
    background: transparent;
    border: none;
    border-bottom: 4px solid transparent;
    border-radius: var(--smpl-radius) var(--smpl-radius) 0 0;
    min-height: 3rem;
    padding: var(--kendo-spacing-2) var(--kendo-spacing-5);
    font: inherit;
    font-size: var(--kendo-font-size-md);
    font-weight: var(--kendo-font-weight-bold);
    color: var(--smpl-text-muted);
    cursor: pointer;
}

.smpl-tab:hover {
    color: var(--smpl-text);
    background: var(--smpl-surface-raised);
}

.smpl-tab[aria-selected="true"] {
    color: var(--smpl-accent);
    background: var(--smpl-surface);
    border-bottom-color: var(--smpl-accent);
}

/* A count beside a tab's name, drawn from data-count rather than written inside the button: the
   screen harness finds a button by its whole text, so the text stays the tab's name alone. */
.smpl-tab[data-count]:not([data-count=""])::after {
    content: attr(data-count);
    min-width: 1.75rem;
    padding: 0 var(--kendo-spacing-2);
    border: 1px solid var(--smpl-border);
    border-radius: 999px;
    background: var(--smpl-surface-raised);
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-xs);
    line-height: 1.5rem;
    text-align: center;
}

.smpl-tab[aria-selected="true"][data-count]:not([data-count=""])::after {
    border-color: var(--smpl-accent);
    background: var(--smpl-accent);
    color: var(--smpl-on-accent);
}

/* A panel's own message and error lines are the canonical .smpl-page-message / .smpl-page-error
   rules above, rendered by the same PageMessage / PageError components — a panel simply places the
   component beside its section rather than at the top of the page, so the position is a matter of
   where the component sits in the markup, not of a separate rule. The .smpl-panel-message and
   .smpl-panel-error duplicates were retired at P74. */

/* A label standing alone above a control with no <label for=""> of its own to carry
   `.smpl-field label`'s styling — a TelerikRadioGroup, here, for the schedule kind and the
   timezone. Same weight and spacing as that rule, so the two kinds of field line up. */
.smpl-field-label {
    display: block;
    margin-bottom: var(--kendo-spacing-1);
    font-weight: var(--kendo-font-weight-bold);
}

/* The weekly schedule's day checkboxes, one row rather than one column. */
.smpl-days {
    display: flex;
    flex-wrap: wrap;
    gap: var(--kendo-spacing-3);
}

.smpl-day {
    display: inline-flex;
    align-items: center;
    gap: var(--kendo-spacing-1);
    font-weight: var(--kendo-font-weight-normal);
}

/* A cell that holds an absence rather than a value — the em dash in a grid column where a row
   simply has no date. Quiet so it reads as "nothing here" rather than as a value of its own. */
.smpl-muted {
    color: var(--smpl-text-muted);
}

/* A form that is only a button — the agents grid's "Open console", which is a real form post so
   the launch is a top-level navigation. Inline so it sits in the row beside the Manage button. */
.smpl-inline-form {
    display: inline;
}

/* A SHA-256 hash on the Agents page's download list: sixty-four characters with no space to break
   at, in a side panel far narrower. Allowed to wrap anywhere, and monospaced so it reads
   digit by digit against the one a browser shows. */
.smpl-fingerprint {
    font-family: var(--kendo-font-family-monospace, monospace);
    overflow-wrap: anywhere;
}

/* The Agents page's download links: one archive per line, its size and hash beneath. */
.smpl-download-list {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--kendo-spacing-4);
}

.smpl-download-list li {
    margin-bottom: var(--kendo-spacing-3);
}

/* The Agents page's self-test results: an outcome's word carries its colour as well as its meaning,
   so the colour is never the only way to read it. */
.smpl-check-pass {
    color: var(--smpl-ok);
}

.smpl-check-warn {
    color: var(--smpl-full);
    font-weight: var(--kendo-font-weight-bold);
}

.smpl-check-fail {
    color: var(--smpl-danger-ink);
    font-weight: var(--kendo-font-weight-bold);
}

.smpl-field {
    margin-bottom: var(--kendo-spacing-4);
}

.smpl-field label {
    display: block;
    margin-bottom: var(--kendo-spacing-1);
    font-weight: var(--kendo-font-weight-bold);
}

/*
    The native controls a few forms use, given the same box as the Telerik editors beside them.

    <b>What this cannot do is change the date format.</b> A `type="date"` input renders mm/dd/yyyy
    or dd/mm/yyyy according to the browser's own locale, and no stylesheet reaches inside it. The
    slots form is native deliberately — a Telerik date picker builds its calendar in the browser
    and contributes no server-side target, so the screen harness could not drive it — and the cost
    of that decision is a format the page does not control. Worth knowing before somebody files the
    US-looking date as a bug in this file.
*/
.smpl-field input[type="date"],
.smpl-field input[type="time"],
.smpl-field select {
    min-height: var(--smpl-control-min-height);
    padding: var(--kendo-spacing-2) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border-strong);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    color: var(--smpl-text);
    font: inherit;
    font-variant-numeric: tabular-nums;
}

.smpl-field select {
    /* A select sizes to its widest option and then sits oddly narrow next to a text box. */
    min-width: 12rem;
}

/*
    Present to a screen reader, absent to everyone else — a column header whose meaning is obvious
    from the buttons under it but which a table still owes its non-visual readers.
*/
.smpl-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/*
    A plain textarea, styled from the same tokens the Telerik editors read.

    Plain rather than a Telerik control, and the reason is not preference. The recipients box is
    the first field on this surface a test has to type into, and what the screen harness records
    is the `onchange` handler Blazor's own `@bind` puts on an element — so a control whose internal
    input is bound by the component library is a control the harness cannot drive without knowing
    how that library wires itself. A textarea with `@bind` is exactly the primitive being tested.

    Every value here is a `--kendo-*` token rather than a literal, so a tenant palette moves this
    with everything else. That is the whole of what specification §9.1 bought by choosing Telerik,
    and a hand-picked hex is the one thing a palette will not move.
*/
.smpl-textarea {
    display: block;
    width: 100%;
    padding: var(--kendo-spacing-1\.5, 0.375rem) var(--kendo-spacing-2, 0.5rem);
    border: 1px solid var(--kendo-color-border, #ccc);
    border-radius: var(--kendo-border-radius-md, 0.25rem);
    background-color: var(--kendo-color-surface-alt, #fff);
    color: var(--kendo-color-on-app-surface, inherit);
    font-family: var(--kendo-font-family, inherit);
    font-size: var(--kendo-font-size-md, 1rem);
    line-height: var(--kendo-line-height-md, 1.5);
    resize: vertical;
}

.smpl-textarea:focus-visible {
    outline: none;
    border-color: var(--kendo-color-primary, #1a4f8a);
    box-shadow: 0 0 0 2px var(--kendo-color-primary-subtle, rgba(26, 79, 138, 0.25));
}

.smpl-textarea:disabled {
    background-color: var(--kendo-color-base-subtle, #f5f5f5);
    color: var(--smpl-text-muted);
}

/* A checkbox reads left of its label rather than under it, so this one row runs the other way.
   `label` loses its block display and its own margin here, or it would push the text onto a
   second line beside the box. */
.smpl-field-inline {
    display: flex;
    align-items: center;
    gap: var(--kendo-spacing-2);
}

.smpl-field-inline label {
    display: inline;
    margin-bottom: 0;
    font-weight: var(--kendo-font-weight-normal);
}

/* The one-control filter row above a grid. Outside a panel, because it belongs to the grid
   rather than to a form, and given the panel's bottom spacing so the two do not collide. */
.smpl-grid-filter {
    margin-bottom: var(--kendo-spacing-3);
}

/* A row of toggle chips used as a grid filter — the data-report queue's status filter, in place
   of a dropdown the screen harness cannot drive. Built from the Kendo tokens like the rest of the
   page chrome so a tenant palette moves it. */
.smpl-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--kendo-spacing-2);
}

.smpl-chip {
    min-height: var(--smpl-button-height);
    padding: var(--kendo-spacing-1) var(--kendo-spacing-3);
    border: 1px solid var(--kendo-color-border);
    border-radius: var(--kendo-border-radius-md);
    background: var(--kendo-color-app-surface);
    color: var(--kendo-color-on-app-surface);
    font: inherit;
    cursor: pointer;
}

.smpl-chip:hover {
    background: var(--kendo-color-base-hover);
}

.smpl-chip-active {
    border-color: var(--kendo-color-primary);
    background: var(--kendo-color-primary);
    color: var(--kendo-color-on-primary);
}

/*
    Name-and-value facts about one row — node and edge counts, timestamps. A definition list rather
    than a table because that is what it is, and a two-column grid so the values line up without the
    markup having to.

    The value is set against the right edge and a hairline runs between rows. Both are for scanning:
    a column of values on a ragged left edge, with nothing separating one row from the next, is read
    by tracking across from each label. `align-items: baseline` keeps a wrapped two-line value
    aligned with its own label rather than floating against the middle of it.
*/
.smpl-facts {
    display: grid;
    grid-template-columns: minmax(8rem, max-content) 1fr;
    align-items: baseline;
    gap: 0 var(--kendo-spacing-4);
    margin: 0 0 var(--kendo-spacing-4);
}

.smpl-facts dt,
.smpl-facts dd {
    padding: var(--kendo-spacing-2) 0;
    border-top: 1px solid var(--smpl-rule);
}

/* The first row of each column: a rule above the top row would read as the card's own edge. */
.smpl-facts > dt:first-of-type,
.smpl-facts > dt:first-of-type + dd {
    border-top: none;
}

.smpl-facts dt {
    color: var(--smpl-text-muted);
}

.smpl-facts dd {
    margin: 0;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* ── Status, said in a word ───────────────────────────────────────────────────────────────── */

.smpl-status-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--kendo-spacing-2);
    padding: var(--kendo-spacing-1) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border-strong);
    border-radius: 999px;
    background: var(--smpl-surface);
    color: var(--smpl-text);
    font-size: var(--kendo-font-size-xs);
    font-weight: var(--kendo-font-weight-bold);
    white-space: nowrap;
}

.smpl-status-dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 999px;
    background: var(--smpl-text-muted);
}

.smpl-status-pill-ok .smpl-status-dot {
    background: var(--smpl-ok);
}

.smpl-status-pill-warn .smpl-status-dot {
    background: var(--smpl-full);
}

.smpl-status-pill-error .smpl-status-dot {
    background: var(--smpl-danger);
}

/* The resolved value beside a colour swatch. Monospaced digits so the six characters read as a
   code rather than as a word. */
.smpl-swatch-hex {
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
}

/* ── Taking something away ────────────────────────────────────────────────────────────────── */

/*
    A card whose action removes something, and the button inside it.

    Outlined rather than filled: a solid red block competes with the page's primary action and wins,
    which is the wrong way round for the one control you would rather nobody pressed by accident.
    The card is marked by a tinted edge rather than a red background, because the card is not an
    error — it is an ordinary part of the page that happens to be irreversible.
*/
.smpl-panel-danger {
    border-color: var(--smpl-danger-border);
}

.smpl-button-danger,
.smpl-button-danger:hover {
    border-color: var(--smpl-danger-border);
    background: var(--smpl-surface);
    color: var(--smpl-danger-ink);
    font-weight: var(--kendo-font-weight-bold);
}

.smpl-button-danger:hover {
    background: var(--smpl-danger-surface);
}

/*
    A proposal the model has produced and nobody has accepted.

    Set apart from the controls above it with a rule and a tint rather than a border, because it
    is a continuation of the panel rather than a second panel — the two buttons at the bottom of
    it act on the panel's own form.
*/
.smpl-draft {
    margin-top: var(--kendo-spacing-4);
    padding-top: var(--kendo-spacing-4);
    border-top: 1px solid var(--smpl-border);
}

.smpl-draft h3 {
    margin-bottom: var(--kendo-spacing-2);
    font-size: var(--kendo-font-size);
}

/*
    The proposed schema, shown in full.

    Scrolls in both directions inside its own box. A schema is machine-generated JSON with long
    lines, and letting it size the panel would push the Apply button off the side of the page —
    which is the control the whole panel exists to put in front of somebody. Capped in height for
    the same reason: a forty-question form is several hundred lines, and the buttons must not be
    below them.
*/
.smpl-draft-schema {
    max-height: 22rem;
    margin: 0 0 var(--kendo-spacing-4);
    padding: var(--kendo-spacing-3);
    overflow: auto;
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    color: var(--smpl-text);
    font-family: var(--kendo-font-family-monospace, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
    font-size: var(--kendo-font-size-sm);
    white-space: pre;
}

/*
    One patient's answers, question by question.

    The same two-column definition list as .smpl-facts, with the value column allowed to keep its
    own line breaks. ResponseAnswerReader renders a composite answer — a repeating panel, a matrix,
    a multiple-text question — as one line per part, so collapsing that whitespace would run a
    table of answers together into a paragraph and lose which value belonged to which row.

    pre-wrap rather than pre: the line breaks are meaningful and the wrapping is not, and a long
    free-text answer must wrap inside the column rather than widen the page.

    Rows are given room to breathe because this is a screen somebody reads rather than scans, and
    a divider between them because the value above and the label below are otherwise one block of
    text with no edge.
*/
.smpl-answers dt,
.smpl-answers dd {
    padding-bottom: var(--kendo-spacing-2);
    border-bottom: 1px solid var(--smpl-border);
}

.smpl-answers dd {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* An answer whose question is not in the schema it is being read against — the one row on that
   page that is evidence something was lost. Coloured as a warning rather than set in the muted
   grey the rest of the labels use, because it is the opposite of incidental. */
.smpl-answer-flag {
    margin-left: var(--kendo-spacing-2);
    color: var(--kendo-color-warning-on-surface, var(--smpl-text-muted));
    font-size: var(--kendo-font-size-sm);
    font-style: italic;
}

/* A question the respondent skipped. Muted and italic, so it is legible as a statement about the
   record rather than mistaken for an answer somebody gave. */
.smpl-answer-blank {
    color: var(--smpl-text-muted);
    font-style: italic;
}

.smpl-list {
    margin: 0 0 var(--kendo-spacing-4);
    padding-left: var(--kendo-spacing-5);
}

.smpl-list-note {
    color: var(--smpl-text-muted);
}

/*
    The lifecycle slot table on a form's page.

    A table rather than a Telerik grid, and that is a decision. Its rows are the seven members of
    an enum: there is nothing to page, nothing to sort, nothing to filter, and every row needs two
    buttons and a paragraph of explanation in its first cell. A grid would bring paging machinery
    to a fixed list of seven and would fight the cell content the whole way.

    Built from the Kendo tokens like everything else here, so it belongs to the same surface as
    the grids that are grids.

    .smpl-table borrows the same plain rows for any other short read-only list: the directory
    send's preview of who a group reaches is one.
*/
.smpl-slots,
.smpl-table {
    width: 100%;
    margin: 0 0 var(--kendo-spacing-4);
    border-collapse: collapse;
}

.smpl-slots th,
.smpl-slots td,
.smpl-table th,
.smpl-table td {
    padding: var(--kendo-spacing-3) var(--kendo-spacing-3) var(--kendo-spacing-3) 0;
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid var(--smpl-border);
}

.smpl-slots thead th,
.smpl-table thead th {
    font-size: var(--kendo-font-size-sm);
    color: var(--smpl-text-muted);
    font-weight: var(--kendo-font-weight-normal);
    border-bottom-color: var(--smpl-border-strong);
}

/* ── A day of appointments ────────────────────────────────────────────────────────────────── */

/*
    The day heading, as a row of the table. A flat list repeated the date down every row and left
    the reader to find where one day ended; this says it once and carries the day's own count.

    No top border on the first day, because the header row above it already has one.
*/
.smpl-slots .smpl-slot-day th,
.smpl-slots .smpl-slot-day td {
    padding-top: var(--kendo-spacing-5);
    border-bottom: 1px solid var(--smpl-border-strong);
    font-weight: var(--kendo-font-weight-bold);
    vertical-align: baseline;
}

.smpl-slots tbody:first-of-type .smpl-slot-day th,
.smpl-slots tbody:first-of-type .smpl-slot-day td {
    padding-top: var(--kendo-spacing-3);
}

/* "3 slots · 1 open" — a count, so it sits against the right edge with the actions above it. */
.smpl-slot-day-count {
    text-align: right;
    color: var(--smpl-text-muted);
    font-weight: var(--kendo-font-weight-normal);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Within a day the rows are separated by a hairline rather than by the card's own border. */
.smpl-slots tbody tr:not(.smpl-slot-day) td {
    border-bottom-color: var(--smpl-rule);
}

/* When it runs. The heaviest thing in the row, because it is what the eye is looking for. */
.smpl-slot-time {
    font-weight: var(--kendo-font-weight-bold);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.smpl-slot-title,
.smpl-slot-location,
.smpl-slot-booked {
    display: block;
}

.smpl-slot-location {
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-xs);
}

.smpl-slot-booked {
    margin-bottom: var(--kendo-spacing-1);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* The schema key beside the question's own title — context, not the name of the thing. */
.smpl-slot-context {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--kendo-spacing-3);
}

.smpl-slot-context h3 {
    margin-bottom: var(--kendo-spacing-2);
}

.smpl-slot-key {
    padding: var(--kendo-spacing-1) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border);
    border-radius: 999px;
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-xs);
}

/* ── How full something is ────────────────────────────────────────────────────────────────── */

/*
    A capacity bar. Never rendered alone — the count in words sits above it, and this is the part
    that can be removed without losing the answer.
*/
.smpl-meter {
    display: block;
    width: 100%;
    max-width: 10rem;
    height: 6px;
    border-radius: 999px;
    background: var(--smpl-surface-raised);
    overflow: hidden;
}

.smpl-meter-fill {
    display: block;
    height: 100%;
    background: var(--smpl-accent);
}

.smpl-meter-full .smpl-meter-fill {
    background: var(--smpl-full);
}

/* The row header carries the slot's name, what fires it, and — for the four that nothing fires
   yet — why not. Three lines of very different weight, so they stack. */
.smpl-slots tbody th {
    font-weight: var(--kendo-font-weight-bold);
    width: 34%;
}

/*
    The buttons sit at the right of a slot row — but the editor row is one full-width cell that is
    also a last child, and it inherited this. Every label and field in it ended up hard against the
    right margin, which the browser showed and the compiler could not.

    Excluded by selector rather than overridden, because the override loses: this rule is
    .smpl-slots + td + :last-child, and anything scoped to the editor row alone is less specific.
    The negation is wrapped in :where() so it contributes no specificity of its own.
*/
.smpl-slots tr:where(:not(.smpl-slot-editor)) td:last-child {
    text-align: right;
    white-space: nowrap;
}

/*
    The binding editor, in a row of its own directly under the slot it edits.

    It began as a panel below the table, and driving the page in a browser is what showed that up:
    seven rows of prose put the editor eight hundred pixels below the button that opened it, so
    pressing Set on the first row looked like nothing had happened. A row inside the table needs no
    scripting to appear where somebody is already looking.
*/
.smpl-slot-editor > td {
    padding: var(--kendo-spacing-4) var(--kendo-spacing-4) var(--kendo-spacing-5);
    background: var(--smpl-surface);
    border-bottom: 1px solid var(--smpl-border-strong);

    /*
        Undoing the right alignment the last cell of a slot row carries — the buttons live at the
        right of a row, and this cell is also a last child. The first attempt inherited it and put
        every label, field and note in the editor hard against the right margin, which the browser
        showed and nothing else would have.
    */
    text-align: left;
    white-space: normal;
}

.smpl-slot-editor h3 {
    margin: 0 0 var(--kendo-spacing-4);
}

.smpl-slot-note {
    display: block;
    margin-top: var(--kendo-spacing-1);
    font-size: var(--kendo-font-size-sm);
    font-weight: var(--kendo-font-weight-normal);
    color: var(--smpl-text-muted);
}

/*
    A slot nothing fires yet, or a binding onto a pipeline that has been switched off.

    Not the danger colour: neither is a fault, and colouring them as one would train somebody to
    ignore the colour that means a fault. This is the same muted note with enough emphasis to be
    read rather than skipped.
*/
.smpl-slot-note-warning {
    color: var(--smpl-text);
    font-style: italic;
}

/* The way back up from a detail page. Above the heading, because it is navigation rather than
   content, and quiet for the same reason. */
.smpl-breadcrumb {
    margin-bottom: var(--kendo-spacing-3);
    font-size: var(--kendo-font-size-sm);
}

/* ── The pipeline editor canvas ───────────────────────────────────────────────────────────── */

/*
    The one screen on this surface built on a library that is not Telerik — spec section 9.2
    argues Z.Blazor.Diagrams over Telerik's own Diagram, and the canvas mechanics, the ports and
    the link paths all come from that package's two stylesheets, loaded in App.razor.

    What is here is the page around it and the appearance of a node. Node appearance is ours
    because a node is an arbitrary Blazor component rather than a shape carrying text, which is
    the first of the three reasons the spec gives for the exception.

    Still no literal colours. The Kendo tokens the rest of this file uses apply here too, which is
    what will let a tenant's palette reach the canvas at the same moment it reaches the grids.
*/

.smpl-canvas-bar {
    display: flex;
    align-items: center;
    gap: var(--kendo-spacing-4);
    margin-bottom: var(--kendo-spacing-4);
}

.smpl-canvas-bar h1 {
    margin: 0;
}

.smpl-canvas-bar-actions {
    display: flex;
    gap: var(--kendo-spacing-2);
    margin-left: auto;
}

/*
    A height the browser can resolve without knowing the content, and it is a decision rather than
    a shortcut. The diagram measures its container and reports zero until that container has a
    size; inside a flex column whose height depends on its content, the container is zero at first
    measure and the canvas draws nodes at the origin however they were dropped.

    That rule is kept by the editor page filling the window (below): its height is derived from the
    viewport, never from the content, so the first measure is still correct. The fixed 40rem here
    is what any other page that renders this layout gets.
*/
.smpl-canvas-layout {
    display: grid;
    grid-template-columns: 16rem 1fr;
    gap: var(--kendo-spacing-4);
    height: 40rem;
}

.smpl-canvas {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
}

/* The library renders its own root inside this box and needs to fill it. */
.smpl-canvas > .diagram-canvas {
    width: 100%;
    height: 100%;
}

/*
    The editor page fills the window, and follows it as the browser is resized: the palette, the
    canvas and the AI panel all run to the bottom of the screen.

    Done as a chain of flex columns of definite height rather than by guessing how tall the header
    above the canvas is. The page body is exactly the window's height; the main region takes what
    the app bar leaves; every element between it and .smpl-canvas-page — Telerik's root among them,
    whatever it renders — takes all of that; and inside the page the bar and messages keep their own
    height while the split takes the rest. Every link is definite, so the canvas has its size before
    the diagram measures it — the rule the .smpl-canvas-layout comment above exists for.

    Scoped by :has(.smpl-canvas-page) so no other page's shell changes. A window too short for the
    28rem floor scrolls the main region rather than squeezing the canvas to nothing.
*/
.smpl-shell-body:has(.smpl-canvas-page) {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
}

.smpl-shell-body:has(.smpl-canvas-page) > .smpl-shell-main {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

.smpl-shell-main :has(.smpl-canvas-page),
.smpl-canvas-page {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}

.smpl-canvas-page > * {
    flex: none;
}

.smpl-canvas-page > .smpl-design-split-fill {
    flex: 1 1 0;
    min-height: 28rem;
}

.smpl-design-split-fill > .smpl-design-main {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.smpl-design-split-fill .smpl-canvas-layout {
    flex: 1;
    height: auto;
    min-height: 0;
    grid-template-rows: minmax(0, 1fr);
}

.smpl-design-split-fill > .smpl-design-chat {
    min-height: 0;
    overflow-y: auto;
}

.smpl-design-split-fill .smpl-design-chat-body {
    min-height: 8rem;
}

/* ── The palette ──────────────────────────────────────────────────────────────────────────── */

.smpl-palette {
    overflow-y: auto;
    padding: var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface-raised);
}

.smpl-palette-heading {
    margin: var(--kendo-spacing-3) 0 var(--kendo-spacing-2);
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-sm);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.smpl-palette-heading:first-child {
    margin-top: 0;
}

.smpl-palette-item {
    display: block;
    margin-bottom: var(--kendo-spacing-2);
    padding: var(--kendo-spacing-2) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    cursor: grab;
}

.smpl-palette-item:hover {
    border-color: var(--smpl-accent);
}

/* A start node already on the canvas. Shown rather than removed, so the palette does not change
   shape underneath somebody — and the note says why it cannot be dragged. */
.smpl-palette-item-blocked {
    cursor: not-allowed;
    opacity: 0.55;
}

.smpl-palette-item-blocked:hover {
    border-color: var(--smpl-border);
}

.smpl-palette-item-name {
    display: block;
    font-weight: var(--kendo-font-weight-bold);
}

.smpl-palette-item-note {
    display: block;
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-sm);
}

/* ── A node ───────────────────────────────────────────────────────────────────────────────── */

.smpl-node {
    position: relative;
    width: 15rem;
    padding: var(--kendo-spacing-2) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border-strong);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    box-shadow: var(--smpl-elevation);
    font-size: var(--kendo-font-size-sm);
}

/* The amber ring spec section 9.2 names, for a node that runs on an agent. Amber rather than red
   because the definition is not wrong — it will run correctly the day the agent ships. */
.smpl-node-agent {
    border-color: var(--kendo-color-warning);
    box-shadow: 0 0 0 2px var(--kendo-color-warning-subtle);
}

.smpl-node-head {
    display: flex;
    align-items: center;
    gap: var(--kendo-spacing-2);
    margin-bottom: var(--kendo-spacing-1);
}

.smpl-node-type {
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-xs);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.smpl-node-actions {
    display: flex;
    gap: var(--kendo-spacing-1);
    margin-left: auto;
}

.smpl-node-action {
    padding: 0 var(--kendo-spacing-1);
    border: none;
    background: transparent;
    color: var(--smpl-accent);
    font: inherit;
    font-size: var(--kendo-font-size-xs);
    cursor: pointer;
}

.smpl-node-action-remove {
    color: var(--smpl-danger);
}

.smpl-node-label {
    font-weight: var(--kendo-font-weight-bold);
    overflow-wrap: anywhere;
}

.smpl-node-chip {
    display: inline-block;
    margin-top: var(--kendo-spacing-1);
    padding: 0 var(--kendo-spacing-2);
    border-radius: var(--smpl-radius);
    font-size: var(--kendo-font-size-xs);
}

.smpl-node-chip-agent {
    background: var(--kendo-color-warning-subtle);
    color: var(--kendo-color-warning-on-subtle);
}

/*
    A node that genuinely runs on an agent, as against one no agent can run.

    Informational rather than amber. Before P8 those were the same state and one chip served
    both; they are now very different, and an author whose working pipeline is marked in warning
    colours has been told it is broken.
*/
.smpl-node-chip-agent-run {
    background: var(--kendo-color-info-subtle);
    color: var(--kendo-color-info-on-subtle);
}

.smpl-node-chip-unconfigured {
    background: var(--kendo-color-info-subtle);
    color: var(--kendo-color-info-on-subtle);
}

/*
    Ports.

    ══ The library positions none of this, and that is not obvious ═══════════════════════════

    Z.Blazor.Diagrams' own two stylesheets style the canvas, the links and the selection, and
    leave a port entirely to the application: PortRenderer emits
    `<div class="diagram-port left|right|bottom">` with `position: static` and no offsets. So a
    node whose CSS gives ports a size and a colour but no position renders all of them stacked in
    normal flow at the node's left edge, twelve pixels apart — which looks like a rendering bug in
    the library and is a missing rule here. It was exactly that for a while: three ports on a
    branch, all in the same place, and links that therefore all left from the same point.

    The alignment class is the contract. It comes from the PortAlignment the node model passed to
    AddPort, so these three rules and PipelineNodeModel's constructor have to agree — and
    PipelineCanvas reads the alignment back on save to recover a branch's output label, which
    makes the same agreement load-bearing for what gets stored.

    Offset outward by half their own size so a port straddles the node's edge, which is what makes
    it look attached to the node rather than inside it.
*/

.smpl-node .diagram-port {
    position: absolute;
    z-index: 1;
    width: 0.75rem;
    height: 0.75rem;
    border: 2px solid var(--smpl-surface);
    border-radius: 50%;
    background: var(--smpl-accent);

    /* A port is a drag handle, and nothing else on this canvas is. The cursor is the only thing
       that says so before somebody tries. */
    cursor: crosshair;
}

.smpl-node .diagram-port.left {
    top: 50%;
    left: -0.375rem;
    transform: translateY(-50%);
}

.smpl-node .diagram-port.right {
    top: 50%;
    right: -0.375rem;
    transform: translateY(-50%);
}

.smpl-node .diagram-port.bottom {
    bottom: -0.375rem;
    left: 50%;
    transform: translateX(-50%);
}

.smpl-node .diagram-port.top {
    top: -0.375rem;
    left: 50%;
    transform: translateX(-50%);
}

/* Grown on hover, because a twelve-pixel circle is a small target and the feedback is what tells
   somebody they have hold of it. The transform is restated per alignment: it carries the
   centring above, so a bare `scale()` here would drop that and make the port jump on hover. */
.smpl-node .diagram-port.left:hover,
.smpl-node .diagram-port.right:hover {
    transform: translateY(-50%) scale(1.3);
}

.smpl-node .diagram-port.bottom:hover,
.smpl-node .diagram-port.top:hover {
    transform: translateX(-50%) scale(1.3);
}

/* A second or third output — a branch's false, a delivery's failed — told apart from the first by
   colour as well as by position. */
.smpl-node .diagram-port.smpl-node-port-false {
    background: var(--smpl-text-muted);
}

/* A third output — a fetch's empty — in a colour of its own, so the top port is not read as the
   first output's twin. Placed above the node, where nothing else leaves. */
.smpl-node .diagram-port.smpl-node-port-third {
    background: var(--smpl-surface);
    border-color: var(--smpl-text-muted);
}

/* Which output is which, said on the canvas rather than only in the configuration dialog. A
   branch whose two edges are drawn the wrong way round runs and does the opposite of what its
   author meant, and nothing else on screen would say so. Placed by port position, not by output
   name, because PipelineNodePorts assigns positions in declaration order for every type. */
.smpl-node-port-label {
    position: absolute;
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-xs);
}

.smpl-node-port-label-right {
    top: 50%;
    left: calc(100% + 0.75rem);
    transform: translateY(-50%);
}

.smpl-node-port-label-bottom {
    bottom: -1.5rem;
    left: calc(50% + 0.75rem);
}

.smpl-node-port-label-top {
    top: -1.5rem;
    left: calc(50% + 0.75rem);
}

/* A section heading with a control beside it — "Run history" and the button that adds to it.
   The heading keeps its own bottom margin from the h2 rule, so it is zeroed here and carried by
   the row instead; otherwise the button sits proud of the text it belongs with. */
.smpl-section-head {
    display: flex;
    align-items: center;
    gap: var(--kendo-spacing-4);
    margin-bottom: var(--kendo-spacing-4);
}

.smpl-section-head h2 {
    margin-bottom: 0;
}

/* A link out of a section, styled as a control rather than as body copy.
   The content-scoped `a` rule above underlines every anchor; this must beat it. */
.smpl-action-link,
.smpl-shell-main a.smpl-action-link {
    display: inline-block;
    padding: var(--kendo-spacing-1) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-accent);
    border-radius: var(--smpl-radius);
    text-decoration: none;
}

/* ── Narrow viewports ─────────────────────────────────────────────────────────────────────── */

/*
    Not a phone layout — this surface is a desktop tool and its grids assume width. Enough that
    a laptop at a small window, or a tablet, does not lose the sign-out button off the edge.
*/
@media (max-width: 40rem) {
    .smpl-admin-main {
        padding: var(--kendo-spacing-5) var(--kendo-spacing-4);
    }
}

/* ── The platform operations surface ──────────────────────────────────────────────────────── */

/*
    P73 moved the superadmin surface onto the same drawer+appbar shell as the tenant surface (see
    "The admin app shell: left drawer + appbar", further up this file) rather than a second copy
    of the old single-row header. What is left here is the one thing that shell has no equivalent
    for: a word saying which surface an operator is looking at, so a window is identifiable at a
    glance without reading its URL. PlatformLayout's appbar carries this badge where AdminLayout's
    carries the tenant pill.

    There used to be a second difference — a wider content column, because these pages are log
    lines and audit metadata rather than forms — but the drawer+appbar shell caps neither surface's
    main region, so that distinction had nothing left to attach to and was dropped rather than
    carried forward as a rule with no reason.
*/
.smpl-admin-surface {
    padding: var(--kendo-spacing-0\.5) var(--kendo-spacing-2);
    border: 1px solid var(--smpl-border-strong);
    border-radius: var(--smpl-radius);
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-xs);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/*
    Audit metadata and logger categories, rendered verbatim.

    Wrapped rather than clipped: a JSON blob or a fully qualified type name that is cut off is one
    an operator has to select and paste somewhere else to read, and the whole point of the screen
    is that they do not have to leave it.
*/
.smpl-audit-metadata,
.smpl-log-category {
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-xs);
    overflow-wrap: anywhere;
}

/*
    A formatted exception under its message.

    Scrolls rather than wraps. A stack trace is the one thing on these pages whose shape carries
    meaning - frames read down the left edge - and re-wrapping it destroys that.
*/
.smpl-log-exception {
    margin: var(--kendo-spacing-2) 0 0;
    padding: var(--kendo-spacing-2);
    max-height: 14rem;
    overflow: auto;
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface-raised);
    font-size: var(--kendo-font-size-xs);
}

/* The Survey Creator (visual form designer) mounts into this host. A min-height reserves the
   space so the panel does not collapse to zero between first render and the Creator mounting. */
.smpl-designer-host {
    min-height: 600px;
    height: calc(100vh - 14rem);
}

/* Form design / pipeline canvas: main surface left, collapsible AI chat right. */
.smpl-design-split {
    display: flex;
    gap: var(--kendo-spacing-4);
    align-items: stretch;
    min-height: calc(100vh - 10rem);
}

.smpl-design-main {
    flex: 1 1 auto;
    min-width: 0;
}

.smpl-design-chat {
    flex: 0 0 22rem;
    display: flex;
    flex-direction: column;
    gap: var(--kendo-spacing-3);
    max-width: 22rem;
    padding: var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface-raised);
}

.smpl-design-chat-collapsed {
    flex-basis: 3rem;
    max-width: 3rem;
    padding: var(--kendo-spacing-2);
    align-items: center;
}

.smpl-design-chat-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--kendo-spacing-2);
}

.smpl-design-chat-header h2 {
    margin: 0;
    font-size: var(--kendo-font-size-lg);
}

.smpl-design-chat-body {
    flex: 1 1 auto;
    min-height: 12rem;
}

.smpl-design-chat-composer .smpl-textarea {
    width: 100%;
}

.smpl-design-chat-expand,
.smpl-design-chat-collapse {
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    color: var(--smpl-accent);
    cursor: pointer;
    padding: var(--kendo-spacing-1) var(--kendo-spacing-2);
}

.smpl-design-chat-expand {
    writing-mode: vertical-rl;
    text-orientation: mixed;
    height: 100%;
    min-height: 8rem;
}

.smpl-design-chat-draft {
    border-top: 1px solid var(--smpl-border);
    padding-top: var(--kendo-spacing-3);
    display: flex;
    flex-direction: column;
    gap: var(--kendo-spacing-2);
}

/* Empty-grid guidance. From --kendo-* tokens so a tenant palette moves them. */
.smpl-empty-state {
    padding: var(--kendo-spacing-8) var(--kendo-spacing-6);
    text-align: center;
    color: var(--smpl-text-muted);
}
.smpl-empty-state-heading {
    font-weight: var(--kendo-font-weight-bold);
    color: var(--smpl-text);
    margin: 0 0 var(--kendo-spacing-2);
}
.smpl-empty-state-hint { margin: 0 0 var(--kendo-spacing-4); }

/* ── The admin app shell: left drawer + appbar ────────────────────────────────────────────── */

/*
    The shared authenticated chrome for both AdminLayout and PlatformLayout — a fixed nav rail
    and an appbar carrying the breadcrumb, the signed-in identity, and sign-out. AdminLayout adds
    a tenant pill and a notification count PlatformLayout has no equivalent for, since a
    superadmin holds no tenant; PlatformLayout adds the "Platform" surface badge in their place
    (see .smpl-admin-surface, further up this file). It replaces the single-row header the
    .smpl-admin-* rules above still serve for AdminLayout's own unauthenticated forms (sign-in,
    tenant selection) — the one shape neither surface's drawer+appbar chrome can back, because
    issuing a cookie means writing a response header before either shell's interactive-looking
    markup would exist.

    All of it stays statically rendered — see AdminLayout's own remarks on why an interactive
    Drawer cannot sit above a page that has to write an auth cookie. The checkbox-and-label pair
    below is the entire mechanism for the narrow-viewport toggle, and it needs no script: a
    checked checkbox is state the browser already keeps for free.
*/

.smpl-shell {
    display: flex;
    min-height: 100vh;
}

.smpl-shell-drawer {
    width: 240px;
    flex-shrink: 0;
    background: var(--smpl-drawer);
    border-right: 1px solid var(--smpl-drawer-raised);
    padding: var(--kendo-spacing-3) 0;
    color: var(--smpl-drawer-text);
}

.smpl-shell-brand {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: var(--kendo-font-weight-bold);
    font-size: var(--kendo-font-size-lg, 1.125rem);
    line-height: 1;
    color: var(--smpl-drawer-text);
    padding: var(--kendo-spacing-2) var(--kendo-spacing-4) var(--kendo-spacing-5);
}

.smpl-shell-brand img {
    width: 2rem;
    height: 2rem;
    border-radius: 0.35rem;
    flex-shrink: 0;
    background: #0B0D14;
}

/* Section labels in the drawer — muted, tracked, and hairline-separated so they read as
   groups, not peers of `.smpl-nav-item`. */
.smpl-nav-group {
    text-transform: uppercase;
    letter-spacing: 0.1em;
    font-size: var(--smpl-font-size-eyebrow);
    font-weight: var(--kendo-font-weight-bold);
    color: var(--smpl-drawer-muted);
    padding: var(--kendo-spacing-5) var(--kendo-spacing-4) var(--kendo-spacing-2);
    margin-top: var(--kendo-spacing-3);
    border-top: 1px solid var(--smpl-drawer-raised);
    pointer-events: none;
    user-select: none;
}

.smpl-nav-item {
    display: block;
    padding: var(--kendo-spacing-2) var(--kendo-spacing-4);
    color: var(--smpl-drawer-text);
    text-decoration: none;
    border-left: 3px solid transparent;
}

.smpl-nav-item:hover {
    background: var(--smpl-drawer-hover);
    color: #FFFFFF;
}

/* NavLink adds `active` itself; the Match on each link decides when. */
.smpl-nav-item.active {
    background: var(--smpl-drawer-active);
    color: #FFFFFF;
    font-weight: var(--kendo-font-weight-bold);
    border-left-color: var(--smpl-accent);
    padding-left: var(--kendo-spacing-4);
}

.smpl-shell-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.smpl-appbar {
    display: flex;
    align-items: center;
    gap: var(--kendo-spacing-4);
    padding: var(--kendo-spacing-3) var(--kendo-spacing-6);
    background: var(--smpl-surface);
    border-bottom: 1px solid var(--smpl-border);
}

.smpl-appbar-spacer {
    flex: 1;
}

/* Shares its name with the "back to list" links on the detail pages further up this file — both
   are secondary wayfinding text, and this rule adds only a colour neither of those six pages'
   own <p class="smpl-breadcrumb"> rule sets. Their <a> children keep the accent colour from the
   base `a` rule regardless, because an element's own explicit rule always wins over an inherited
   one, so this is confirmed to add nothing visible to them. */
.smpl-breadcrumb {
    color: var(--smpl-text-muted);
}

.smpl-tenant-pill {
    background: var(--kendo-color-primary-subtle);
    color: var(--kendo-color-primary-on-subtle);
    padding: var(--kendo-spacing-1) var(--kendo-spacing-3);
    border-radius: var(--smpl-radius);
}

.smpl-appbar-user {
    color: var(--smpl-text-muted);
}

/* The surface's one statement that its timestamps are UTC. Quiet, because it is a standing fact
   rather than a notice — but it is text, so it stays at the 15px floor rather than shrinking to
   the size the phrase's importance might suggest. */
.smpl-appbar-zone {
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-xs);
}

/* The page behind the cards — see the note on `body` for why the tint lands here rather than
   there. The appbar and the drawer paint themselves, so this is the whole of the content area. */
.smpl-shell-main {
    padding: var(--kendo-spacing-6);
    flex: 1;
    background: var(--smpl-page);
}

/* The unauthenticated branch's main also carries .smpl-admin-main for its form styling — this
   just centers it the same way, in case that class is ever dropped from one without the other. */
.smpl-shell-main-plain {
    margin: 0 auto;
}

.smpl-drawer-toggle {
    position: absolute;
    left: -9999px;
}

.smpl-drawer-button {
    display: none;
    cursor: pointer;
}

@media (max-width: 900px) {
    .smpl-shell-drawer {
        display: none;
    }

    .smpl-drawer-toggle:checked ~ .smpl-shell-drawer {
        display: block;
    }

    .smpl-drawer-button {
        display: inline-block;
    }
}

.smpl-signout {
    background: none;
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    padding: var(--kendo-spacing-1) var(--kendo-spacing-3);
    color: var(--smpl-text);
    cursor: pointer;
}

/* ── The respondents screen: a full-width list with a side panel ───────────────────────────── */

/* The list and the panel beside it. The panel pushes the list narrower rather than covering it,
   so the row a person pressed stays in view and pressing another row switches to them. */
.smpl-workspace {
    display: flex;
    align-items: flex-start;
    gap: var(--kendo-spacing-4);
}

.smpl-workspace-main {
    flex: 1;
    min-width: 0;
    padding: 0;
    overflow: hidden;
}

.smpl-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--kendo-spacing-3) var(--kendo-spacing-5);
    padding: var(--kendo-spacing-4);
    border-bottom: 1px solid var(--smpl-border);
}

.smpl-toolbar-search {
    display: flex;
    gap: var(--kendo-spacing-2);
    flex: 0 1 22rem;
    min-width: 14rem;
}

.smpl-toolbar-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--kendo-spacing-1);
}

.smpl-toolbar-label {
    margin-right: var(--kendo-spacing-1);
    font-size: var(--kendo-font-size-xs);
    font-weight: var(--kendo-font-weight-bold);
    color: var(--smpl-text-muted);
}

.smpl-toolbar-spacer {
    flex: 1;
}

/* A second row the toolbar opens: more filters, or the column chooser. */
.smpl-toolbar-more {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--kendo-spacing-3) var(--kendo-spacing-5);
    padding: var(--kendo-spacing-3) var(--kendo-spacing-4);
    border-bottom: 1px solid var(--smpl-border);
    background: var(--smpl-surface-raised);
}

.smpl-toolbar-more .smpl-panel-note {
    flex-basis: 100%;
    margin: 0;
}

.smpl-button-small {
    min-height: var(--smpl-button-height);
    padding: var(--kendo-spacing-1) var(--kendo-spacing-3);
    font-size: var(--kendo-font-size-sm);
}

.smpl-button-add::before {
    content: "+";
    margin-right: var(--kendo-spacing-2);
    font-size: 1.2em;
    line-height: 1;
}

.smpl-button-disclose::after {
    content: "\25BE";
    margin-left: var(--kendo-spacing-2);
}

.smpl-button-disclose[aria-expanded="true"]::after {
    content: "\25B4";
}

.smpl-button-link {
    border-color: transparent;
    background: transparent;
    color: var(--smpl-accent);
}

/* The filters in force, each a pill that removes itself when pressed. */
.smpl-filter-pills {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--kendo-spacing-2);
    padding: var(--kendo-spacing-2) var(--kendo-spacing-4);
    border-bottom: 1px solid var(--smpl-border);
}

.smpl-filter-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--kendo-spacing-2);
    padding: var(--kendo-spacing-1) var(--kendo-spacing-3);
    border: 1px solid transparent;
    border-radius: 999px;
    background: var(--smpl-surface-raised);
    color: var(--smpl-accent);
    font: inherit;
    font-size: var(--kendo-font-size-sm);
    font-weight: var(--kendo-font-weight-bold);
    cursor: pointer;
}

.smpl-filter-pill::after {
    content: "\2715";
    font-size: 0.8em;
}

.smpl-filter-pill:hover {
    border-color: var(--smpl-accent);
}

/* A grid inside a card that already has an edge: the grid's own border would draw a second one. */
.smpl-workspace-main > .telerik-blazor {
    border: none;
}

.smpl-row-selected > td {
    background: var(--smpl-surface-raised);
}

.smpl-row-selected > td:first-child {
    box-shadow: inset 3px 0 0 var(--smpl-accent);
}

/* A short word naming what kind of thing a row is — an audience, a field's kind. Not a status:
   that is .smpl-status-pill. */
.smpl-tag {
    display: inline-block;
    padding: 0 var(--kendo-spacing-2);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface-raised);
    color: var(--smpl-text-body);
    font-size: var(--kendo-font-size-xs);
    line-height: 1.5rem;
    white-space: nowrap;
}

.smpl-tag-employee {
    border-color: var(--smpl-accent);
    color: var(--smpl-accent);
}

/* The side panel: a header, a body that scrolls on its own, and a footer that stays put so the
   button that saves is never scrolled away from.

   Always the height of the window, not the height of its content, and it follows the window as
   the browser is resized. A short panel therefore still reaches the bottom of the screen, with its
   empty space above the footer, so the buttons are always in the same place. `100vh` first as the
   fallback for a browser without `dvh`; `dvh` second because a phone's collapsing address bar
   changes the visible height and `vh` does not follow it. */
.smpl-sidepanel {
    position: sticky;
    top: var(--kendo-spacing-4);
    display: flex;
    flex-direction: column;
    flex: none;
    width: 28rem;
    height: calc(100vh - 2 * var(--kendo-spacing-4));
    height: calc(100dvh - 2 * var(--kendo-spacing-4));
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    box-shadow: var(--smpl-elevation);
}

.smpl-sidepanel-wide {
    width: 40rem;
}

/* An agent's panel: a list of short facts and a few buttons, so it leaves the grid the room. */
.smpl-sidepanel-narrow {
    width: 22rem;
}

/* A grid cell that stays on one line: a machine name, a version, a row's buttons. A value too long
   for its column is cut with an ellipsis, and the cell's title carries the whole of it. */
.smpl-nowrap {
    display: block;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* A category drawn in its place in the tree: indented one step for each level below the first,
   with a branch mark in front of anything that has a parent. The depth arrives as --depth on the
   element, because a level is data and an indent per class would cap the tree at however many
   classes somebody wrote. */
.smpl-tree-name {
    display: inline-flex;
    align-items: baseline;
    gap: var(--kendo-spacing-2);
    padding-left: calc(max(var(--depth, 0) - 1, 0) * 1.5rem);
}

.smpl-tree-branch {
    color: var(--smpl-text-muted);
}

/* The eyebrow over each group of source cards on the new connection page: Databases, Files, APIs. */
.smpl-source-group {
    margin: var(--kendo-spacing-5) 0 var(--kendo-spacing-2);
    font-size: var(--smpl-font-size-eyebrow);
    font-weight: var(--kendo-font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--smpl-text-muted);
}

/* What a role may do, one area to a row, under the role cards. The area column is narrow and fixed
   so the levels line up down the table whichever role is chosen. */
.smpl-role-capabilities th {
    width: 12rem;
    color: var(--smpl-text);
    font-weight: var(--kendo-font-weight-bold);
}

/* A row's buttons, at the right edge of the grid. The column holding them is fitted to them by
   GridAutoFit and is the last one, so the buttons sit flush right whatever else the row carries. */
.smpl-row-actions {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--kendo-spacing-2);
}

.smpl-sidepanel-head {
    display: flex;
    align-items: flex-start;
    gap: var(--kendo-spacing-3);
    padding: var(--kendo-spacing-4) var(--kendo-spacing-5);
    border-bottom: 1px solid var(--smpl-border);
}

.smpl-sidepanel-title {
    flex: 1;
    min-width: 0;
}

.smpl-sidepanel-title h2 {
    margin: 0;
}

.smpl-sidepanel-title .smpl-panel-note {
    margin: var(--kendo-spacing-1) 0 0;
}

.smpl-sidepanel-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--kendo-spacing-2);
    margin-top: var(--kendo-spacing-1);
    color: var(--smpl-text-muted);
    overflow-wrap: anywhere;
}

.smpl-sidepanel-close {
    flex: none;
    width: 2.25rem;
    height: 2.25rem;
    border: none;
    border-radius: var(--smpl-radius);
    background: transparent;
    color: var(--smpl-text-muted);
    cursor: pointer;
}

.smpl-sidepanel-close::before {
    content: "\2715";
    font-size: 1.1rem;
}

.smpl-sidepanel-close:hover {
    background: var(--smpl-surface-raised);
    color: var(--smpl-text);
}

.smpl-sidepanel-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0 var(--kendo-spacing-5);
}

.smpl-sidepanel-section {
    padding: var(--kendo-spacing-4) 0;
    border-bottom: 1px solid var(--smpl-rule);
}

.smpl-sidepanel-section:last-child {
    border-bottom: none;
}

.smpl-sidepanel-section h3 {
    margin: 0 0 var(--kendo-spacing-3);
    font-size: var(--kendo-font-size-xs);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--smpl-text-muted);
}

.smpl-sidepanel-section .smpl-field-row {
    margin-bottom: 0;
}

.smpl-sidepanel-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--kendo-spacing-2);
}

.smpl-sidepanel-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--kendo-spacing-2);
    padding: var(--kendo-spacing-3) var(--kendo-spacing-5);
    border-top: 1px solid var(--smpl-border);
}

.smpl-sidepanel-hint {
    margin-right: auto;
    font-size: var(--kendo-font-size-sm);
    color: var(--smpl-text-muted);
}

/* The numbered steps of an import: which one is showing, and which are done. */
.smpl-steps {
    display: flex;
    gap: var(--kendo-spacing-4);
    margin: 0;
    padding: var(--kendo-spacing-3) var(--kendo-spacing-5);
    border-bottom: 1px solid var(--smpl-border);
    list-style: none;
}

.smpl-step {
    display: flex;
    align-items: center;
    gap: var(--kendo-spacing-2);
    font-size: var(--kendo-font-size-sm);
    font-weight: var(--kendo-font-weight-bold);
    color: var(--smpl-text-muted);
}

.smpl-step-number {
    display: grid;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    border: 2px solid var(--smpl-border-strong);
    border-radius: 999px;
    font-size: var(--kendo-font-size-xs);
}

.smpl-step-current {
    color: var(--smpl-accent);
}

.smpl-step-current .smpl-step-number {
    border-color: var(--smpl-accent);
    background: var(--smpl-accent);
    color: var(--smpl-on-accent);
}

.smpl-step-done {
    color: var(--smpl-ok);
}

.smpl-step-done .smpl-step-number {
    border-color: var(--smpl-ok);
    background: var(--smpl-ok);
    color: var(--smpl-on-accent);
}

.smpl-disclosure {
    margin: var(--kendo-spacing-4) 0;
    font-size: var(--kendo-font-size-sm);
    color: var(--smpl-text-muted);
}

.smpl-disclosure summary {
    color: var(--smpl-accent);
    font-weight: var(--kendo-font-weight-bold);
    cursor: pointer;
}

.smpl-disclosure ul,
.smpl-refusals {
    margin: var(--kendo-spacing-2) 0 0;
    padding-left: var(--kendo-spacing-5);
}

/* The fields tab: the list on the left, the editor beside it. */
.smpl-split {
    display: grid;
    grid-template-columns: minmax(18rem, 24rem) minmax(0, 1fr);
    gap: var(--kendo-spacing-4);
    align-items: start;
}

.smpl-split > .smpl-panel {
    margin-bottom: 0;
}

.smpl-split-head {
    display: flex;
    align-items: center;
    gap: var(--kendo-spacing-3);
    margin-bottom: var(--kendo-spacing-3);
}

.smpl-split-head h2 {
    flex: 1;
    margin: 0;
}

.smpl-field-list td {
    vertical-align: middle;
}

.smpl-field-list-name {
    display: block;
    font-weight: var(--kendo-font-weight-bold);
    color: var(--smpl-text);
}

.smpl-field-list-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--kendo-spacing-1);
    margin-top: var(--kendo-spacing-1);
}

.smpl-field-list-choices {
    display: block;
    margin-top: var(--kendo-spacing-1);
    font-size: var(--kendo-font-size-sm);
    color: var(--smpl-text-muted);
}

.smpl-split-editor {
    padding: 0;
}

.smpl-split-editor-body {
    padding: var(--kendo-spacing-5) var(--kendo-spacing-6);
}

.smpl-split-editor-body h2 {
    margin-top: 0;
}

.smpl-split-editor-foot {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--kendo-spacing-2);
    padding: var(--kendo-spacing-3) var(--kendo-spacing-6);
    border-top: 1px solid var(--smpl-border);
}

.smpl-split-editor-foot-start {
    margin-right: auto;
}

.smpl-inline-field {
    display: flex;
    gap: var(--kendo-spacing-2);
}

/* ── The pipeline screens: the respondents layout, applied to the list and to one pipeline ───── */

/* A list row's last run: its status pill and when, on one line. */
.smpl-last-run {
    display: inline-flex;
    flex-wrap: nowrap;
    white-space: nowrap;
    align-items: center;
    gap: var(--kendo-spacing-2);
}

/* One pipeline's header: its name, its state and its event on the left; Open the editor and Run
   now on the right, above every tab, because both are wanted from every one of them. */
.smpl-detail-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--kendo-spacing-3) var(--kendo-spacing-5);
    margin-bottom: var(--kendo-spacing-2);
}

.smpl-detail-title {
    flex: 1 1 24rem;
    min-width: 0;
}

.smpl-detail-name {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--kendo-spacing-3);
}

.smpl-detail-name h1 {
    margin: 0;
    overflow-wrap: anywhere;
}

.smpl-detail-title .smpl-panel-note {
    margin: var(--kendo-spacing-2) 0 0;
}

.smpl-detail-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--kendo-spacing-2);
}

/* The tab beside whichever side panel is open. */
.smpl-detail-main {
    flex: 1;
    min-width: 0;
}

.smpl-tabpanel-body {
    padding: var(--kendo-spacing-3) var(--kendo-spacing-4) 0;
}

.smpl-tabpanel-body:empty {
    display: none;
}

/* A section heading that sits in a toolbar rather than above it. */
.smpl-toolbar-title,
.smpl-toolbar-heading h2 {
    margin: 0;
    font-size: var(--kendo-font-size-lg);
}

.smpl-toolbar-heading .smpl-panel-note {
    margin: var(--kendo-spacing-1) 0 0;
}

.smpl-toolbar-note {
    margin: 0;
    padding: var(--kendo-spacing-2) var(--kendo-spacing-4);
    border-bottom: 1px solid var(--smpl-border);
}

/* The Overview's facts, side by side in one strip rather than as tiles: these are facts to read,
   not figures to compare. */
.smpl-facts-strip {
    display: flex;
    flex-wrap: wrap;
    margin: 0 0 var(--kendo-spacing-5);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
}

.smpl-facts-strip > div {
    flex: 1 1 10rem;
    padding: var(--kendo-spacing-3) var(--kendo-spacing-4);
    border-right: 1px solid var(--smpl-rule);
}

.smpl-facts-strip > div:last-child {
    border-right: none;
}

.smpl-facts-strip dt {
    font-size: var(--smpl-font-size-eyebrow);
    font-weight: var(--kendo-font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--smpl-text-muted);
}

.smpl-facts-strip dd {
    margin: var(--kendo-spacing-1) 0 0;
    font-weight: var(--kendo-font-weight-bold);
    font-variant-numeric: tabular-nums;
}

.smpl-overview-columns {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--kendo-spacing-4);
}

.smpl-overview-columns > .smpl-panel,
.smpl-settings > .smpl-panel {
    max-width: none;
    margin-bottom: 0;
}

.smpl-settings {
    display: grid;
    gap: var(--kendo-spacing-4);
    max-width: var(--smpl-panel-form-width);
}

.smpl-next-runs {
    margin: var(--kendo-spacing-3) 0 0;
    padding: 0;
    list-style: none;
}

.smpl-next-runs li {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--kendo-spacing-1) var(--kendo-spacing-4);
    padding: var(--kendo-spacing-2) 0;
    border-top: 1px solid var(--smpl-rule);
    font-variant-numeric: tabular-nums;
}

.smpl-next-runs li:first-child {
    border-top: none;
}

.smpl-schedule-ownership p {
    margin: 0 0 var(--kendo-spacing-1);
}

/* Why a run stopped, at the top of its panel: the step, then the runner's own sentence. */
.smpl-run-failure {
    padding: var(--kendo-spacing-3) var(--kendo-spacing-4);
    border: 1px solid var(--smpl-danger-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-danger-surface);
    color: var(--smpl-danger-text);
}

.smpl-run-failure p {
    margin: 0;
}

.smpl-run-failure p + p {
    margin-top: var(--kendo-spacing-1);
}

.smpl-run-failure-step {
    font-weight: var(--kendo-font-weight-bold);
}

/* An identifier somebody copies into a support request: monospaced, and allowed to wrap. */
.smpl-code {
    font-family: var(--kendo-font-family-monospace, monospace);
    font-size: var(--kendo-font-size-sm);
    overflow-wrap: anywhere;
}

@media (max-width: 1100px) {
    .smpl-sidepanel,
    .smpl-sidepanel-wide {
        width: 24rem;
    }

    /* Already narrower than the rule above; repeated after it so that rule does not widen it. */
    .smpl-sidepanel-narrow {
        width: 22rem;
    }

    .smpl-split {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* On a phone the side panel covers the screen rather than squeezing the list to nothing. */
@media (max-width: 900px) {
    .smpl-sidepanel,
    .smpl-sidepanel-wide {
        position: fixed;
        inset: 0;
        z-index: 20;
        width: auto;
        height: auto;
        max-height: none;
        border-radius: 0;
    }

    .smpl-toolbar-search {
        flex-basis: 100%;
    }
}

/* The node configuration dialog's two columns: the editors on the left, the variable picker on the
   right. Stacks under the picker on a narrow window rather than scrolling sideways. */
.smpl-node-config {
    display: flex;
    gap: var(--kendo-spacing-6);
    align-items: flex-start;
}

.smpl-node-config-fields {
    flex: 1 1 0;
    min-width: 0;
}

.smpl-node-config-picker {
    flex: 0 0 15rem;
    align-self: stretch;
    border-left: 1px solid var(--smpl-border);
    padding-left: var(--kendo-spacing-6);
}

@media (max-width: 45rem) {
    .smpl-node-config {
        flex-direction: column;
    }

    .smpl-node-config-picker {
        flex-basis: auto;
        border-left: none;
        border-top: 1px solid var(--smpl-border);
        padding-left: 0;
        padding-top: var(--kendo-spacing-4);
    }
}

.smpl-var-picker-heading {
    margin: 0 0 var(--kendo-spacing-3);
    font-size: var(--kendo-font-size-md);
}

/* The declared variables offered for insertion. A plain list of buttons: each is a click target the
   picker inserts, so it is a button rather than a styled span. */
.smpl-var-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--kendo-spacing-2);
}

.smpl-var-item {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--kendo-spacing-2);
    padding: var(--kendo-spacing-2) var(--kendo-spacing-3);
    background: var(--smpl-surface-raised);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
}

.smpl-var-chip-title {
    font-weight: 600;
    flex: 1 1 100%;
}

.smpl-var-chip-key {
    font-family: var(--kendo-font-family-monospace, monospace);
    font-size: var(--kendo-font-size-sm);
    color: var(--smpl-text-muted);
}

.smpl-var-chip-kind {
    font-size: var(--kendo-font-size-sm);
    color: var(--smpl-text-muted);
}

.smpl-var-chip {
    margin-left: auto;
    background: none;
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    padding: 2px var(--kendo-spacing-2);
    font-size: var(--kendo-font-size-sm);
    color: var(--smpl-accent);
    cursor: pointer;
}

.smpl-var-chip:hover {
    border-color: var(--smpl-accent);
}

.smpl-var-hint {
    margin: var(--kendo-spacing-3) 0 0;
    color: var(--smpl-text-muted);
    font-size: var(--kendo-font-size-sm);
}

/* The design-time warning that a declared variable no longer matches its form. Field names only,
   never a value. */
.smpl-var-stale {
    margin-bottom: var(--kendo-spacing-4);
    padding: var(--kendo-spacing-3);
    background: var(--smpl-danger-surface);
    border: 1px solid var(--smpl-danger);
    border-radius: var(--smpl-radius);
}

.smpl-var-stale-title {
    margin: 0 0 var(--kendo-spacing-2);
    font-weight: 600;
    color: var(--smpl-danger-text);
}

.smpl-var-stale-list {
    margin: 0;
    padding-left: var(--kendo-spacing-5);
    font-size: var(--kendo-font-size-sm);
    color: var(--smpl-danger-text);
}

/*
    The document field editor (Forms > a form > Document): the template's pages down the left with
    a box over each placed field, and the selected field's settings beside them.

    The two halves wrap rather than switch at a breakpoint: the pages want 36rem and the side panel
    20rem, so below about 900px the side panel simply drops under the pages. No media query, the
    rule UI-LAYOUT.md sets for this surface.
*/
.smpl-doc-editor {
    display: flex;
    flex-wrap: wrap;
    gap: var(--kendo-spacing-5);
    align-items: flex-start;
}

.smpl-doc-pages {
    flex: 3 1 36rem;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--kendo-spacing-5);
}

.smpl-doc-side {
    flex: 1 1 20rem;
    min-width: 0;
    position: sticky;
    top: var(--kendo-spacing-4);
    max-height: calc(100vh - 2 * var(--kendo-spacing-4));
    overflow-y: auto;
    padding: var(--kendo-spacing-4);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
}

.smpl-doc-side h3 {
    margin: var(--kendo-spacing-5) 0 var(--kendo-spacing-2);
}

.smpl-doc-side-section {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--kendo-spacing-2);
}

.smpl-doc-save {
    margin-top: var(--kendo-spacing-5);
    padding-top: var(--kendo-spacing-4);
    border-top: 1px solid var(--smpl-rule);
}

.smpl-doc-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--kendo-spacing-3) var(--kendo-spacing-5);
    margin-bottom: var(--kendo-spacing-4);
}

.smpl-doc-replace {
    margin-top: var(--kendo-spacing-5);
}

.smpl-doc-page-frame {
    margin: 0;
}

.smpl-doc-page-frame figcaption {
    margin-top: var(--kendo-spacing-1);
    color: var(--smpl-text-muted);
}

/*
    One page. The aspect ratio is set inline from the page's own size, so a lazily loaded image
    holds its place in the scroll before it arrives and every box, positioned in percentages of
    the page, lands on its field however wide the column is. touch-action and user-select stop the
    browser panning or selecting while the editor's script drags.
*/
.smpl-doc-page {
    position: relative;
    width: 100%;
    border: 1px solid var(--smpl-border-strong);
    background: var(--smpl-surface);
    touch-action: none;
    user-select: none;
    cursor: crosshair;
}

.smpl-doc-page img {
    display: block;
    width: 100%;
    height: 100%;
}

.smpl-doc-box {
    position: absolute;
    box-sizing: border-box;
    border: 2px solid var(--smpl-accent);
    background: color-mix(in srgb, var(--kendo-color-primary-subtle) 45%, transparent);
    cursor: move;
}

.smpl-doc-box:focus-visible {
    outline: 3px solid var(--smpl-accent-active);
    outline-offset: 1px;
}

.smpl-doc-box-selected {
    border-color: var(--smpl-accent-active);
    border-width: 3px;
    background: color-mix(in srgb, var(--kendo-color-primary-subtle) 70%, transparent);
}

.smpl-doc-box-tick {
    border-style: dashed;
}

/* The field's number, matching the field list, so a box and its row can be paired by eye. */
.smpl-doc-box-number {
    position: absolute;
    top: -1.4em;
    left: -2px;
    padding: 0 var(--kendo-spacing-1);
    border-radius: var(--smpl-radius);
    background: var(--smpl-accent);
    color: var(--smpl-on-accent);
    font-size: var(--kendo-font-size-sm);
    line-height: 1.3;
    pointer-events: none;
}

/* The corner a box is resized from. Drawn at 14px so it does not hide a small field, and pressed over
   28px: the invisible square around it belongs to the handle (the script finds it with closest()), so
   a press that just misses the visible corner still resizes rather than moving the box. */
.smpl-doc-box-handle {
    position: absolute;
    right: -7px;
    bottom: -7px;
    width: 14px;
    height: 14px;
    border-radius: 2px;
    background: var(--smpl-accent-active);
    box-shadow: 0 0 0 1px var(--smpl-on-accent);
    cursor: nwse-resize;
}

.smpl-doc-box-handle::before {
    content: "";
    position: absolute;
    inset: -7px;
}

/* The rectangle the script draws while a new field is being sketched. */
.smpl-doc-sketch {
    position: absolute;
    border: 2px dashed var(--smpl-accent);
    pointer-events: none;
}

.smpl-doc-fieldlist,
.smpl-doc-unplaced {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--kendo-spacing-1);
}

.smpl-doc-fieldlist-item {
    width: 100%;
    min-height: var(--smpl-control-min-height);
    padding: var(--kendo-spacing-2) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    color: var(--smpl-text);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.smpl-doc-fieldlist-item:hover {
    border-color: var(--smpl-accent);
}

.smpl-doc-fieldlist-item[aria-pressed="true"] {
    border-color: var(--smpl-accent);
    box-shadow: 0 0 0 1px var(--smpl-accent);
    background: var(--kendo-color-primary-subtle);
}

.smpl-doc-properties {
    display: flex;
    flex-direction: column;
    gap: var(--kendo-spacing-2);
}

.smpl-doc-geometry {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
    gap: 0 var(--kendo-spacing-3);
}

/* The editor's number boxes, given the box the native date and select controls already have. */
.smpl-field input.smpl-doc-number {
    width: 100%;
    box-sizing: border-box;
    min-height: var(--smpl-control-min-height);
    padding: var(--kendo-spacing-2) var(--kendo-spacing-3);
    border: 1px solid var(--smpl-border-strong);
    border-radius: var(--smpl-radius);
    background: var(--smpl-surface);
    color: var(--smpl-text);
    font: inherit;
    font-variant-numeric: tabular-nums;
}

.smpl-doc-properties .smpl-field select {
    width: 100%;
    min-width: 0;
}

/* ── The form-from-document wizard ─────────────────────────────────────────────────────────── */

/* The stepper: plain markup rather than a TelerikWizard or TelerikStepper. The wizard renders only
   the current step's content, which would tear down the form designer between steps and lose what
   was typed in it; a stepper is a picture of where you are, and nothing here should be clickable
   that does not do what the Next and Back buttons already do. The state is in words as well as
   colour: aria-current on the current step, and each step's number beside its name. */
.smpl-wizard-steps {
    display: flex;
    flex-wrap: wrap;
    gap: var(--kendo-spacing-2) var(--kendo-spacing-5);
    margin: 0 0 var(--kendo-spacing-4);
    padding: 0;
    list-style: none;
}

.smpl-wizard-step {
    display: inline-flex;
    align-items: center;
    gap: var(--kendo-spacing-2);
    color: var(--smpl-text-muted);
    font-weight: var(--kendo-font-weight-bold);
}

.smpl-wizard-step-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2rem;
    min-height: 2rem;
    border: 2px solid var(--smpl-border-strong);
    border-radius: 999px;
    background: var(--smpl-surface);
    font-variant-numeric: tabular-nums;
}

.smpl-wizard-step[data-state="current"] {
    color: var(--smpl-accent);
}

.smpl-wizard-step[data-state="current"] .smpl-wizard-step-number {
    border-color: var(--smpl-accent);
    background: var(--smpl-accent);
    color: var(--smpl-on-accent);
}

.smpl-wizard-step[data-state="done"] {
    color: var(--smpl-text);
}

.smpl-wizard-step[data-state="done"] .smpl-wizard-step-number {
    border-color: var(--smpl-ok);
}

/* The buttons that move between steps, under every step: Cancel apart on the left, Back and the
   primary action together on the right, with what pressing them said just above. */
.smpl-wizard-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--kendo-spacing-3);
    margin-top: var(--kendo-spacing-5);
    padding-top: var(--kendo-spacing-4);
    border-top: 1px solid var(--smpl-border);
}

.smpl-wizard-actions-spacer {
    flex: 1 1 auto;
}

.smpl-wizard-feedback {
    margin-top: var(--kendo-spacing-5);
}

/* On a step whose content is a form panel, the footer stops where the panel does, so the primary
   action sits beside what it acts on rather than at the far edge of a wide window. Steps with
   full-width content (the designer, the field editor, the preview) keep the full width. */
.smpl-wizard-narrow {
    max-width: var(--smpl-panel-form-width);
}

/* BusyIndicator: slow work under way. The accent-left notice of .smpl-page-message with a spinning
   ring in front of the words. */
.smpl-busy {
    display: flex;
    align-items: center;
    gap: var(--kendo-spacing-3);
    margin-bottom: var(--kendo-spacing-4);
    padding: var(--kendo-spacing-3) var(--kendo-spacing-4);
    border-left: 3px solid var(--smpl-accent);
    background: var(--smpl-surface-raised);
    color: var(--smpl-text);
}

.smpl-busy-spinner {
    flex: 0 0 auto;
    width: 1.1rem;
    height: 1.1rem;
    border: 2px solid var(--smpl-border);
    border-top-color: var(--smpl-accent);
    border-radius: 50%;
    animation: smpl-busy-spin 0.8s linear infinite;
}

@keyframes smpl-busy-spin {
    to {
        transform: rotate(360deg);
    }
}

@keyframes smpl-busy-pulse {
    50% {
        opacity: 0.35;
    }
}

/* No spinning for anybody who has asked for less motion: a slow fade says the same thing. */
@media (prefers-reduced-motion: reduce) {
    .smpl-busy-spinner {
        animation: smpl-busy-pulse 2s ease-in-out infinite;
    }
}

.smpl-wizard-check {
    display: flex;
    align-items: flex-start;
    gap: var(--kendo-spacing-2);
}

.smpl-wizard-check input {
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.2rem;
}

.smpl-wizard-preview {
    margin-top: var(--kendo-spacing-4);
}

/* Documents shared with one respondent, in the respondent panel. */
.smpl-shared-docs {
    width: 100%;
    border-collapse: collapse;
    margin: var(--kendo-spacing-2) 0;
}

.smpl-shared-docs td {
    padding: var(--kendo-spacing-2) var(--kendo-spacing-1);
    vertical-align: top;
    border-top: 1px solid var(--kendo-color-border);
}

.smpl-shared-docs td span {
    display: block;
}

.smpl-shared-doc-title {
    font-weight: 600;
}

.smpl-shared-doc-actions {
    white-space: nowrap;
    text-align: right;
}

.smpl-shared-doc-actions .smpl-button + .smpl-button {
    margin-left: var(--kendo-spacing-2);
}
