/* =============================================================================
   Stroma Client Portal — UI design system
   -----------------------------------------------------------------------------
   Loaded AFTER the Telerik kendo-theme-bootstrap sheet (see Components/App.razor),
   so every rule here wins on source order alone. Do not add !important.

   Namespaces: custom properties are --sp-*, classes are .sp-*. Nothing here may
   collide with Bootstrap 5.1.0, the Kendo .k-* namespace, or the legacy classes
   in stroma-portal.css (which is a generated marketing-site export and is not
   edited by this project).

   Raleway is declared by stroma-portal.css (medium 500 / semibold 600 / bold 700).
   There is no 400 or 300 face on disk, so --sp-fw-regular is 500 by design —
   asking for 300/400 gets faux-lightened by the browser.
   ========================================================================== */

:root {
    /* --- Brand ------------------------------------------------------------ */
    --sp-navy:            #16355c;   /* = legacy --secondary-color-accent      */
    --sp-navy-900:        #0f2645;   /* footer band, hero scrim                */
    --sp-navy-700:        #1d4478;
    --sp-cyan:            #2dafe6;   /* = legacy --secondary-color             */
    --sp-slate:           #686f7d;   /* = legacy --primary-color               */

    /* Vivid CTA blue from the mockups — distinct from the brand cyan. */
    --sp-primary:         #1a56db;
    --sp-primary-700:     #1544b0;
    --sp-primary-100:     #dbe6fe;
    --sp-primary-050:     #eef4ff;
    /* --sp-primary at 5% — the "light transparent blue" of the boxes that hold counters and
       statuses (Site Visits stat strip, Final Certificate work status), always on a
       --sp-primary-100 border. Deliberately lighter than the --sp-info-bg fill of the .sp-infobox
       these boxes sit beneath: at the same #eef4ff the notice and the boxes stack into one
       continuous blue block and the hierarchy inverts. Left genuinely transparent rather than
       flattened to a hex, so a box still reads correctly should it ever sit on --sp-canvas. */
    --sp-primary-tint:    rgba(26, 86, 219, .05);

    /* --- Neutrals --------------------------------------------------------- */
    --sp-ink:             #212427;
    --sp-ink-soft:        #48505b;
    --sp-muted:           #6b7480;
    --sp-line:            #e3e8ee;
    --sp-line-strong:     #cbd3dd;
    --sp-surface:         #ffffff;
    --sp-canvas:          #f5f7fa;

    /* --- Status ----------------------------------------------------------- */
    --sp-success:         #0f7b3d;
    --sp-success-bg:      #e6f6ec;
    /* The green button fill (Quote Acceptance). Brighter than --sp-success, which is a text
       colour, while still 4.5:1 against white text — the mockup's #53b845 is only 2.5:1. */
    --sp-success-strong:  #218838;
    --sp-danger:          #c62828;
    --sp-danger-bg:       #fdecec;
    --sp-warn:            #a86400;
    --sp-warn-bg:         #fff4e0;
    --sp-info:            #1a56db;
    --sp-info-bg:         #eef4ff;
    --sp-neutral:         #5b6472;
    --sp-neutral-700:     #454d59;
    --sp-neutral-bg:      #f1f3f5;

    /* --- Space ------------------------------------------------------------ */
    --sp-space-1: 4px;   --sp-space-2: 8px;   --sp-space-3: 12px;  --sp-space-4: 16px;
    --sp-space-5: 24px;  --sp-space-6: 32px;  --sp-space-7: 48px;  --sp-space-8: 64px;

    /* --- Radius ----------------------------------------------------------- */
    --sp-radius-sm:   6px;
    --sp-radius-md:  10px;
    --sp-radius-lg:  16px;
    --sp-radius-pill: 999px;

    /* --- Elevation -------------------------------------------------------- */
    --sp-shadow-1: 0 1px 2px rgba(16, 33, 56, .06), 0 1px 3px rgba(16, 33, 56, .08);
    --sp-shadow-2: 0 4px 12px rgba(16, 33, 56, .08), 0 2px 4px rgba(16, 33, 56, .05);
    --sp-shadow-3: 0 12px 32px rgba(16, 33, 56, .12), 0 4px 8px rgba(16, 33, 56, .06);

    /* --- Type ------------------------------------------------------------- */
    --sp-font: "Raleway", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --sp-fs-display: 2.25rem;
    --sp-fs-h1:      1.75rem;
    --sp-fs-h2:      1.375rem;
    --sp-fs-h3:      1.125rem;
    --sp-fs-body:     .9375rem;
    --sp-fs-small:    .8125rem;
    --sp-lh-tight:   1.2;
    --sp-lh-base:    1.55;
    --sp-fw-regular:  500;   /* no 400 face exists — see header note */
    --sp-fw-semibold: 600;
    --sp-fw-bold:     700;

    /* --- Layout ----------------------------------------------------------- */
    --sp-container-max: 1240px;
    --sp-hero-band-h:    220px;
    --sp-tile-lift:     72px;
}

/* =============================================================================
   Layout helpers
   ========================================================================== */

.sp-container {
    width: 100%;
    max-width: var(--sp-container-max);
    margin-inline: auto;
    padding-inline: var(--sp-space-5);
}

.sp-stack   { display: flex; flex-direction: column; gap: var(--sp-space-4); }
.sp-row     { display: flex; align-items: center; gap: var(--sp-space-3); }
.sp-spacer  { flex: 1 1 auto; }

/* =============================================================================
   App shell
   ========================================================================== */

.sp-app { display: flex; flex-direction: column; min-height: 100vh; }
.sp-app__main { flex: 1 1 auto; background: var(--sp-canvas); }

/* Legacy: .sub-header is still used by OptInOut.razor and ProjectTransfer.razor, which
   render directly inside MainLayout's URL branches. Lifted verbatim out of MainLayout's
   inline <style> so those two pages keep their current appearance. The green shadow
   against a cyan gradient is a leftover from an older palette — left as-is deliberately,
   since restyling those pages is not part of this work. */
.sub-header {
    background: linear-gradient(135deg, var(--secondary-color) 0%, #a8dadc 100%);
    box-shadow: 0 4px 12px rgba(129, 199, 132, 0.4);
    border-bottom: none;
    position: sticky;
    top: 0;
    z-index: 1000;
}

/* =============================================================================
   Hero
   ========================================================================== */

.sp-hero {
    position: relative;
    isolation: isolate;
    background-color: var(--sp-navy);   /* fallback while the photo is pending */
    color: #fff;
    overflow: hidden;
}

.sp-hero__media {
    position: absolute;
    inset: 0;
    z-index: -2;
    background-position: center center;
    background-size: cover;
    background-repeat: no-repeat;
}

/* Navy on the text side, photo showing through on the right. */
.sp-hero__scrim {
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(100deg,
        var(--sp-navy-900) 0%,
        rgba(15, 38, 69, .94) 38%,
        rgba(15, 38, 69, .55) 62%,
        rgba(15, 38, 69, .15) 100%);
}

/* For artwork that has its own navy panel painted in, where a second scrim would muddy it.
   Nothing uses it today: ticket 869eybf57 put one photo (hero-houses.jpg) behind the
   sign-in, Home and project heroes, and that photo needs the scrim for the white heading
   to stay readable. */
.sp-hero--plain .sp-hero__scrim { display: none; }

.sp-hero__inner   { padding-block: var(--sp-space-6); }

/* Reserves clearance underneath the hero copy for a following .sp-card--raised row, so the
   two can never overlap. Both derive from --sp-tile-lift, including at the mobile
   breakpoint where the lift shrinks. */
.sp-hero--overlapped .sp-hero__inner {
    padding-bottom: calc(var(--sp-space-6) + var(--sp-tile-lift));
}
.sp-hero--band    { min-height: var(--sp-hero-band-h); }
.sp-hero--tall    { min-height: 100vh; display: flex; flex-direction: column; }

.sp-hero__eyebrow {
    font-size: var(--sp-fs-small);
    font-weight: var(--sp-fw-semibold);
    letter-spacing: .04em;
    text-transform: uppercase;
    opacity: .85;
    margin: 0 0 var(--sp-space-2);
}

.sp-hero__title {
    font-size: var(--sp-fs-display);
    line-height: var(--sp-lh-tight);
    font-weight: var(--sp-fw-bold);
    margin: 0;
    color: #fff;
}

.sp-hero__title em {
    display: block;
    font-style: normal;
    color: var(--sp-cyan);
}

.sp-hero__sub {
    margin: var(--sp-space-3) 0 0;
    max-width: 46ch;
    line-height: var(--sp-lh-base);
    opacity: .9;
}

/* =============================================================================
   Chrome — logo bar, nav, user chip
   ========================================================================== */

.sp-logobar {
    background: var(--sp-surface);
    border-bottom: 1px solid var(--sp-line);
}

.sp-logobar__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-4);
    min-height: 76px;
}

.sp-logobar__logo img { max-height: 52px; width: auto; display: block; }

.sp-navbar { background: var(--sp-navy); }

.sp-navbar__inner { display: flex; align-items: center; gap: var(--sp-space-5); min-height: 54px; }

/* Nav links sit left, the user chip and Logout are pushed to the right-hand edge. */
.sp-navbar__inner .sp-userchip { margin-left: auto; }

.sp-navbar__list {
    display: flex;
    align-items: center;
    gap: var(--sp-space-5);
    list-style: none;
    margin: 0;
    padding: 0;
}

.sp-navbar__link {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    color: rgba(255, 255, 255, .88);
    text-decoration: none;
    font-size: var(--sp-fs-body);
    font-weight: var(--sp-fw-semibold);
    padding-block: var(--sp-space-3);
    border-bottom: 2px solid transparent;
}

.sp-navbar__link:hover,
.sp-navbar__link:focus-visible { color: #fff; border-bottom-color: var(--sp-cyan); }
.sp-navbar__link--active       { color: #fff; border-bottom-color: var(--sp-cyan); }

/* Both the mobile menu and the user dropdown are checkbox-driven: MainLayout is static
   SSR, so @onclick never fires there. Keep them CSS-only. */
.sp-navbar__state,
.sp-userchip__state {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.sp-navbar__toggle {
    display: none;
    background: none;
    border: 0;
    color: #fff;
    padding: var(--sp-space-2);
    cursor: pointer;
}

.sp-navbar__state:focus-visible ~ .sp-navbar__toggle,
.sp-userchip__state:focus-visible ~ .sp-userchip__button {
    outline: 2px solid var(--sp-cyan);
    outline-offset: 2px;
}

/* --- User chip ---------------------------------------------------------- */

.sp-userchip { position: relative; }

.sp-userchip__button {
    display: inline-flex;
    user-select: none;
    align-items: center;
    gap: var(--sp-space-2);
    background: var(--sp-surface);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-pill);
    padding: var(--sp-space-2) var(--sp-space-3);
    font: inherit;
    font-size: var(--sp-fs-body);
    font-weight: var(--sp-fw-semibold);
    color: var(--sp-ink);
    cursor: pointer;
}

.sp-userchip__button:hover { border-color: var(--sp-line-strong); }

.sp-userchip__avatar {
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--sp-primary);
    color: #fff;
    font-size: var(--sp-fs-small);
    font-weight: var(--sp-fw-bold);
    text-transform: uppercase;
}

.sp-userchip__menu {
    display: none;
    position: absolute;
    top: calc(100% + var(--sp-space-2));
    right: 0;
    min-width: 200px;
    background: var(--sp-surface);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-md);
    box-shadow: var(--sp-shadow-2);
    padding: var(--sp-space-2);
    z-index: 60;
}

.sp-userchip__item {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    width: 100%;
    background: none;
    border: 0;
    border-radius: var(--sp-radius-sm);
    padding: var(--sp-space-2) var(--sp-space-3);
    font: inherit;
    font-size: var(--sp-fs-body);
    color: var(--sp-ink);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.sp-userchip__state:checked ~ .sp-userchip__menu { display: block; }

.sp-userchip__item:hover { background: var(--sp-canvas); }

.sp-userchip__menu form { margin: 0; }
.sp-userchip__item { font-size: var(--sp-fs-body); }

/* =============================================================================
   Page heading
   ========================================================================== */

.sp-page { display: flex; flex-direction: column; gap: var(--sp-space-5); padding-block: var(--sp-space-6) var(--sp-space-8); }
.sp-page__head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--sp-space-4); }
.sp-page__title { font-size: var(--sp-fs-h1); font-weight: var(--sp-fw-bold); color: var(--sp-primary); margin: 0; }

/* A heading that carries an icon badge to its left, as the FAQ page does. The h1 and lead
   go in a sibling div so they stay stacked beside the badge rather than under it. */
.sp-page__titlerow { display: flex; align-items: center; gap: var(--sp-space-3); }

.sp-page__titleicon {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    /* Sized to the height of the title and its lead together, which is how the mockup
       proportions it against the heading. */
    width: 56px; height: 56px;
    border-radius: 50%;
    background: var(--sp-primary-050);
    color: var(--sp-primary);
}
/* stroma-portal.css sizes headings inside .richtext at 0-2-1
   (`.richtext h4:not([class^="title"])` -> 26px/36px), which outscores .sp-subheading's 0-1-0
   however late this sheet loads. Restated at 0-2-1 so a tie is broken on source order — a
   subheading inside prose should not come out bigger than the accordion title above it. */
.richtext h4.sp-subheading {
    font-size: var(--sp-fs-h3);
    line-height: var(--sp-lh-tight);
}

.sp-subheading {
    font-size: var(--sp-fs-h3);
    font-weight: var(--sp-fw-bold);
    color: var(--sp-ink);
    margin: 0 0 var(--sp-space-3);
}

.sp-page__lead { margin: var(--sp-space-1) 0 0; color: var(--sp-muted); font-size: var(--sp-fs-body); }

/* =============================================================================
   Card
   ========================================================================== */

.sp-card {
    background: var(--sp-surface);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-lg);
    box-shadow: var(--sp-shadow-1);
}

.sp-card__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-space-4);
    padding: var(--sp-space-5) var(--sp-space-5) 0;
}

.sp-card__title    { font-size: var(--sp-fs-h2); font-weight: var(--sp-fw-bold); margin: 0; color: var(--sp-ink); }
.sp-card__subtitle { font-size: var(--sp-fs-small); color: var(--sp-muted); margin: var(--sp-space-1) 0 0; }
.sp-card__body     { padding: var(--sp-space-5); }
.sp-card__footer   { padding: 0 var(--sp-space-5) var(--sp-space-5); }
.sp-card--flush .sp-card__body { padding: 0; }

/* Lifts the tile row up over the hero band above it. Pair with .sp-hero--overlapped on
   that hero, or the lifted row will cover the hero's own text. */
.sp-card--raised { position: relative; z-index: 2; margin-top: calc(-1 * var(--sp-tile-lift)); }

/* =============================================================================
   Sub-card
   A plain white bordered box for sub-sections nested inside an accordion panel,
   where .sp-card is too heavy: no shadow and a tighter radius. The title is the
   first line of the box, on the same white as the content under it — no fill
   and no rule of its own. It used to sit in a tinted header band, which read as
   a table heading; ClickUp 869euhvt4 asked for the titles to be part of their
   sections, as the Invoicing mockup draws them.
   ========================================================================== */

.sp-subcard {
    background: var(--sp-surface);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-md);
}

/* Still a flex row, so an action can sit right of the title; no bottom padding, so the
   body's own padding is the only gap between the title and what follows. */
.sp-subcard__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-3);
    padding: var(--sp-space-4) var(--sp-space-4) 0;
}

.sp-subcard__title {
    margin: 0;
    font-size: var(--sp-fs-h3);
    line-height: var(--sp-lh-tight);
    font-weight: var(--sp-fw-bold);
    color: var(--sp-ink);
}

.sp-subcard__body { padding: var(--sp-space-4); }

/* Under a title the body closes up, so the heading and its content read as one block. */
.sp-subcard__header + .sp-subcard__body { padding-top: var(--sp-space-3); }

/* Same cascade problem .richtext h4.sp-subheading solves above: stroma-portal.css
   sizes .richtext headings at 0-2-1, which outscores .sp-subcard__title's 0-1-0
   however late this sheet loads — 26px for h4, and for h5 a 3rem line-height that
   opens a gap under the title. Restated at 0-2-1 so the tie breaks on source order.
   Both tags are covered so the title survives a heading-level change. */
.richtext h4.sp-subcard__title,
.richtext h5.sp-subcard__title {
    font-size: var(--sp-fs-h3);
    line-height: var(--sp-lh-tight);
}

/* =============================================================================
   Tiles
   ========================================================================== */

.sp-tilerow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--sp-space-4);
}

.sp-tile {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-space-4);
    background: var(--sp-surface);
    /* The tile is a white card wherever it sits — including inside .sp-hero, which sets
       color:#fff on everything beneath it. */
    color: var(--sp-ink);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-lg);
    box-shadow: var(--sp-shadow-2);
    padding: var(--sp-space-5);
}

.sp-tile__icon {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 48px;
    height: 48px;
    border-radius: var(--sp-radius-md);
    background: var(--sp-primary-050);
    color: var(--sp-primary);
}

.sp-tile__icon:has(img) { background: none; }
.sp-tile__icon img { width: 100%; height: 100%; object-fit: contain; display: block; }
.sp-tile__body    { min-width: 0; }
.sp-tile__count   { font-size: var(--sp-fs-h1); font-weight: var(--sp-fw-bold); line-height: 1; color: var(--sp-ink); }
.sp-tile__label   { font-size: var(--sp-fs-body); font-weight: var(--sp-fw-semibold); color: var(--sp-ink); margin-top: var(--sp-space-1); }
.sp-tile__meta    { font-size: var(--sp-fs-small); color: var(--sp-muted); margin-top: var(--sp-space-1); }
.sp-tile__actions { display: flex; flex-wrap: wrap; gap: var(--sp-space-2); margin-top: var(--sp-space-3); }

/* =============================================================================
   Stat strip
   ========================================================================== */

.sp-statrow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--sp-space-3);
}

.sp-stat {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
    /* See --sp-primary-tint for why the fill is 5% rather than --sp-info-bg. */
    background: var(--sp-primary-tint);
    border: 1px solid var(--sp-primary-100);
    border-radius: var(--sp-radius-md);
    padding: var(--sp-space-4);
}

.sp-stat__icon {
    display: grid;
    place-items: center;
    width: 40px; height: 40px;
    flex: 0 0 auto;
    border-radius: var(--sp-radius-sm);
    /* -100 rather than -050: at #eef4ff the chip all but vanishes against the tinted box.
       #1a56db on #dbe6fe is ~6.2:1, so the glyph stays comfortably clear of AA. */
    background: var(--sp-primary-100);
    color: var(--sp-primary);
}

.sp-stat__label { font-size: var(--sp-fs-small); color: var(--sp-muted); }
.sp-stat__value { font-size: var(--sp-fs-h2); font-weight: var(--sp-fw-bold); color: var(--sp-ink); line-height: 1.15; }
.sp-stat__value--danger  { color: var(--sp-danger); }
.sp-stat__value--success { color: var(--sp-success); }
.sp-stat__value--warn    { color: var(--sp-warn); }

/* Divided variant — the invoicing 3-up summary. */
.sp-statrow--divided {
    background: var(--sp-canvas);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-md);
    gap: 0;
}

.sp-statrow--divided .sp-stat {
    background: none;
    border: 0;
    border-left: 1px solid var(--sp-line);
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-space-1);
}

.sp-statrow--divided .sp-stat:first-child { border-left: 0; }

/* =============================================================================
   Status pill
   ========================================================================== */

.sp-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    border-radius: var(--sp-radius-pill);
    padding: var(--sp-space-1) var(--sp-space-3);
    font-size: var(--sp-fs-small);
    font-weight: var(--sp-fw-semibold);
    line-height: 1.4;
    white-space: nowrap;
    background: var(--sp-neutral-bg);
    color: var(--sp-neutral);
}

.sp-pill--success { background: var(--sp-success-bg); color: var(--sp-success); }
.sp-pill--danger  { background: var(--sp-danger-bg);  color: var(--sp-danger); }
.sp-pill--warning { background: var(--sp-warn-bg);    color: var(--sp-warn); }
.sp-pill--info    { background: var(--sp-info-bg);    color: var(--sp-info); }
.sp-pill--neutral { background: var(--sp-neutral-bg); color: var(--sp-neutral); }

/* =============================================================================
   Accordion
   ========================================================================== */

.sp-accordion { display: flex; flex-direction: column; }

.sp-accordion__item { border-top: 1px solid var(--sp-line); }
.sp-accordion__item:first-child { border-top: 0; }

.sp-accordion__header {
    display: flex;
    align-items: center;
    gap: var(--sp-space-4);
    width: 100%;
    background: none;
    border: 0;
    padding: var(--sp-space-4) var(--sp-space-5);
    font: inherit;
    text-align: left;
    cursor: pointer;
    color: var(--sp-ink);
}

.sp-accordion__header:hover { background: var(--sp-canvas); }

.sp-accordion__icon {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 40px; height: 40px;
    border-radius: 50%;
    background: var(--sp-primary);
    color: #fff;
}

/* The supplied section icons already are the coloured circle from the design. Where one is
   present, drop this wrapper's own background and let the artwork fill it — otherwise the
   glyph sits in a circle inside a circle, and the white-out filter erases it entirely. */
.sp-accordion__icon:has(img) { background: none; }
.sp-accordion__icon img { width: 100%; height: 100%; object-fit: contain; display: block; }

.sp-accordion__icon--success { background: var(--sp-success); }
.sp-accordion__icon--danger  { background: var(--sp-danger); }
.sp-accordion__icon--warning { background: #e8a317; }
.sp-accordion__icon--info    { background: var(--sp-cyan); }
.sp-accordion__icon--violet  { background: #7c4dff; }
.sp-accordion__icon--pink    { background: #ec4899; }
.sp-accordion__icon--teal    { background: #0fa697; }

/* Title and subtitle are <span> pairs that must stack. They were inline, which ran the
   heading straight into its description with no break — margins do nothing on an inline box. */
.sp-accordion__text     { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; }
.sp-accordion__title    { display: block; font-size: var(--sp-fs-h3); font-weight: var(--sp-fw-bold); margin: 0; }
.sp-accordion__subtitle { display: block; font-size: var(--sp-fs-small); color: var(--sp-muted); margin: 2px 0 0; }

/* --plain is for accordions whose rows carry no icon — the FAQ page. AccordionSection always
   emits the icon span, so without this every question sits behind an empty 40px brand circle.
   Scoped rather than global: two ProjectView sections are also icon-less, but they sit among
   nine iconed siblings and would lose their alignment. */
.sp-accordion--plain .sp-accordion__icon  { display: none; }
.sp-accordion--plain .sp-accordion__title { color: var(--sp-primary); }

/* --plain rows are separate cards with air between them, rather than one card divided by
   rules. The container therefore carries no .sp-card of its own. overflow keeps the header's
   hover fill inside the rounded corners. */
.sp-accordion--plain { gap: var(--sp-space-3); }

.sp-accordion--plain .sp-accordion__item,
.sp-accordion--plain .sp-accordion__item:first-child {
    background: var(--sp-surface);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-md);
    overflow: hidden;
}

.sp-accordion__chevron {
    flex: 0 0 auto;
    color: var(--sp-muted);
    transition: transform .18s ease;
}

.sp-accordion__header[aria-expanded="true"] .sp-accordion__chevron { transform: rotate(180deg); }

.sp-accordion__panel { padding: 0 var(--sp-space-5) var(--sp-space-5); }

.sp-accordion__toolbar {
    display: flex;
    align-items: center;
    gap: var(--sp-space-4);
}

/* =============================================================================
   Info box and alerts
   ========================================================================== */

.sp-infobox {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-space-3);
    background: var(--sp-info-bg);
    border: 1px solid var(--sp-primary-100);
    border-radius: var(--sp-radius-md);
    padding: var(--sp-space-4);
    color: var(--sp-ink-soft);
    line-height: var(--sp-lh-base);
    font-size: var(--sp-fs-body);
}

.sp-infobox__icon { flex: 0 0 auto; color: var(--sp-primary); margin-top: 2px; }
.sp-infobox p:last-child { margin-bottom: 0; }

.sp-infobox--warning { background: var(--sp-warn-bg);    border-color: #f3d9a6; }
.sp-infobox--warning .sp-infobox__icon { color: var(--sp-warn); }
.sp-infobox--danger  { background: var(--sp-danger-bg);  border-color: #f5c6c6; }
.sp-infobox--danger  .sp-infobox__icon { color: var(--sp-danger); }
.sp-infobox--success { background: var(--sp-success-bg); border-color: #b8e3c8; }
.sp-infobox--success .sp-infobox__icon { color: var(--sp-success); }

.sp-alert {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
    border-radius: var(--sp-radius-md);
    padding: var(--sp-space-4) var(--sp-space-5);
    font-size: var(--sp-fs-body);
}

.sp-alert--danger { background: var(--sp-danger-bg); color: var(--sp-danger); border: 1px solid #f5c6c6; }
.sp-alert--warning { background: var(--sp-warn-bg); color: var(--sp-warn); border: 1px solid #f3d9a6; }
.sp-alert--help   { background: var(--sp-info-bg);   color: var(--sp-ink); border: 1px solid var(--sp-primary-100); }

/* =============================================================================
   Footer band
   ========================================================================== */

.sp-footer { background: var(--sp-navy-900); color: rgba(255, 255, 255, .82); }

.sp-footer__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-5);
    padding-block: var(--sp-space-6);
}

.sp-footer__tagline { display: flex; align-items: center; gap: var(--sp-space-4); }

.sp-footer__shield {
    display: grid;
    place-items: center;
    width: 44px; height: 44px;
    flex: 0 0 auto;
    border-radius: var(--sp-radius-md);
    background: var(--sp-primary);
    color: #fff;
}

.sp-footer__strong { display: block; color: #fff; font-weight: var(--sp-fw-bold); }
.sp-footer__contact { line-height: var(--sp-lh-base); }
.sp-footer__contact a { color: var(--sp-cyan); text-decoration: none; }
.sp-footer__contact a:hover { text-decoration: underline; }
.sp-footer__legal { width: 100%; border-top: 1px solid rgba(255,255,255,.12); padding-block: var(--sp-space-4); font-size: var(--sp-fs-small); opacity: .7; }

/* =============================================================================
   Progress ring
   ========================================================================== */

.sp-ring { display: inline-grid; place-items: center; position: relative; }
.sp-ring svg { display: block; transform: rotate(-90deg); }
.sp-ring__track { stroke: var(--sp-line); }
.sp-ring__value { stroke: var(--sp-primary); stroke-linecap: round; transition: stroke-dashoffset .4s ease; }
.sp-ring__value--complete { stroke: var(--sp-navy); }

.sp-ring__label {
    position: absolute;
    font-weight: var(--sp-fw-bold);
    font-size: var(--sp-fs-small);
    color: var(--sp-ink);
}

.sp-ring--lg .sp-ring__label { font-size: var(--sp-fs-h3); }

/* Placeholder while the row's detail is still loading. */
.sp-ring--skeleton .sp-ring__value { stroke: var(--sp-line); }
.sp-ring--skeleton .sp-ring__label { color: var(--sp-line-strong); }

/* =============================================================================
   Tabs
   ========================================================================== */

.sp-tabs__list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
    border-bottom: 1px solid var(--sp-line);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-tabs__tab {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    background: none;
    border: 0;
    border-bottom: 3px solid transparent;
    padding: var(--sp-space-4) var(--sp-space-4);
    font: inherit;
    font-size: var(--sp-fs-body);
    font-weight: var(--sp-fw-semibold);
    color: var(--sp-muted);
    cursor: pointer;
    white-space: nowrap;
}

.sp-tabs__tab:hover { color: var(--sp-ink); }
.sp-tabs__tab--active { color: var(--sp-primary); border-bottom-color: var(--sp-primary); }
.sp-tabs__panel { padding: var(--sp-space-5); line-height: var(--sp-lh-base); }

/* Label inside a Telerik TabStrip HeaderTemplate. */
.sp-tabs__tab-label { font-size: var(--sp-fs-body); font-weight: var(--sp-fw-semibold); color: inherit; }

.sp-tabs__close {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    background: none;
    border: 0;
    color: var(--sp-muted);
    font: inherit;
    font-size: var(--sp-fs-small);
    cursor: pointer;
}

/* --- CSS-only variant, for the static-SSR login page --------------------- */
/* The login page has no render mode and cannot use @onclick. Tabs are driven
   by hidden radios + :checked sibling selectors instead. */

.sp-tabs--static input[type="radio"] {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* All four panels share one grid cell, so the card is always as tall as its tallest
   panel and switching tabs never changes the page height. Inactive panels are hidden
   with visibility rather than display: display:none would collapse them and take that
   height away again. visibility:hidden also keeps them out of the accessibility tree
   and out of the tab order. */
.sp-tabs--static .sp-tabs__panels { display: grid; }
.sp-tabs--static .sp-tabs__panel  { grid-area: 1 / 1; visibility: hidden; }

.sp-tabs--static input:nth-of-type(1):checked ~ .sp-tabs__panels > .sp-tabs__panel:nth-of-type(1),
.sp-tabs--static input:nth-of-type(2):checked ~ .sp-tabs__panels > .sp-tabs__panel:nth-of-type(2),
.sp-tabs--static input:nth-of-type(3):checked ~ .sp-tabs__panels > .sp-tabs__panel:nth-of-type(3),
.sp-tabs--static input:nth-of-type(4):checked ~ .sp-tabs__panels > .sp-tabs__panel:nth-of-type(4) {
    visibility: visible;
}

.sp-tabs--static input:nth-of-type(1):checked ~ .sp-tabs__list > .sp-tabs__tab:nth-of-type(1),
.sp-tabs--static input:nth-of-type(2):checked ~ .sp-tabs__list > .sp-tabs__tab:nth-of-type(2),
.sp-tabs--static input:nth-of-type(3):checked ~ .sp-tabs__list > .sp-tabs__tab:nth-of-type(3),
.sp-tabs--static input:nth-of-type(4):checked ~ .sp-tabs__list > .sp-tabs__tab:nth-of-type(4) {
    color: var(--sp-primary);
    border-bottom-color: var(--sp-primary);
}

/* Keyboard focus has to be visible on the label, since the radio is hidden. */
.sp-tabs--static input:focus-visible ~ .sp-tabs__list > .sp-tabs__tab { outline: none; }
.sp-tabs--static input:nth-of-type(1):focus-visible ~ .sp-tabs__list > .sp-tabs__tab:nth-of-type(1),
.sp-tabs--static input:nth-of-type(2):focus-visible ~ .sp-tabs__list > .sp-tabs__tab:nth-of-type(2),
.sp-tabs--static input:nth-of-type(3):focus-visible ~ .sp-tabs__list > .sp-tabs__tab:nth-of-type(3),
.sp-tabs--static input:nth-of-type(4):focus-visible ~ .sp-tabs__list > .sp-tabs__tab:nth-of-type(4) {
    outline: 2px solid var(--sp-primary);
    outline-offset: -2px;
    border-radius: var(--sp-radius-sm);
}

/* =============================================================================
   Lists — project rows, site visits, documents
   ========================================================================== */

.sp-list { display: flex; flex-direction: column; gap: var(--sp-space-3); }

.sp-list__row {
    display: flex;
    align-items: center;
    gap: var(--sp-space-4);
    background: var(--sp-surface);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-md);
    padding: var(--sp-space-4);
}

.sp-list__main    { min-width: 0; flex: 1 1 auto; }
.sp-list__primary { font-size: var(--sp-fs-h3); font-weight: var(--sp-fw-bold); margin: 0; color: var(--sp-ink); }
.sp-list__ref     { font-size: var(--sp-fs-small); color: var(--sp-muted); margin-top: 2px; }

/* Leading glyph on a list row — the uploaded-file rows. Mirrors .sp-doclink__icon's tinted
   square so a file reads the same whether or not the row links anywhere. */
.sp-list__icon {
    display: grid;
    place-items: center;
    width: 36px; height: 36px;
    flex: 0 0 auto;
    border-radius: var(--sp-radius-sm);
    background: var(--sp-primary-050);
    color: var(--sp-primary);
}

.sp-list__field       { min-width: 140px; }
.sp-list__field-label { font-size: var(--sp-fs-small); color: var(--sp-muted); }
.sp-list__field-value { font-size: var(--sp-fs-body); font-weight: var(--sp-fw-semibold); color: var(--sp-primary); }
.sp-list__field-value--ink { color: var(--sp-ink); }
.sp-list__action { flex: 0 0 auto; }

/* A pill is nowrap by default, but .sp-list__field's explicit min-width lets the field
   shrink below the pill's text width, and the pill then overprints the next field (a long
   CRM status over Role on My Projects). Inside a list field the pill wraps instead. */
.sp-list__field-value .sp-pill { white-space: normal; }

/* Column-aligned rows — My Projects on Home. A plain .sp-list__row is its own flex container,
   so each field starts wherever that row's address happens to end. Here every row is a grid
   with the same track template instead, so address, Status and Role each start at the same x
   in every row. Children are placed in source order: main, field, field, action — a fifth
   child (the commented-out ProgressRing in Home.razor) would need a track of its own.

   The tiers follow the list's own width, not the viewport's: the Home card is narrower at a
   992px window (two-column split) than at an 800px one (single column). */
.sp-list--columns { container-type: inline-size; }

.sp-list--columns .sp-list__row {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) 10rem minmax(0, 1fr) max-content;
    align-items: center;
}

.sp-list--columns .sp-list__field { min-width: 0; }
.sp-list--columns .sp-list__action,
.sp-list--columns .sp-list__action .sp-btn { width: auto; }

/* Too narrow for four columns: the address takes a line to itself. */
@container (max-width: 650px) {
    .sp-list--columns .sp-list__row {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) max-content;
        align-items: start;
        row-gap: var(--sp-space-3);
    }
    .sp-list--columns .sp-list__main   { grid-column: 1 / -1; }
    .sp-list--columns .sp-list__action { align-self: center; }
}

/* Phone widths: the button drops to a full-width line of its own. */
@container (max-width: 440px) {
    .sp-list--columns .sp-list__row    { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .sp-list--columns .sp-list__action { grid-column: 1 / -1; }
    .sp-list--columns .sp-list__action,
    .sp-list--columns .sp-list__action .sp-btn { width: 100%; }
}

/* =============================================================================
   Empty state
   -----------------------------------------------------------------------------
   The "nothing here yet" panel that fills a card body. Dashed rather than solid so it
   reads as an absence rather than as a row of content.
   ========================================================================== */

.sp-emptystate {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-space-3);
    border: 1px dashed var(--sp-line-strong);
    border-radius: var(--sp-radius-md);
    padding: var(--sp-space-5);
}

.sp-emptystate__icon {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--sp-primary-050);
    color: var(--sp-primary);
}

/* Sizes are restated because stroma-portal.css sets a bare `p` to 18px/28px inside prose. */
.sp-emptystate__title {
    margin: 0;
    font-size: var(--sp-fs-body);
    line-height: var(--sp-lh-base);
    font-weight: var(--sp-fw-semibold);
    color: var(--sp-ink);
}

.sp-emptystate__hint {
    margin: 2px 0 0;
    font-size: var(--sp-fs-small);
    line-height: var(--sp-lh-base);
    color: var(--sp-muted);
}

/* Iconless single-line variant, left aligned — the "no certificates yet" panel. */
.sp-emptystate--plain {
    justify-content: flex-start;
    border-style: solid;
    border-color: var(--sp-line);
    padding: var(--sp-space-4);
}

.sp-emptystate--plain .sp-emptystate__title { font-weight: var(--sp-fw-regular); color: var(--sp-ink-soft); }

/* =============================================================================
   Certificate cards
   -----------------------------------------------------------------------------
   One issued document per card. Green because reaching this list means the certificate
   exists — the action column still explains when it cannot be opened (unpaid invoice,
   archived after six months).
   ========================================================================== */

.sp-certlist { display: flex; flex-direction: column; gap: var(--sp-space-3); }

.sp-certcard {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
        "icon main actions"
        "note note note";
    align-items: center;
    gap: var(--sp-space-2) var(--sp-space-4);
    padding: var(--sp-space-4);
    border: 1px solid #b8e3c8;
    border-radius: var(--sp-radius-md);
    background: var(--sp-success-bg);
}

.sp-certcard__icon { grid-area: icon; align-self: start; color: var(--sp-success); }
.sp-certcard__main { grid-area: main; min-width: 0; }
.sp-certcard__actions {
    grid-area: actions;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-space-2);
}

.sp-certcard__title {
    margin: 0 0 var(--sp-space-1);
    font-size: var(--sp-fs-body);
    line-height: var(--sp-lh-tight);
    font-weight: var(--sp-fw-bold);
    color: var(--sp-ink);
}

/* Sizes restated because stroma-portal.css sets a bare p to 18px/28px inside prose. */
.sp-certcard__meta {
    margin: 0;
    font-size: var(--sp-fs-small);
    line-height: var(--sp-lh-base);
    color: var(--sp-muted);
}

.sp-certcard__meta strong { color: var(--sp-ink); font-weight: var(--sp-fw-semibold); }

.sp-certcard__note {
    grid-area: note;
    margin: 0;
    font-size: var(--sp-fs-small);
    line-height: var(--sp-lh-base);
    color: var(--sp-muted);
}

.sp-certcard__status { margin: 0; font-size: var(--sp-fs-small); color: var(--sp-ink-soft); }

@media (max-width: 575.98px) {
    .sp-certcard {
        grid-template-columns: auto minmax(0, 1fr);
        grid-template-areas:
            "icon main"
            "actions actions"
            "note note";
    }
}

/* Consultations — ConsultationsPanel.razor (ClickUp 869f2q5hj). One card per consultation:
   icon, title and description on top, then a rule and a row of letter date, outcome and the
   response download. The download column keeps its width when there is no response to offer,
   so the two fields start at the same place on every card. */
.sp-consultlist { display: flex; flex-direction: column; gap: var(--sp-space-3); margin-top: var(--sp-space-4); }

.sp-consult {
    padding: var(--sp-space-4);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-md);
    background: var(--sp-surface);
}

.sp-consult__head {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-space-4);
    padding-bottom: var(--sp-space-4);
    border-bottom: 1px solid var(--sp-line);
}

/* The supplied consultation icons already are the tinted circle from the design, so this only
   sizes them — a background here would draw a circle behind the circle. */
.sp-consult__icon { width: 64px; height: 64px; flex: 0 0 auto; }
.sp-consult__icon img { width: 100%; height: 100%; object-fit: contain; display: block; }

.sp-consult__title {
    margin: 0 0 var(--sp-space-1);
    font-size: var(--sp-fs-h3);
    line-height: var(--sp-lh-tight);
    font-weight: var(--sp-fw-bold);
    color: var(--sp-ink);
}

/* Sizes restated because stroma-portal.css sets a bare p to 18px/28px inside prose. */
.sp-consult__text {
    margin: 0;
    font-size: var(--sp-fs-body);
    line-height: var(--sp-lh-base);
    color: var(--sp-ink-soft);
}

.sp-consult__details {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 13rem;
    align-items: center;
    gap: var(--sp-space-4);
    padding-top: var(--sp-space-4);
}

.sp-consult__field { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sp-consult__field + .sp-consult__field { padding-left: var(--sp-space-4); border-left: 1px solid var(--sp-line); }
.sp-consult__label { font-size: var(--sp-fs-body); font-weight: var(--sp-fw-bold); color: var(--sp-ink); }
.sp-consult__value { font-size: var(--sp-fs-body); color: var(--sp-ink); }
.sp-consult__action .sp-btn { width: 100%; }

@media (max-width: 767.98px) {
    .sp-consult__details { grid-template-columns: minmax(0, 1fr); gap: var(--sp-space-3); }
    .sp-consult__field + .sp-consult__field { padding-left: 0; border-left: 0; }
}

/* Centred "show more" control under a list. Was .sp-projectview__viewall in
   ProjectView.razor.css, but the only markup using it lives in SiteVisitsPanel.razor, which has
   no companion .razor.css and so carries no scope id — the rule compiled to
   .sp-projectview__viewall[b-3wzwd71u7j] and matched nothing, leaving the button uncentred. */
.sp-list__more {
    display: flex;
    justify-content: center;
    padding: var(--sp-space-3) 0 var(--sp-space-2);
}

/* Date chip — day / MON / year block on the site-visit rows. */
.sp-datechip {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 56px;
    padding: var(--sp-space-2) 0;
    border-radius: var(--sp-radius-sm);
    background: var(--sp-primary-050);
    color: var(--sp-primary);
    line-height: 1.1;
}

.sp-datechip__day   { font-size: var(--sp-fs-h3); font-weight: var(--sp-fw-bold); }
.sp-datechip__month { font-size: 10px; font-weight: var(--sp-fw-bold); letter-spacing: .08em; text-transform: uppercase; }
.sp-datechip__year  { font-size: 10px; opacity: .75; }

/* Document link rows. */
.sp-doclink {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
    padding: var(--sp-space-3);
    border-radius: var(--sp-radius-sm);
    text-decoration: none;
    color: inherit;
}

.sp-doclink:hover { background: var(--sp-canvas); }
.sp-doclink__icon { display: grid; place-items: center; width: 36px; height: 36px; flex: 0 0 auto; border-radius: var(--sp-radius-sm); background: var(--sp-primary-050); color: var(--sp-primary); }
.sp-doclink__name { display: block; font-size: var(--sp-fs-body); font-weight: var(--sp-fw-semibold); color: var(--sp-ink); }
.sp-doclink__desc { display: block; font-size: var(--sp-fs-small); color: var(--sp-muted); }
.sp-doclink__chevron { margin-left: auto; color: var(--sp-muted); }

.sp-doclink--disabled { opacity: .5; pointer-events: none; }

/* =============================================================================
   Prose — long-form guidance copy rendered from trusted HTML
   ========================================================================== */

.sp-prose { line-height: var(--sp-lh-base); color: var(--sp-ink-soft); font-size: var(--sp-fs-body); }
.sp-prose > :first-child { margin-top: 0; }
.sp-prose > :last-child { margin-bottom: 0; }
.sp-prose p { margin: 0 0 var(--sp-space-3); }
.sp-prose h4 {
    font-size: var(--sp-fs-h3);
    font-weight: var(--sp-fw-bold);
    color: var(--sp-ink);
    margin: var(--sp-space-5) 0 var(--sp-space-2);
}
.sp-prose ul, .sp-prose ol { margin: 0 0 var(--sp-space-3); padding-left: var(--sp-space-5); }
.sp-prose li { margin-bottom: var(--sp-space-1); }
.sp-prose strong { color: var(--sp-ink); font-weight: var(--sp-fw-semibold); }
.sp-prose a { color: var(--sp-primary); }

/* Numbered project-journey steps. */
.sp-prose ol.sp-journey { list-style: none; padding-left: 0; counter-reset: sp-journey; }
.sp-prose ol.sp-journey > li {
    counter-increment: sp-journey;
    position: relative;
    padding: var(--sp-space-2) 0 var(--sp-space-3) var(--sp-space-7);
    border-left: 2px solid var(--sp-primary-100);
    margin-left: 14px;
}
.sp-prose ol.sp-journey > li::before {
    content: counter(sp-journey);
    position: absolute;
    left: -15px;
    top: var(--sp-space-2);
    display: grid;
    place-items: center;
    width: 28px; height: 28px;
    border-radius: 50%;
    background: var(--sp-primary);
    color: #fff;
    font-size: var(--sp-fs-small);
    font-weight: var(--sp-fw-bold);
}
.sp-prose ol.sp-journey > li:last-child { border-left-color: transparent; }

/* =============================================================================
   Buttons
   -----------------------------------------------------------------------------
   The canonical button system. Almost every variant is a solid fill with white text and
   a 6px radius. The one exception is --secondary, added for the project-page dialogs the
   mockups spell out as "white with a blue outline and blue writing".

   Three other systems are still in the markup — Telerik's .k-button, Bootstrap's .btn
   and the legacy .button from stroma-portal.css — and each is mapped onto these tokens
   further down the file rather than being rewritten at the call sites.
   ========================================================================== */

.sp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-space-2);
    border: 1px solid transparent;
    border-radius: var(--sp-radius-sm);
    padding: var(--sp-space-3) var(--sp-space-5);
    font: inherit;
    font-size: var(--sp-fs-body);
    font-weight: var(--sp-fw-semibold);
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

.sp-btn:disabled,
.sp-btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

/* Two things about the selectors:

   1. The doubled class (.sp-btn.sp-btn--x, 0-2-0) is deliberate. It has to outscore the
      .k-button-solid-base default in the Telerik mapping below, which is 0-1-0 but sits
      later in the file and would otherwise win on source order. Every call site already
      writes both classes, so no markup had to change.
   2. :active / .k-active are spelled out for the same reason — .k-button-solid-base:active
      is 0-2-0, so without them a TelerikButton would flash neutral grey while pressed. */

.sp-btn.sp-btn--primary { background: var(--sp-primary); border-color: var(--sp-primary); color: #fff; }
.sp-btn.sp-btn--primary:hover:not(:disabled),
.sp-btn.sp-btn--primary:active,
.sp-btn.sp-btn--primary.k-active { background: var(--sp-primary-700); border-color: var(--sp-primary-700); color: #fff; }

/* --outline and --ghost keep their names — 37 call sites — but are no longer outlines.
   They are the subordinate action sitting beside a primary one (Cancel, Save as Draft,
   Refresh, Close): still solid, still white text, just neutral rather than brand blue so
   the hierarchy survives. --ghost drops its tighter padding-inline, which looked cramped
   once the button carried a fill. */
.sp-btn.sp-btn--outline,
.sp-btn.sp-btn--ghost { background: var(--sp-neutral); border-color: var(--sp-neutral); color: #fff; }
.sp-btn.sp-btn--outline:hover:not(:disabled),
.sp-btn.sp-btn--outline:active,
.sp-btn.sp-btn--outline.k-active,
.sp-btn.sp-btn--ghost:hover:not(:disabled),
.sp-btn.sp-btn--ghost:active,
.sp-btn.sp-btn--ghost.k-active { background: var(--sp-neutral-700); border-color: var(--sp-neutral-700); color: #fff; }

/* The one genuine outline. Requested explicitly by the Request Inspection, Site Update and
   Compliance Declaration mockups for the cancel/subordinate action inside a dialog, where a
   solid grey button read as heavier than the primary one beside it. Named --secondary rather
   than reusing --outline, whose 37 call sites all expect the solid neutral above. */
.sp-btn.sp-btn--secondary { background: var(--sp-surface); border-color: var(--sp-primary); color: var(--sp-primary); }
.sp-btn.sp-btn--secondary:hover:not(:disabled),
.sp-btn.sp-btn--secondary:active,
.sp-btn.sp-btn--secondary.k-active { background: var(--sp-primary-050); border-color: var(--sp-primary-700); color: var(--sp-primary-700); }

.sp-btn.sp-btn--danger { background: var(--sp-danger); border-color: var(--sp-danger); color: #fff; }
.sp-btn.sp-btn--danger:hover:not(:disabled),
.sp-btn.sp-btn--danger:active,
.sp-btn.sp-btn--danger.k-active { background: #a31f1f; border-color: #a31f1f; color: #fff; }

/* A positive confirmation (the Quote Acceptance Accept buttons). Disabled, it greys out
   completely rather than fading, because ClickUp 869em4hn9 asks for the button to be "greyed
   out" until usable and again once used ("Accepted"); a half-transparent green reads as
   available. .k-disabled is listed because Telerik adds it, and its own fade, to a disabled
   TelerikButton. */
.sp-btn.sp-btn--success { background: var(--sp-success-strong); border-color: var(--sp-success-strong); color: #fff; }
.sp-btn.sp-btn--success:hover:not(:disabled),
.sp-btn.sp-btn--success:active,
.sp-btn.sp-btn--success.k-active { background: #1b6d2e; border-color: #1b6d2e; color: #fff; }
.sp-btn.sp-btn--success:disabled,
.sp-btn.sp-btn--success.k-disabled {
    background: var(--sp-neutral-bg);
    border-color: var(--sp-line-strong);
    color: var(--sp-neutral);
    opacity: 1;
}

/* Telerik wraps a button's ChildContent in .k-button-text, so an inline <svg> sitting beside
   the label lands inside that span and .sp-btn's own gap never applies between them. Making the
   wrapper a flex row keeps the spacing at one --sp-space-2 whether the icon comes from Telerik's
   Icon parameter or from hand-written SVG (used where the Telerik 5.1.1 SVG set has no glyph —
   there is no paper-plane, for instance). */
.sp-btn .k-button-text { display: inline-flex; align-items: center; gap: var(--sp-space-2); }

.sp-btn--block { width: 100%; }
.sp-btn--sm    { padding: var(--sp-space-2) var(--sp-space-3); font-size: var(--sp-fs-small); }
.sp-btn--lg    { padding: var(--sp-space-4) var(--sp-space-6); }

/* =============================================================================
   Forms
   ========================================================================== */

.sp-field { display: flex; flex-direction: column; gap: var(--sp-space-2); }

.sp-field__label {
    font-size: var(--sp-fs-small);
    font-weight: var(--sp-fw-semibold);
    color: var(--sp-ink);
}

.sp-field__wrap { position: relative; display: flex; align-items: center; }

.sp-field__icon {
    position: absolute;
    left: var(--sp-space-3);
    /* Above the field: .k-input brings its own background and positioning, so without this the
       icon paints underneath it. Harmless for the plain .sp-field__control on the sign-in page. */
    z-index: 2;
    color: var(--sp-muted);
    pointer-events: none;
    display: grid;
    place-items: center;
}

.sp-field__control {
    width: 100%;
    border: 1px solid var(--sp-line-strong);
    border-radius: var(--sp-radius-sm);
    padding: var(--sp-space-3) var(--sp-space-4);
    font: inherit;
    font-size: var(--sp-fs-body);
    color: var(--sp-ink);
    background: var(--sp-surface);
}

.sp-field__control::placeholder { color: var(--sp-muted); }

.sp-field__control:focus {
    outline: none;
    border-color: var(--sp-primary);
    box-shadow: 0 0 0 3px var(--sp-primary-100);
}

.sp-field__wrap--has-icon   .sp-field__control { padding-left: var(--sp-space-8); }
.sp-field__wrap--has-toggle .sp-field__control { padding-right: var(--sp-space-8); }

.sp-field__toggle {
    position: absolute;
    right: var(--sp-space-2);
    display: grid;
    place-items: center;
    width: 34px; height: 34px;
    background: none;
    border: 0;
    border-radius: var(--sp-radius-sm);
    color: var(--sp-muted);
    cursor: pointer;
}

.sp-field__toggle:hover { color: var(--sp-ink); background: var(--sp-canvas); }
.sp-field__toggle--on { color: var(--sp-primary); }
.sp-field__error { font-size: var(--sp-fs-small); color: var(--sp-danger); }

.sp-check { display: inline-flex; align-items: center; gap: var(--sp-space-2); font-size: var(--sp-fs-body); }

.sp-divider {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
    color: var(--sp-muted);
    font-size: var(--sp-fs-small);
}

.sp-divider::before,
.sp-divider::after { content: ""; flex: 1 1 auto; height: 1px; background: var(--sp-line); }

/* =============================================================================
   Auth shell — login, forgot password, reset password
   -----------------------------------------------------------------------------
   Replaces the three duplicated inline <style> blocks that previously leaked
   globally from Login / ForgotPassword / ResetPassword.
   ========================================================================== */

.sp-auth { display: flex; flex-direction: column; min-height: 100vh; }
.sp-auth__main { flex: 1 1 auto; display: flex; align-items: center; }

/* Both columns run to the same height: the welcome heading through the bottom of the info
   card on the left, and the sign-in panel matching it on the right. `stretch` (the grid
   default) does that; `center` previously left them ragged. */
.sp-auth__split {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
    gap: var(--sp-space-7);
    align-items: stretch;
    width: 100%;
    padding-block: var(--sp-space-7);
}

/* Centres the welcome copy and the info card within the row. */
.sp-auth__intro {
    color: #fff;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.sp-auth__panel {
    background: var(--sp-surface);
    border-radius: var(--sp-radius-lg);
    box-shadow: var(--sp-shadow-3);
    padding: var(--sp-space-6);
    max-width: 420px;
    width: 100%;
    justify-self: end;
    /* Fills the taller column, with the form centred rather than stranded at the top. This
       is only stable because the info tabs beside it are now equal-height (see
       .sp-tabs--static): the panel used to grow and shrink with the selected tab. */
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.sp-auth__panel-head { display: flex; align-items: flex-start; gap: var(--sp-space-3); margin-bottom: var(--sp-space-5); }

.sp-auth__panel-icon {
    display: grid;
    place-items: center;
    width: 44px; height: 44px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--sp-primary-050);
    color: var(--sp-primary);
}

.sp-auth__panel-icon:has(img) { background: none; }
.sp-auth__panel-icon img { width: 100%; height: 100%; object-fit: contain; display: block; }

.sp-footer__shield:has(img) { background: none; }
.sp-footer__shield img { width: 100%; height: 100%; object-fit: contain; display: block; }

.sp-auth__panel-icon--success { background: var(--sp-success-bg); color: var(--sp-success); }
.sp-auth__panel-icon--warning { background: var(--sp-warn-bg); color: var(--sp-warn); }

.sp-auth__panel-title { font-size: var(--sp-fs-h2); font-weight: var(--sp-fw-bold); margin: 0; color: var(--sp-ink); }
.sp-auth__panel-sub   { font-size: var(--sp-fs-small); color: var(--sp-muted); margin: 2px 0 0; }

/* The feature card carrying the 4 info tabs. */
.sp-auth__infocard {
    background: var(--sp-surface);
    border-radius: var(--sp-radius-lg);
    box-shadow: var(--sp-shadow-3);
    margin-top: var(--sp-space-6);
    overflow: hidden;
}

.sp-auth__feature {
    display: flex;
    align-items: center;
    gap: var(--sp-space-4);
    padding: var(--sp-space-4) 0;
    border-top: 1px solid var(--sp-line);
}

.sp-auth__feature:first-child { border-top: 0; }

.sp-auth__feature-icon {
    display: grid;
    place-items: center;
    width: 44px; height: 44px;
    flex: 0 0 auto;
    border-radius: 50%;
    border: 1px solid var(--sp-primary-100);
    background: var(--sp-primary-050);
    color: var(--sp-primary);
}

.sp-auth__feature-icon:has(img) { background: none; border-color: transparent; }
.sp-auth__feature-icon img { width: 100%; height: 100%; object-fit: contain; display: block; }
.sp-auth__feature-title { display: block; font-size: var(--sp-fs-body); font-weight: var(--sp-fw-bold); color: var(--sp-ink); }
.sp-auth__feature-desc  { display: block; font-size: var(--sp-fs-small); color: var(--sp-muted); }

.sp-auth__backlink {
    margin-top: var(--sp-space-4);
    padding-top: var(--sp-space-4);
    border-top: 1px solid var(--sp-line);
    text-align: center;
    font-size: var(--sp-fs-small);
}

.sp-auth__backlink a { color: var(--sp-primary); font-weight: var(--sp-fw-semibold); text-decoration: none; }
.sp-auth__backlink a:hover { text-decoration: underline; }

/* Single-column variant for ForgotPassword / ResetPassword / confirmations. */
.sp-auth__split--single { grid-template-columns: minmax(0, 1fr); justify-items: center; }
.sp-auth__split--single .sp-auth__panel { justify-self: center; }

/* =============================================================================
   Telerik surfaces
   -----------------------------------------------------------------------------
   TelerikWindow renders into a popup container OUTSIDE the owning component's
   DOM subtree, so scoped .razor.css never reaches it. Modal styling has to live
   here.
   ========================================================================== */

.sp-modal.k-window {
    border-radius: var(--sp-radius-lg);
    box-shadow: var(--sp-shadow-3);
    border: 1px solid var(--sp-line);
    overflow: hidden;
}

.sp-modal .k-window-titlebar {
    background: var(--sp-surface);
    border-bottom: 1px solid var(--sp-line);
    padding: var(--sp-space-4) var(--sp-space-5);
}

.sp-modal .k-window-title {
    font-family: var(--sp-font);
    font-size: var(--sp-fs-h3);
    font-weight: var(--sp-fw-bold);
    color: var(--sp-navy);
}

.sp-modal .k-window-content { padding: var(--sp-space-5); font-family: var(--sp-font); }
.sp-modal .k-window-actions { padding: 0 var(--sp-space-5) var(--sp-space-5); }

/* Supporting line under a window's title. It sits inside .k-window-title, so it has to undo
   that rule's size and weight explicitly. */
.sp-modal__sub {
    display: block;
    margin: var(--sp-space-1) 0 0;
    font-size: var(--sp-fs-small);
    font-weight: var(--sp-fw-regular);
    color: var(--sp-muted);
}

/* TelerikTextBox renders <span class="k-input"><input class="k-input-inner">, so a field's
   icon and toggle clearance has to go on the inner input; on the wrapper it stacks on top of
   Kendo's own padding and the text still runs underneath. Same trap as the search box below. */
.sp-field__wrap > .k-input { width: 100%; }
.sp-field__wrap--has-toggle .k-input-inner { padding-right: 38px; }
.sp-field__wrap--has-icon   .k-input-inner { padding-left: 34px; }

/* The dialogs' own form: fields in a column. Its buttons are stacked by the shared
   .sp-modal__actions--stacked rule below. */
.sp-userform .k-form-fieldset,
.sp-userform .k-form-field { margin: 0; }

.sp-userform .k-form-field + .k-form-field { margin-top: var(--sp-space-4); }

/* Postcode and its Search button share a line. */
.sp-userform__row { display: flex; align-items: center; gap: var(--sp-space-3); }
.sp-userform__row > .k-input  { flex: 1 1 auto; min-width: 0; }
.sp-userform__row > .k-button { flex: 0 0 auto; }

/* Dialog footer buttons: cancel hard left, primary hard right, as the mockups draw them.
   Deliberately our own class rather than Telerik's footer element — 5.1.1's bootstrap theme
   ships no .k-window-footer rule, and .k-window-actions is also the titlebar control strip,
   so targeting either would be a guess that an upgrade could quietly break. */
.sp-modal__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-3);
    width: 100%;
    margin-top: var(--sp-space-5);
}

/* Stacked variant: primary above secondary, both full width. Shares one rule with the
   TelerikForm FormButtons that Update User Details uses, so the home screen's two dialogs
   cannot drift apart. Must stay after .sp-modal__actions — equal specificity, so it is
   source order that lets the modifier win, and flex-start that undoes space-between. */
.sp-userform .k-form-buttons,
.sp-modal__actions--stacked {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: var(--sp-space-3);
    margin-top: var(--sp-space-5);
}

/* Confirmation popup, drawn by the project email opt in/out mockup (ClickUp 869ev1da1): an
   icon badge, the question as the heading, a divider, then No / Yes at equal width. There is
   no visible title — the titlebar stays only for the close button, so it loses its rule and
   bottom padding. All of these follow the .sp-modal rules above on purpose: equal specificity,
   so source order is what lets them win. */
.sp-modal--confirm.k-window { max-width: calc(100vw - 2 * var(--sp-space-4)); }

.sp-modal--confirm .k-window-titlebar {
    border-bottom: 0;
    padding: var(--sp-space-4) var(--sp-space-4) 0;
}

/* The theme fades the close button to .5 opacity; the mockup has it as a solid grey. */
.sp-modal--confirm .k-window-titlebar .k-window-titlebar-action { color: var(--sp-muted); opacity: 1; }
.sp-modal--confirm .k-window-titlebar .k-window-titlebar-action:hover { color: var(--sp-ink); }

.sp-modal--confirm .k-window-content { padding: 0 var(--sp-space-6) var(--sp-space-7); }

/* The page behind is dimmed and blurred. Telerik renders the overlay as a sibling of the window
   inside .k-dialog-wrapper, so a bare .k-overlay rule would blur every modal — :has() keeps it
   to this one. The theme dims with opacity: .5, which would also halve the blur, so the dim
   moves into the background colour instead (the same 50% black). */
.k-dialog-wrapper:has(.sp-modal--confirm) .k-overlay {
    opacity: 1;
    background-color: rgba(0, 0, 0, .5);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
}

.sp-confirm { text-align: center; }

.sp-confirm__icon {
    display: grid;
    place-items: center;
    width: 88px; height: 88px;
    margin: 0 auto var(--sp-space-4);
    border-radius: 50%;
    background: var(--sp-primary-050);
    color: var(--sp-primary);
}

.sp-confirm__icon svg { width: 60px; height: 60px; }

.sp-confirm__message {
    margin: 0;
    font-size: var(--sp-fs-h2);
    font-weight: var(--sp-fw-semibold);
    line-height: 1.3;
    color: var(--sp-ink);
    text-wrap: balance;
}

/* The top border is the mockup's divider. The side padding keeps the buttons a little narrower
   than it, as drawn; the grid keeps No and Yes the same width whatever their labels. */
.sp-confirm__actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-space-5);
    margin-top: var(--sp-space-5);
    padding: var(--sp-space-6) var(--sp-space-3) 0;
    border-top: 1px solid var(--sp-line);
}

/* The mockup's dialog buttons carry larger labels than the page's. */
.sp-confirm__actions .sp-btn { font-size: var(--sp-fs-h3); }



/* =============================================================================
   Reconnect overlay
   -----------------------------------------------------------------------------
   Components/Layout/ReconnectModal.razor, shown when the Blazor Server circuit
   drops. blazor.web.js drives it purely by class on the root:
   components-reconnect-show (retrying), -failed (gave up), -rejected (server
   back, circuit gone) and -hide. With none of them it stays hidden, which is
   also its state on first paint. Modelled on the confirm dialog above, but as
   plain markup: no Telerik component can render without the circuit.
   ========================================================================== */

/* Above every Telerik layer (overlay 10001, windows 10002, tooltips 12000), so an open dialog
   can't sit on top of it. The scrim is the hero's --sp-navy-900 at 55%, blurred like the confirm
   dialog's backdrop. The card centres itself with margin: auto rather than place-items, so on a
   short screen it top-aligns and scrolls instead of overflowing out of reach above the fold. */
.sp-reconnect {
    position: fixed;
    inset: 0;
    z-index: 20000;
    display: none;
    padding: var(--sp-space-4);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: rgba(15, 38, 69, .55);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
}

/* The 500ms hold copies Blazor's stock screen, which waits that long so a page being left
   doesn't flash it. All three states share one animation name, so moving between them never
   replays it. */
.sp-reconnect.components-reconnect-show,
.sp-reconnect.components-reconnect-failed,
.sp-reconnect.components-reconnect-rejected {
    display: grid;
    animation: sp-reconnect-fade .2s ease-out .5s both;
}

.sp-reconnect.components-reconnect-show .sp-reconnect__card,
.sp-reconnect.components-reconnect-failed .sp-reconnect__card,
.sp-reconnect.components-reconnect-rejected .sp-reconnect__card {
    animation: sp-reconnect-rise .25s ease-out .5s both;
}

@keyframes sp-reconnect-fade { from { opacity: 0; } }
@keyframes sp-reconnect-rise { from { opacity: 0; transform: translateY(8px); } }
@keyframes sp-reconnect-spin { to { transform: rotate(360deg); } }

.sp-reconnect__card {
    width: 100%;
    max-width: 440px;
    margin: auto;
    padding: var(--sp-space-6);
    background: var(--sp-surface);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-lg);
    box-shadow: var(--sp-shadow-3);
    font-family: var(--sp-font);
    color: var(--sp-ink);
    text-align: center;
}

/* Focus sits on the card itself (tabindex -1) while there is nothing to press yet. */
.sp-reconnect__card:focus { outline: none; }

.sp-reconnect__brand {
    padding-bottom: var(--sp-space-5);
    margin-bottom: var(--sp-space-5);
    border-bottom: 1px solid var(--sp-line);
}

.sp-reconnect__brand img { display: block; width: auto; height: 40px; margin: 0 auto; }

.sp-reconnect__state { display: none; }

.sp-reconnect.components-reconnect-show .sp-reconnect__state--show,
.sp-reconnect.components-reconnect-failed .sp-reconnect__state--failed,
.sp-reconnect.components-reconnect-rejected .sp-reconnect__state--rejected { display: block; }

/* Badge tones follow .sp-auth__panel-icon. */
.sp-reconnect__icon {
    position: relative;
    display: grid;
    place-items: center;
    width: 72px; height: 72px;
    margin: 0 auto var(--sp-space-4);
    border-radius: 50%;
    background: var(--sp-primary-050);
    color: var(--sp-primary);
}

.sp-reconnect__icon svg { width: 32px; height: 32px; }

.sp-reconnect__icon--warning { background: var(--sp-warn-bg); color: var(--sp-warn); }

/* A hand-rolled spinner ring: a Telerik loader needs the very circuit this is standing in for. */
.sp-reconnect__icon--busy::after {
    content: "";
    position: absolute;
    inset: -6px;
    border: 3px solid var(--sp-primary-100);
    border-top-color: var(--sp-primary);
    border-radius: 50%;
    animation: sp-reconnect-spin 1s linear infinite;
}

/* Sizes restated in full: the legacy sheet forces every bare <p> to 16/24px (18/28px from 576px)
   and Bootstrap sizes bare <h2>. One class outranks both. */
.sp-reconnect__title {
    margin: 0 0 var(--sp-space-2);
    font-family: var(--sp-font);
    font-size: var(--sp-fs-h2);
    font-weight: var(--sp-fw-bold);
    line-height: var(--sp-lh-tight);
    color: var(--sp-ink);
    text-wrap: balance;
}

.sp-reconnect__message {
    margin: 0;
    font-size: var(--sp-fs-body);
    line-height: var(--sp-lh-base);
    color: var(--sp-ink-soft);
    text-wrap: pretty;
}

.sp-reconnect__attempt { margin-top: var(--sp-space-4); }

/* After Try again, Blazor's counter still reads its last attempt ("8 of 8"). */
.sp-reconnect[data-reconnect-manual] .sp-reconnect__attempt { display: none; }

/* The confirm dialog's divider and equal-width buttons, at the page's own button size. */
.sp-reconnect__actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-space-3);
    margin-top: var(--sp-space-5);
    padding-top: var(--sp-space-5);
    border-top: 1px solid var(--sp-line);
}

.sp-reconnect__actions--single { grid-template-columns: 1fr; }

/* .sp-btn has no focus ring of its own, and these are plain buttons rather than Telerik ones. */
.sp-reconnect .sp-btn:focus-visible { outline: 2px solid var(--sp-primary); outline-offset: 2px; }

@media (max-width: 400px) {
    .sp-reconnect__card { padding: var(--sp-space-5); }
    .sp-reconnect__actions { grid-template-columns: 1fr; }
    .sp-reconnect__actions .sp-btn--primary { order: -1; }
}

/* Same selectors as above so these win on source order. The ring slows rather than stops: with
   nothing else moving, it is the only sign that anything is still happening. */
@media (prefers-reduced-motion: reduce) {
    .sp-reconnect.components-reconnect-show,
    .sp-reconnect.components-reconnect-failed,
    .sp-reconnect.components-reconnect-rejected,
    .sp-reconnect.components-reconnect-show .sp-reconnect__card,
    .sp-reconnect.components-reconnect-failed .sp-reconnect__card,
    .sp-reconnect.components-reconnect-rejected .sp-reconnect__card { animation: none; }

    .sp-reconnect__icon--busy::after { animation-duration: 2.4s; }
}



/* =============================================================================
   Enquiry forms
   -----------------------------------------------------------------------------
   Anglian.razor and Ultraframe.razor are ~1,700 lines of flat form markup each. Rather
   than restructure them, this themes what is already there: headings, section rules, the
   .vl accent bar and labels. Their Telerik controls already pick up the mapping above.
   ========================================================================== */

.sp-enquiry .container { padding-inline: 0; max-width: none; }

.sp-enquiry h1 {
    font-size: var(--sp-fs-h1);
    font-weight: var(--sp-fw-bold);
    color: var(--sp-ink);
    line-height: var(--sp-lh-tight);
    margin: 0;
}

.sp-enquiry h2, .sp-enquiry h3, .sp-enquiry h4 {
    font-size: var(--sp-fs-h3);
    font-weight: var(--sp-fw-bold);
    color: var(--sp-ink);
    margin: var(--sp-space-5) 0 var(--sp-space-3);
}

/* The form's own section accent — was a hard-coded legacy cyan. */
.sp-enquiry .vl {
    border-left: 4px solid var(--sp-primary);
    border-left-color: var(--sp-primary);
    padding-left: var(--sp-space-5);
    height: auto;
}

.sp-enquiry label {
    font-size: var(--sp-fs-small);
    font-weight: var(--sp-fw-semibold);
    color: var(--sp-ink);
    margin-bottom: var(--sp-space-1);
}

.sp-enquiry p { line-height: var(--sp-lh-base); color: var(--sp-ink-soft); }

/* Give the long flat form some rhythm: each top-level row reads as a band. */
.sp-enquiry > .container > .row { padding-block: var(--sp-space-3); }

/* The form's tables use fixed percentage column widths with !important, so below about
   700px they overflow. Contain the scroll inside the form rather than letting the whole
   page scroll sideways. */
.sp-enquiry .container { overflow-x: auto; }
.sp-enquiry table { min-width: 620px; }

.sp-enquiry .form-control {
    border: 1px solid var(--sp-line-strong);
    border-radius: var(--sp-radius-sm);
    padding: var(--sp-space-3) var(--sp-space-4);
    font-size: var(--sp-fs-body);
}

.sp-enquiry .form-control:focus {
    border-color: var(--sp-primary);
    box-shadow: 0 0 0 3px var(--sp-primary-100);
}

/* =============================================================================
   Drop zone
   -----------------------------------------------------------------------------
   A native <input type="file"> already accepts dropped files. Stretching it invisibly
   across the zone means drag-and-drop works with no JS and no change to the upload
   pipeline — the same OnChange handler still receives the files.
   ========================================================================== */

.sp-dropzone {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-space-3);
    min-height: 118px;
    padding: var(--sp-space-5);
    border: 2px dashed var(--sp-line-strong);
    border-radius: var(--sp-radius-md);
    background: var(--sp-canvas);
    text-align: left;
    transition: border-color .15s ease, background-color .15s ease;
}

.sp-dropzone:hover,
.sp-dropzone:focus-within {
    border-color: var(--sp-primary);
    background: var(--sp-primary-050);
}

/* The real input, covering the zone so drops and clicks both land on it. */
.sp-dropzone__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.sp-dropzone__icon { color: var(--sp-primary); flex: 0 0 auto; }
.sp-dropzone__text { display: flex; flex-direction: column; gap: 2px; font-size: var(--sp-fs-body); }
.sp-dropzone__text strong { color: var(--sp-ink); }
.sp-dropzone__text span { color: var(--sp-muted); font-size: var(--sp-fs-small); }

/* The files a pop-up is holding, under its drop zone — SelectedFileList.razor. One row per
   file, the name on the left and its Remove button on the right. */
.sp-filelist {
    list-style: none;
    margin: var(--sp-space-2) 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
}

.sp-filelist__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-3);
    padding: var(--sp-space-2) var(--sp-space-3);
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-sm);
    background: var(--sp-surface);
}

/* Long names wrap rather than push the button out of the pop-up. */
.sp-filelist__name { min-width: 0; overflow-wrap: anywhere; font-size: var(--sp-fs-body); color: var(--sp-ink); }
.sp-filelist__item .sp-btn { flex: 0 0 auto; }
.sp-filelist__empty { margin: var(--sp-space-2) 0 0; font-size: var(--sp-fs-small); color: var(--sp-muted); }

/* =============================================================================
   Tables
   -----------------------------------------------------------------------------
   stroma-portal.css sets `.table > thead > tr { background-color: var(--secondary-color) }`,
   which is the legacy cyan header. Same specificity here (0,1,2) and this sheet loads later,
   so a plain override wins — no !important needed.

   The header fill is --sp-primary-050, not --sp-canvas: the project-page mockups call for a
   light blue table throughout, and the grey was the specific complaint.
   ========================================================================== */

.table > thead > tr,
.richtext table > thead > tr {
    background-color: var(--sp-primary-050);
    color: var(--sp-navy);
}

.table > thead > tr > th,
.richtext table > thead > tr > th {
    font-size: var(--sp-fs-small);
    font-weight: var(--sp-fw-semibold);
    letter-spacing: .01em;
    /* stroma-portal.css puts a full 1px box border in near-black on every cell
       (`.table th, .table td { border: 1px solid #212427 }`). The design uses horizontal
       rules only, so zero the sides rather than just recolouring them. */
    border-width: 0 0 2px 0;
    border-bottom-color: var(--sp-primary-100);
    padding: var(--sp-space-3);
}

.table > tbody > tr > td,
.richtext table > tbody > tr > td {
    border-width: 0 0 1px 0;
    border-color: var(--sp-line);
    padding: var(--sp-space-3);
    vertical-align: middle;
}

.table > tbody > tr:nth-of-type(even),
.richtext table > tbody > tr:nth-of-type(even) {
    background-color: var(--sp-surface);
}

.table > tbody > tr:hover,
.richtext table > tbody > tr:hover {
    background-color: var(--sp-canvas);
}

/* Telerik grid headers, so a grid and a plain table read the same. */
.k-grid .k-table-thead,
.k-grid .k-table-header {
    background-color: var(--sp-primary-050);
    color: var(--sp-navy);
}

/* .project-table is the legacy grid wrapper from stroma-portal.css, whose
   `.project-table .k-table-thead { background-color: #F5F5F5 }` is 0-2-0 and so outscores the
   rule above. Matched here rather than edited there — that sheet is a generated export. */
.project-table .k-table-thead,
.project-table .k-table-header {
    background-color: var(--sp-primary-050);
    color: var(--sp-navy);
}

/* -----------------------------------------------------------------------------
   Dutyholder table, opt-in via .table.sp-dutyholders.

   The Compliance Declaration mockup draws the three dutyholders as a two-column
   table with no header row: the role sits in a light blue label column, the name
   and email in a white value column. So the tint the rules above give a <thead>
   has to move to the first cell of every body row instead — hence <th scope="row">
   rather than a header.

   The backgrounds are stated on the cells, not the rows, because .table already
   paints rows for zebra striping and hover; a cell rule is 0-1-3 against those
   0-1-2 row rules and so wins without touching them or reaching for !important.
   -------------------------------------------------------------------------- */

.sp-dutyholders {
    border: 1px solid var(--sp-line);
    border-radius: var(--sp-radius-md);
    /* Bootstrap's .table is border-collapse: collapse, and a collapsed table ignores both
       border-radius clipping and overflow on the table box — the tinted cells would square
       off the two left corners. Separating the borders restores the clip; the cells draw
       their own single bottom rule, so zero spacing keeps the collapsed look. */
    border-collapse: separate;
    border-spacing: 0;
    overflow: hidden;
}

/* Belt and braces for the clip: only the label column is tinted, so only its corners can
   show. The white value cells are invisible against the dialog surface either way. */
.sp-dutyholders > tbody > tr:first-child > th { border-top-left-radius: var(--sp-radius-md); }
.sp-dutyholders > tbody > tr:last-child  > th { border-bottom-left-radius: var(--sp-radius-md); }

.sp-dutyholders > tbody > tr > th {
    width: 40%;
    background: var(--sp-primary-050);
    color: var(--sp-navy);
    font-size: var(--sp-fs-body);
    font-weight: var(--sp-fw-semibold);
    border-width: 0 0 1px 0;
    border-color: var(--sp-line);
    padding: var(--sp-space-3);
    vertical-align: middle;
}

.sp-dutyholders > tbody > tr > td { background: var(--sp-surface); color: var(--sp-ink-soft); }

/* The outer border already closes the box, so the last row keeps no rule of its own. */
.sp-dutyholders > tbody > tr:last-child > th,
.sp-dutyholders > tbody > tr:last-child > td { border-bottom-width: 0; }

.sp-dutyholders__label { display: flex; align-items: center; gap: var(--sp-space-3); }

/* White, not the --sp-primary-100 the mockup shows. There the badge sits on a grey cell,
   so a light blue disc reads as a circle; against this light blue column it disappears.
   Inverting keeps the badge legible and the column tinted, which is what the ticket asked
   for. The ring stops the white disc floating on the paler fill. */
.sp-dutyholders__badge {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--sp-surface);
    border: 1px solid var(--sp-primary-100);
    color: var(--sp-primary);
    display: grid;
    place-items: center;
}

.sp-dutyholders__email { color: var(--sp-muted); font-size: var(--sp-fs-small); }

/* -----------------------------------------------------------------------------
   Telerik TabStrip, opt-in via Class="sp-tabstrip".

   Kendo's bootstrap theme draws tabs as folder tabs: the active one is a white box with
   a border, on a bordered white content panel. The portal's design is an underline strip
   over a transparent panel, so the box, the borders and the panel padding are all undone
   here and the active tab is marked with a brand-blue bar instead.

   Not applied to every .k-tabstrip, so the Invoices tabs keep the Kendo look until they
   are looked at as well.
   -------------------------------------------------------------------------- */

.sp-tabstrip.k-tabstrip { background: none; }

.sp-tabstrip .k-tabstrip-items-wrapper { border-color: var(--sp-line); }

/* 0-3-0, to outscore the theme's own .k-tabstrip-items-wrapper .k-item colour. */
.sp-tabstrip .k-tabstrip-items-wrapper .k-item {
    background: none;
    border-color: transparent;
    border-radius: 0;
    color: var(--sp-ink-soft);
}

.sp-tabstrip .k-tabstrip-items-wrapper .k-item:hover,
.sp-tabstrip .k-tabstrip-items-wrapper .k-item.k-hover {
    background: none;
    border-color: transparent;
    color: var(--sp-primary);
}

/* The theme sets the active tab's background and border with the same specificity, and
   pairs it with a -1px bottom margin to lift it over the wrapper's rule. Both are undone,
   and the underline is drawn as an inset shadow so it costs no layout. */
.sp-tabstrip .k-tabstrip-items-wrapper .k-item:active,
.sp-tabstrip .k-tabstrip-items-wrapper .k-item.k-active,
.sp-tabstrip .k-tabstrip-items-wrapper .k-item.k-selected {
    margin-bottom: 0;
    background: none;
    border-color: transparent;
    color: var(--sp-primary);
    box-shadow: inset 0 -3px 0 var(--sp-primary);
}

/* The underline above is drawn with box-shadow, which would otherwise replace the theme's
   focus ring outright and leave keyboard users with no indicator on the open tab. */
.sp-tabstrip .k-tabstrip-items-wrapper .k-item:focus,
.sp-tabstrip .k-tabstrip-items-wrapper .k-item.k-focus {
    box-shadow: inset 0 0 0 3px var(--sp-primary-100);
}

.sp-tabstrip .k-tabstrip-items-wrapper .k-item.k-active:focus,
.sp-tabstrip .k-tabstrip-items-wrapper .k-item.k-active.k-focus,
.sp-tabstrip .k-tabstrip-items-wrapper .k-item.k-selected:focus,
.sp-tabstrip .k-tabstrip-items-wrapper .k-item.k-selected.k-focus {
    box-shadow: inset 0 -3px 0 var(--sp-primary), inset 0 0 0 3px var(--sp-primary-100);
}

.sp-tabstrip .k-tabstrip-items-wrapper .k-item .k-link { padding-block: var(--sp-space-3); }

/* Transparent panel, and no inline padding so the content lines up with the page. */
.sp-tabstrip > .k-tabstrip-content,
.sp-tabstrip > .k-content {
    background: none;
    border-width: 0;
    padding-inline: 0;
    padding-block: var(--sp-space-5) 0;
}

/* =============================================================================
   Telerik button mapping
   -----------------------------------------------------------------------------
   Rather than adding .sp-btn to 68 call sites — and still missing Telerik's own
   internal buttons (grid commands, window actions, upload, pager) — map Kendo's
   theme colours onto the design system here. This sheet loads after the Telerik
   theme, so plain selectors win; no !important needed.

   Deliberately limited to colour, font and radius. Padding and sizing are left to
   Telerik, because icon-only buttons (.k-icon-button) and pager controls depend on
   them and would break if overridden.
   ========================================================================== */

.k-button {
    font-family: var(--sp-font);
    font-weight: var(--sp-fw-semibold);
    border-radius: var(--sp-radius-sm);
}

/* "base" is Telerik's default when no ThemeColor is set, so it covers most of the
   TelerikButtons in the app; "secondary" is the 10 that ask for it explicitly. Both
   render as the subordinate action — solid neutral, white text — matching
   .sp-btn--outline / --ghost above.

   This block used to carry !important on every declaration, purely to beat two rules in
   stroma-portal.css: a .k-button-solid-base that forced the legacy slate onto every Kendo
   button, and `.k-rounded-md { border-radius: inherit !important }`, which was squaring
   off every button's corners by making them inherit the parent's radius. Both have now
   been deleted from that sheet, so plain selectors are enough. */
.k-button-solid-base,
.k-button-solid-secondary {
    background-color: var(--sp-neutral);
    border-color: var(--sp-neutral);
    color: #fff;
}

.k-button-solid-base:hover,
.k-button-solid-base.k-hover,
.k-button-solid-base:active,
.k-button-solid-base.k-active,
.k-button-solid-base.k-selected,
.k-button-solid-secondary:hover,
.k-button-solid-secondary.k-hover,
.k-button-solid-secondary:active,
.k-button-solid-secondary.k-active,
.k-button-solid-secondary.k-selected {
    background-color: var(--sp-neutral-700);
    border-color: var(--sp-neutral-700);
    color: #fff;
}

.k-button-solid-primary {
    background-color: var(--sp-primary);
    border-color: var(--sp-primary);
    color: #fff;
}

.k-button-solid-primary:hover,
.k-button-solid-primary.k-hover {
    background-color: var(--sp-primary-700);
    border-color: var(--sp-primary-700);
    color: #fff;
}

.k-button-solid-success {
    background-color: var(--sp-success);
    border-color: var(--sp-success);
    color: #fff;
}

.k-button-solid-error {
    background-color: var(--sp-danger);
    border-color: var(--sp-danger);
    color: #fff;
}

.k-button-solid-warning {
    background-color: var(--sp-warn);
    border-color: var(--sp-warn);
    color: #fff;
}

/* Info deliberately reuses the brand blue rather than --sp-cyan: white on #2dafe6 is
   2.5:1, well under the 4.5:1 WCAG AA floor. Every other fill here clears it. */
.k-button-solid-info {
    background-color: var(--sp-primary);
    border-color: var(--sp-primary);
    color: #fff;
}

/* Icon-only buttons (window close, pager arrows, picker toggles) stay transparent — a
   solid grey block behind every dialog ✕ and pager arrow would be noise. At 0-2-0 these
   outscore the base rules above. */
.k-icon-button.k-button-solid-base {
    background-color: transparent;
    border-color: transparent;
    color: var(--sp-muted);
}

.k-icon-button.k-button-solid-base:hover,
.k-icon-button.k-button-solid-base.k-hover,
.k-icon-button.k-button-solid-base:active,
.k-icon-button.k-button-solid-base.k-active {
    background-color: var(--sp-canvas);
    border-color: transparent;
    color: var(--sp-ink);
}

/* =============================================================================
   Legacy .button mapping
   -----------------------------------------------------------------------------
   The .button family in stroma-portal.css is a marketing-site export, used only by
   AdminUserManagement.razor (22 buttons). It was already solid + white text, but in
   the legacy cyan, with a 5px radius, a heavy drop shadow, a translateY lift on hover
   and an expanding #333 ::after ripple — unmistakably a different button system.

   Its declarations used to be !important, which is why the .sp-btn system was built
   alongside it rather than over it. Those flags have now been removed from that sheet,
   so this maps it onto the design system with plain selectors and source order.
   ========================================================================== */

.button {
    background: var(--sp-primary);
    color: #fff;
    border-radius: var(--sp-radius-sm);
    box-shadow: none;
    transform: none;
}

/* The ripple pseudo-element has no counterpart in the design system. */
.button::after { display: none; }

.button:hover,
.button:active {
    background: var(--sp-primary-700);
    color: #fff;
    box-shadow: none;
    transform: none;
}

.button--primary        { background: var(--sp-primary); color: #fff; }
.button--primary:hover  { background: var(--sp-primary-700); }

.button--secondary,
.button--white          { background: var(--sp-neutral); border-color: var(--sp-neutral); color: #fff; }
.button--secondary:hover,
.button--white:hover    { background: var(--sp-neutral-700); color: #fff; }

.button--danger         { background: var(--sp-danger); border-color: var(--sp-danger); color: #fff; }
.button--danger:hover   { background: #a31f1f; color: #fff; }

.button--success        { background: var(--sp-success); border-color: var(--sp-success); color: #fff; }

/* --warning and --info were black-on-amber and black-on-cyan. Both move to the design
   system's own status colours with white text. */
.button--warning        { background: var(--sp-warn); border-color: var(--sp-warn); color: #fff; }
.button--info           { background: var(--sp-primary); border-color: var(--sp-primary); color: #fff; }

/* =============================================================================
   Bootstrap button mapping
   -----------------------------------------------------------------------------
   ~65 buttons on the login, register, account and administration pages still use
   Bootstrap's .btn classes. This sheet loads after both bootstrap.min.css and app.css,
   so plain selectors win on source order and the whole app lands on one palette.

   This block sits after the legacy .button block on purpose: AdminUserManagement has a
   few buttons carrying both systems at once (Class="button btn-danger"), where the
   Bootstrap half is the one carrying the meaning.

   .btn-link is deliberately absent — it is a text link, not a button.
   ========================================================================== */

.btn {
    border-radius: var(--sp-radius-sm);
    font-weight: var(--sp-fw-semibold);
}

.btn-primary { background-color: var(--sp-primary); border-color: var(--sp-primary); color: #fff; }
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active { background-color: var(--sp-primary-700); border-color: var(--sp-primary-700); color: #fff; }

.btn-secondary { background-color: var(--sp-neutral); border-color: var(--sp-neutral); color: #fff; }
.btn-secondary:hover,
.btn-secondary:focus,
.btn-secondary:active { background-color: var(--sp-neutral-700); border-color: var(--sp-neutral-700); color: #fff; }

.btn-danger { background-color: var(--sp-danger); border-color: var(--sp-danger); color: #fff; }
.btn-danger:hover,
.btn-danger:focus,
.btn-danger:active { background-color: #a31f1f; border-color: #a31f1f; color: #fff; }

.btn-success { background-color: var(--sp-success); border-color: var(--sp-success); color: #fff; }

/* Bootstrap ships these two as black-on-amber and black-on-cyan. White text on the
   design system's own amber clears AA; its cyan does not, so info reuses the brand blue. */
.btn-warning { background-color: var(--sp-warn); border-color: var(--sp-warn); color: #fff; }
.btn-info    { background-color: var(--sp-primary); border-color: var(--sp-primary); color: #fff; }

/* =============================================================================
   Responsive
   ========================================================================== */

@media (max-width: 991.98px) {
    :root { --sp-fs-display: 1.75rem; --sp-tile-lift: 32px; }

    .sp-auth__split {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--sp-space-5);
    }

    .sp-auth__panel { justify-self: center; max-width: 480px; justify-content: flex-start; }
    .sp-auth__intro { justify-content: flex-start; }
    .sp-auth__intro { text-align: center; }
    .sp-auth__intro .sp-hero__sub { margin-inline: auto; }

    .sp-hero--tall { min-height: auto; }
    .sp-hero__scrim { background: linear-gradient(180deg, rgba(15,38,69,.92) 0%, rgba(15,38,69,.86) 100%); }

    .sp-list__row { flex-wrap: wrap; }
    .sp-list__field { min-width: 120px; }
}

@media (max-width: 767.98px) {
    .sp-container { padding-inline: var(--sp-space-4); }

    .sp-navbar__toggle { display: inline-grid; place-items: center; }

    .sp-navbar__list {
        display: none;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        width: 100%;
        padding-bottom: var(--sp-space-3);
    }

    .sp-navbar__state:checked ~ .sp-navbar__list { display: flex; }
    .sp-userchip__name { display: none; }
    .sp-navbar__inner { flex-wrap: wrap; }
    .sp-navbar__link { border-bottom: 0; padding-block: var(--sp-space-3); }

    .sp-logobar__inner { min-height: 64px; }
    .sp-logobar__logo img { max-height: 40px; }

    .sp-accordion__header { padding-inline: var(--sp-space-4); gap: var(--sp-space-3); }
    .sp-accordion__panel  { padding-inline: var(--sp-space-4); }
    .sp-card__header, .sp-card__body, .sp-card__footer { padding-inline: var(--sp-space-4); }

    .sp-list__row { align-items: flex-start; }
    .sp-list__action { width: 100%; }
    .sp-list__action .sp-btn { width: 100%; }

    .sp-statrow--divided { grid-template-columns: minmax(0, 1fr); }
    .sp-statrow--divided .sp-stat { border-left: 0; border-top: 1px solid var(--sp-line); }
    .sp-statrow--divided .sp-stat:first-child { border-top: 0; }

    .sp-footer__inner { flex-direction: column; align-items: flex-start; }
}

/* ---------------------------------------------------------------------------
   Search box

   Global rather than in a page's scoped CSS for two reasons: it styles Telerik's
   own internals (.k-input-inner), which never carry a scope attribute, and the
   box sits inside a PortalCard's HeaderActions.

   These rules previously lived in Home.razor.css anchored on .sp-home__projects
   — a class passed as a Class parameter to PortalCard. That div is rendered
   inside PortalCard.razor, so it never carried Home's scope id, and every rule
   compiled to .sp-home__projects[b-1mdxu3y2r8] ... which matched nothing. The
   box had no styling at all: the magnifier sat beside the field instead of
   inside it, and the clear button rendered as a full-size outlined button.

   TelerikTextBox renders <span class="k-input"><input class="k-input-inner">>,
   so Class lands on the wrapper. Padding must go on the inner input — on the
   wrapper it stacks on top of Kendo's own 12px and leaves typed text running
   underneath the clear button.
   --------------------------------------------------------------------------- */
.sp-search {
    position: relative;
    display: flex;
    align-items: center;
    width: 300px;
    max-width: 100%;
}

.sp-search__input { width: 100%; }

.sp-search__input .k-input-inner {
    padding-left: 34px;    /* clears the magnifier */
    padding-right: 38px;   /* clears the clear button */
}

.sp-search__icon {
    position: absolute;
    left: var(--sp-space-3);
    /* Centred explicitly. An abspos child of a flex container inherits its static position from
       align-items, which would centre it — but only as a side effect, and only once it has no
       vertical offset of its own. Stating it directly is not worth leaving to that. */
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    display: grid;
    place-items: center;
    color: var(--sp-muted);
    pointer-events: none;
}

/* Qualified with .k-button (0-2-0) so it outscores the .k-button-solid-base default
   without needing !important. A clear affordance inside a field should read as a glyph,
   not as a second solid button sitting beside the input. */
.k-button.sp-search__clear {
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 30px;
    height: 30px;
    min-width: 0;
    padding: 0;
    border-radius: var(--sp-radius-sm);
    background-color: transparent;
    border-color: transparent;
    color: var(--sp-muted);
}

.k-button.sp-search__clear:hover,
.k-button.sp-search__clear.k-hover {
    background-color: var(--sp-primary-050);
    color: var(--sp-primary-700);
}

@media (max-width: 767.98px) {
    .sp-search { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    .sp-ring__value,
    .sp-accordion__chevron,
    .sp-btn { transition: none; }
}


/* ===========================================================================
   Building Safety Levy annex questionnaire
   A long, mostly-static legal form: one card per numbered question, answers on
   the right, and free-text panels that appear only for the branch in play.
   =========================================================================== */

.sp-bsl > .sp-card { margin-bottom: var(--sp-space-4); }

.sp-bsl__title {
    font-size: 1.75rem;
    line-height: 1.2;
    color: var(--sp-navy);
    margin: var(--sp-space-5) 0 var(--sp-space-4);
}

/* Read-only project details above question 1: Our reference, Service details and the site address.
   Columns side by side where there is room, a single column on a phone. */
.sp-bsl__reference {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: var(--sp-space-3) var(--sp-space-5);
    padding: var(--sp-space-3) var(--sp-space-4);
    margin-bottom: var(--sp-space-4);
    background: var(--sp-primary-050);
    border-radius: var(--sp-radius-sm);
    color: var(--sp-ink-soft);
}

.sp-bsl__reference .sp-readonlyfield { margin-bottom: 0; }

/* Long service names and unbroken address lines wrap rather than push the page sideways. */
.sp-bsl__reference .sp-readonlyfield__value { overflow-wrap: anywhere; }

/* Question 8's instruction: larger than a card subtitle and in black, as spec S47 CR-4.1 asks. */
.sp-bsl__instruction {
    font-size: var(--sp-fs-h3);
    color: #000;
    margin: 0 0 var(--sp-space-3);
}

.sp-bsl__new-client-hint { margin: var(--sp-space-3) 0 0; }

/* Question label left, Yes/No right, stacking on narrow screens. */
.sp-bsl__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-3);
    padding: var(--sp-space-3) 0;
    border-bottom: 1px solid var(--sp-line);
}

.sp-bsl__row:last-child { border-bottom: 0; }

.sp-bsl__label {
    flex: 1 1 22rem;
    color: var(--sp-ink-soft);
}

.sp-bsl__detail-label {
    display: block;
    margin: var(--sp-space-3) 0 var(--sp-space-1);
    font-weight: 600;
    color: var(--sp-primary-700);
}

.sp-bsl__statement-text {
    color: var(--sp-ink-soft);
    margin-bottom: var(--sp-space-3);
}

/* Questions 4 and 5 sit side by side, as in the mockup. */
.sp-bsl__pair {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--sp-space-4);
    margin-bottom: var(--sp-space-4);
}

.sp-bsl__pair > .sp-card { margin-bottom: 0; }

.sp-bsl__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: var(--sp-space-4);
}

.sp-bsl__notes {
    background: var(--sp-canvas);
    font-size: 0.9375rem;
    color: var(--sp-ink-soft);
}

.sp-bsl__notes p { margin-bottom: var(--sp-space-3); }

.sp-bsl__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--sp-space-3);
    margin: var(--sp-space-5) 0 var(--sp-space-7);
}

@media (max-width: 575.98px) {
    .sp-bsl__actions { flex-direction: column-reverse; }
    .sp-bsl__actions .sp-btn { width: 100%; }
}

/* =============================================================================
   Loader container positioning
   -----------------------------------------------------------------------------
   Every page using <TelerikLoaderContainer Class="min-vh-100 full-height"> carried
   its own identical copy of this rule in an inline <style> block. Hoisted here so a
   page that has otherwise migrated to the design system does not need to keep an
   inline style block alive purely for its loader. The local copies are byte-identical,
   so pages that still declare their own are unaffected.
   ========================================================================== */

.full-height {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

/* ============================================================================
   Quote Acceptance form (Components/Pages/QuoteAcceptance)
   Page-specific, like the .sp-bsl block above. Laid out to the mockup attached to ClickUp
   869em4hn9: a branded header, blue section headings with round icons, navy labels to the left
   of their fields in two columns, and green/red Accept/Reject buttons.
   Classes are not scoped under .sp-quote because the Reject dialog renders outside it (a
   TelerikWindow is portalled to the root component).
   ========================================================================= */

/* Tighter than .sp-page's default gap: the form is a long run of cards, as in the mockup. */
.sp-quote {
  gap: var(--sp-space-4);
}

/* -- Page header ------------------------------------------------------------ */

/* Three equal-weight tracks so the title stays centred whether or not the logo is present (signed
   out only — signed in, PortalHeader already shows it); the right-hand track is an empty balance.
   Sticky, so the form stays identified all the way down. It floats just below the top edge, raised
   by a shadow, rather than butting against it, where its rounded corners would show the page
   scrolling past. The z-index clears the cards (some lift themselves to 2) but stays
   under the portal nav's dropdown (60) and Telerik's popups and dialogs (10000+). */
.sp-quote__header {
  position: sticky;
  top: var(--sp-space-2);
  z-index: 40;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sp-space-4);
  padding: var(--sp-space-4) var(--sp-space-5);
  background: var(--sp-surface);
  border: 1px solid var(--sp-line);
  border-radius: var(--sp-radius-md);
  box-shadow: var(--sp-shadow-2);
}

/* Keeps a field the browser scrolls to (tabbing through the form, a focused validation error)
   clear of the sticky header rather than tucked under it. Only while the form is on the page. */
html:has(.sp-quote__header) {
  scroll-padding-top: 7rem;
}

.sp-quote__header-brand { justify-self: start; }
.sp-quote__header-actions { justify-self: end; }

.sp-quote__logo {
  display: block;
  width: auto;
  height: auto;
  max-height: 52px;
  max-width: 100%;
}

.sp-quote__title {
  margin: 0;
  font-size: var(--sp-fs-h1);
  font-weight: var(--sp-fw-bold);
  line-height: var(--sp-lh-tight);
  color: var(--sp-navy-900);
  text-align: center;
}

/* -- Loading (QuoteLoadingCard.razor) ---------------------------------------- */

/* The reconnect overlay's card — logo, spinner badge, title, message — standing on the page rather
   than over it, centred in the space the form is about to fill. Sizes are restated in full for the
   same reason as .sp-reconnect__title: the legacy sheet sizes every bare <p>, Bootstrap every <h1>. */
.sp-quote__loading {
  display: grid;
  place-items: center;
  min-height: 60vh;
}

.sp-quote__loading-card {
  width: 100%;
  max-width: 440px;
  padding: var(--sp-space-6);
  background: var(--sp-surface);
  border: 1px solid var(--sp-line);
  border-radius: var(--sp-radius-lg);
  box-shadow: var(--sp-shadow-2);
  text-align: center;
}

.sp-quote__loading-brand {
  padding-bottom: var(--sp-space-5);
  margin-bottom: var(--sp-space-5);
  border-bottom: 1px solid var(--sp-line);
}

.sp-quote__loading-brand img {
  display: block;
  width: auto;
  height: 40px;
  margin: 0 auto;
}

.sp-quote__loading-icon {
  position: relative;
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  margin: 0 auto var(--sp-space-4);
  border-radius: 50%;
  background: var(--sp-primary-050);
  color: var(--sp-primary);
}

.sp-quote__loading-icon .k-svg-icon {
  width: 32px;
  height: 32px;
}

/* The spinner ring, as .sp-reconnect__icon--busy draws it. */
.sp-quote__loading-icon::after {
  content: "";
  position: absolute;
  inset: -6px;
  border: 3px solid var(--sp-primary-100);
  border-top-color: var(--sp-primary);
  border-radius: 50%;
  animation: sp-quote-spin 1s linear infinite;
}

@keyframes sp-quote-spin { to { transform: rotate(360deg); } }

.sp-quote__loading-title {
  margin: 0 0 var(--sp-space-2);
  font-size: var(--sp-fs-h2);
  font-weight: var(--sp-fw-bold);
  line-height: var(--sp-lh-tight);
  color: var(--sp-navy-900);
}

.sp-quote__loading-message {
  margin: 0;
  font-size: var(--sp-fs-body);
  line-height: var(--sp-lh-base);
  color: var(--sp-ink-soft);
}

/* Slowed rather than stopped, as the reconnect ring is: it is the only sign anything is happening. */
@media (prefers-reduced-motion: reduce) {
  .sp-quote__loading-icon::after {
    animation-duration: 2.4s;
  }
}

/* -- Cards and section headings --------------------------------------------- */

/* Applied to PortalCard's .sp-card. Body copy is navy throughout, as in the mockup. */
.sp-quote__card {
  border-radius: var(--sp-radius-md);
  color: var(--sp-navy);
}

/* stroma-portal.css sizes every bare <p> at 18px/28px, far larger than the form's labels. */
.sp-quote__card p,
.sp-quote__card li {
  font-size: var(--sp-fs-body);
  line-height: var(--sp-lh-base);
}

.sp-quote__card p {
  margin: 0 0 var(--sp-space-3);
}

.sp-quote__card p:last-child {
  margin-bottom: 0;
}

.sp-quote__heading {
  display: flex;
  align-items: center;
  gap: var(--sp-space-3);
  margin: 0 0 var(--sp-space-5);
  font-size: var(--sp-fs-h3);
  font-weight: var(--sp-fw-bold);
  line-height: var(--sp-lh-tight);
  color: var(--sp-primary);
}

/* The fee cards' headings sit directly on their value box, with no icon to space them out. */
.sp-quote__heading--compact {
  margin-bottom: var(--sp-space-3);
}

/* The round badge before a heading. --soft (pale fill, blue glyph) marks the document-like
   sections, as .sp-page__titleicon does; --solid (blue fill, white glyph) marks the people
   sections, as .sp-accordion__icon does. */
.sp-quote__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
}

.sp-quote__icon--soft {
  background: var(--sp-primary-050);
  color: var(--sp-primary);
}

.sp-quote__icon--solid {
  background: var(--sp-primary);
  color: #fff;
}

.sp-quote__icon .k-svg-icon {
  width: 22px;
  height: 22px;
}

/* A heading inside a section: "Commencement is defined as follows:". */
.sp-quote__subheading {
  margin: var(--sp-space-5) 0 var(--sp-space-3);
  font-size: 1.0625rem;
  font-weight: var(--sp-fw-bold);
  color: var(--sp-primary);
}

/* Guidance under an optional section's heading. Prefixed with .sp-quote__card, like the other
   paragraph classes here, to outrank the ".sp-quote__card p" size and margin above. */
.sp-quote__card .sp-quote__hint {
  margin-top: calc(-1 * var(--sp-space-3));
  font-size: var(--sp-fs-small);
  color: var(--sp-muted);
}

/* The small print under the fee boxes. */
.sp-quote__card .sp-quote__note {
  margin: var(--sp-space-2) 0 0;
  font-size: var(--sp-fs-small);
}

/* -- Field layout ----------------------------------------------------------- */

/* Two columns on desktop, one on narrower screens. */
.sp-quote__cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--sp-space-6);
}

/* The two fee cards side by side use the page's card gap instead. */
.sp-quote__cols--cards {
  column-gap: var(--sp-space-4);
  row-gap: var(--sp-space-4);
}

/* A label to the left of its field. The label is padded down so its text sits on the same line
   as the text inside a single-line input. */
.sp-quote__row {
  display: grid;
  grid-template-columns: 9.5rem minmax(0, 1fr);
  align-items: start;
  column-gap: var(--sp-space-3);
  margin-bottom: var(--sp-space-3);
}

/* Label above the field instead. */
.sp-quote__row--stacked {
  grid-template-columns: minmax(0, 1fr);
}

.sp-quote__label {
  display: block;
  margin: 0;
  padding-top: 0.5rem;
  font-size: 0.875rem;
  font-weight: var(--sp-fw-bold);
  line-height: 1.4;
  color: var(--sp-navy);
}

.sp-quote__row--stacked .sp-quote__label {
  padding-top: 0;
  margin-bottom: var(--sp-space-1);
}

/* "(if applicable)", "(optional)". */
.sp-quote__label-note {
  font-weight: var(--sp-fw-regular);
}

/* Bigger and heavier than the label so it stands out. Raleway draws a small, raised asterisk even
   at its heaviest loaded weight (700), so this one glyph is set in Arial Black (Arial where that is
   missing), which draws a large, solid one, and nudged down to sit level with the label's letters.
   line-height 0 stops the bigger glyph pushing the label's line taller and out of line with its
   input. */
.sp-quote__required {
  position: relative;
  top: 0.2em;
  margin-left: 3px;
  font-family: "Arial Black", Arial, sans-serif;
  font-size: 1.3em;
  font-weight: 900;
  line-height: 0;
  color: var(--sp-danger);
}

/* The right-hand column of a contact section starts level with the Company input rather than
   its label, as the mockup draws it. The offset is one stacked label: line height plus margin. */
.sp-quote__col--offset {
  padding-top: calc(0.875rem * 1.4 + var(--sp-space-1));
}

/* A value the customer cannot change, drawn in an input-shaped box so it lines up with the
   editable fields beside it. The grey fill is what says "not editable". */
.sp-quote__value {
  min-height: 38px;
  padding: 0.4375rem 0.75rem;
  border: 1px solid var(--sp-line-strong);
  border-radius: var(--sp-radius-sm);
  background: var(--sp-canvas);
  font-size: var(--sp-fs-body);
  line-height: 1.5;
  color: var(--sp-ink);
  /* Addresses arrive as a single comma-joined string; preserve any newlines they do carry. */
  white-space: pre-line;
  overflow-wrap: anywhere;
}

.sp-quote__value--multiline {
  min-height: 4.5rem;
}

/* The prompt in an address box that has no address yet. */
.sp-quote__value--placeholder {
  font-style: italic;
  color: var(--sp-muted);
}

/* -- Address lookup (QuoteAddressLookup.razor) ------------------------------- */

/* Postcode and Find address, then the results list, then the read-only address box. */
.sp-quote__address {
  display: grid;
  gap: var(--sp-space-2);
}

.sp-quote__address-search {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-space-2);
}

.sp-quote__card .sp-quote__address-message {
  margin: 0;
  font-size: var(--sp-fs-small);
  color: var(--sp-muted);
}


/* An optional section's Clear details / Undo changes, at its foot. */
.sp-quote__section-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--sp-space-2);
}

/* -- Fee & Payment Terms ---------------------------------------------------- */

/* The billing-profile stages under Payment Terms, one per line. */
/* Payment Terms' main content now the schedule's name is gone, so it sits straight under the
   heading. */
.sp-quote__stages {
  margin: 0;
  padding-left: 1.25rem;
}

/* -- Commencement Notification ----------------------------------------------- */

/* Drawn as a two-column table (Information Required | Date) but built from a grid, so the
   row can stack on a phone. */
.sp-quote__table {
  margin: var(--sp-space-4) 0 var(--sp-space-2);
  border: 1px solid var(--sp-line);
  border-radius: var(--sp-radius-sm);
}

.sp-quote__table-head,
.sp-quote__table-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 16rem;
}

.sp-quote__table-head > *,
.sp-quote__table-row > * {
  padding: var(--sp-space-3) var(--sp-space-4);
}

.sp-quote__table-head > * + *,
.sp-quote__table-row > * + * {
  border-left: 1px solid var(--sp-line);
}

.sp-quote__table-head {
  background: var(--sp-primary-050);
  border-bottom: 1px solid var(--sp-primary-100);
  border-radius: var(--sp-radius-sm) var(--sp-radius-sm) 0 0;
  font-size: 0.875rem;
  font-weight: var(--sp-fw-bold);
  color: var(--sp-navy);
}

.sp-quote__table-row {
  align-items: center;
}

.sp-quote__table-label {
  margin: 0;
  font-size: var(--sp-fs-body);
  font-weight: var(--sp-fw-regular);
  color: var(--sp-navy);
}

.sp-quote__notes {
  margin: 0 0 var(--sp-space-4);
  padding-left: 1.25rem;
}

.sp-quote__notes li {
  margin-bottom: var(--sp-space-2);
}

.sp-quote__notes li::marker {
  color: var(--sp-primary);
}

.sp-quote__notes strong {
  color: var(--sp-navy-900);
}

/* -- Document acceptance boxes ------------------------------------------------ */

.sp-quote__document-title {
  margin: 0 0 var(--sp-space-3);
  font-size: var(--sp-fs-h3);
  font-weight: var(--sp-fw-bold);
  color: var(--sp-primary);
  text-align: center;
}

/* The box a published PDF is shown in (TelerikPdfViewer, Height="100%"). Taller than the HTML box:
   the viewer spends some of it on its toolbar, and an A4 page needs the room to be readable. */
.sp-quote__pdf {
  height: 600px;
  border: 1px solid var(--sp-line-strong);
  border-radius: var(--sp-radius-sm);
  overflow: hidden;
  background: var(--sp-canvas);
}

/* The viewer brings its own border; the box above already draws one. */
.sp-quote__pdf .k-pdf-viewer {
  border: 0;
}

/* Telerik 5.1.1 sizes each page's text layer (the invisible, selectable copy of the text) with the
   page's width as its height. On a landscape page that runs below the page, and below the last page
   it becomes blank scroll space, which the customer then has to scroll through before Accept is
   enabled. Portrait pages are unaffected. This caps the layer at its page's height. */
.sp-quote__pdf .k-pdf-viewer .k-page .k-text-layer {
  max-height: 100%;
}

/* Loading, or the "couldn't display this document" notice, centred in the box. */
.sp-quote__pdf-status {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-space-3);
  height: 100%;
  padding: var(--sp-space-5);
  text-align: left;
}

.sp-quote__card .sp-quote__pdf-status > p {
  margin: 0;
  color: var(--sp-muted);
}

.sp-quote__document-actions {
  display: flex;
  justify-content: center;
  margin-top: var(--sp-space-3);
}

.sp-quote__card .sp-quote__document-hint,
.sp-quote__card .sp-quote__document-link {
  margin: var(--sp-space-2) 0 0;
  font-size: var(--sp-fs-small);
  text-align: center;
}

.sp-quote__document-hint {
  font-style: italic;
  color: var(--sp-muted);
}

/* -- Quote accepted/rejected by ------------------------------------------------- */

/* Accept centred under the Name column and Reject under the Email column, as in the mockup. */
.sp-quote__decision {
  margin-top: var(--sp-space-3);
  row-gap: var(--sp-space-3);
}

.sp-quote__decision > div {
  display: flex;
  justify-content: center;
}

.sp-quote__decision .sp-btn {
  min-width: 11rem;
}

/* What still stops Accept, listed under the buttons while Accept is greyed out. Boxed in the
   portal's danger-alert colours (as .sp-alert--danger / Bootstrap alert-danger) so it isn't lost
   at the foot of the card. Not .sp-alert itself: that is a centred flex row, which would set the
   heading beside the list. */
.sp-quote__outstanding {
  margin-top: var(--sp-space-5);
  padding: var(--sp-space-4);
  background: var(--sp-danger-bg);
  border: 1px solid #f5c6c6;
  border-radius: var(--sp-radius-md);
  color: var(--sp-danger);
}

.sp-quote__card .sp-quote__outstanding p,
.sp-quote__card .sp-quote__outstanding li {
  font-size: 0.875rem;
}

.sp-quote__card .sp-quote__outstanding p {
  margin-bottom: var(--sp-space-1);
}

.sp-quote__outstanding ul {
  margin: 0;
  padding-left: 1.25rem;
}

/* -- Outcome pop-ups (QuoteOutcomeDialog.razor) --------------------------------- */

/* After Accept or Reject, laid out to the designs attached to ClickUp 869em3y2z: the logo, a solid
   round icon — blue tick or red cross — the title, the wording, and Close, all centred. The same
   titlebar treatment as the closed pop-ups below: no drawn title, just the close button floated in
   the corner. These follow the .sp-modal rules on purpose: equal specificity, so source order is
   what lets them win. */
.sp-quote-outcome.k-window {
  max-width: calc(100vw - 2 * var(--sp-space-4));
  max-height: calc(100vh - 2 * var(--sp-space-4));
}

.sp-quote-outcome .k-window-content {
  padding: var(--sp-space-6) var(--sp-space-7) var(--sp-space-6);
  color: var(--sp-navy);
  text-align: center;
}

.sp-quote-outcome .k-window-titlebar {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1;
  padding: var(--sp-space-3);
  background: transparent;
  border-bottom: 0;
}

.sp-quote-outcome .k-window-titlebar-action { color: var(--sp-muted); opacity: 1; }
.sp-quote-outcome .k-window-titlebar-action:hover { color: var(--sp-ink); }

.k-dialog-wrapper:has(.sp-quote-outcome) .k-overlay {
  opacity: 1;
  background-color: rgba(0, 0, 0, .5);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}

.sp-quote-outcome__brand img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 60px;
  margin: 0 auto;
}

/* The designs' solid disc with a white glyph. */
.sp-quote-outcome__icon {
  position: relative;
  display: grid;
  place-items: center;
  width: 88px;
  height: 88px;
  margin: var(--sp-space-5) auto var(--sp-space-4);
  border-radius: 50%;
  color: #fff;
}

.sp-quote-outcome__icon .k-svg-icon {
  width: 48px;
  height: 48px;
}

.sp-quote-outcome__icon--accepted { background: var(--sp-primary); }
.sp-quote-outcome__icon--declined { background: var(--sp-danger); }

/* While the CRM follow-up runs: the loading card's spinning ring (.sp-quote__loading-icon), round
   the disc, in the disc's own colour. */
.sp-quote-outcome__icon--busy::after {
  content: "";
  position: absolute;
  inset: -8px;
  border: 3px solid var(--sp-primary-100);
  border-top-color: var(--sp-primary);
  border-radius: 50%;
  animation: sp-quote-spin 1s linear infinite;
}

.sp-quote-outcome__icon--declined.sp-quote-outcome__icon--busy::after {
  border-color: var(--sp-danger-bg);
  border-top-color: var(--sp-danger);
}

/* Sizes are restated in full: Bootstrap sizes every <h2>, the legacy sheet every bare <p>. */
.sp-quote-outcome__title {
  margin: 0 0 var(--sp-space-4);
  font-size: 1.625rem;
  font-weight: var(--sp-fw-bold);
  line-height: var(--sp-lh-tight);
  color: var(--sp-navy-900);
  text-wrap: balance;
}

.sp-quote-outcome__message p {
  margin: 0 0 var(--sp-space-3);
  font-size: 1.0625rem;
  line-height: var(--sp-lh-base);
  color: var(--sp-ink);
  text-wrap: pretty;
}

.sp-quote-outcome__message p:last-child {
  margin-bottom: 0;
}

.sp-quote-outcome__message a {
  color: var(--sp-primary);
  font-weight: var(--sp-fw-semibold);
}

.sp-quote-outcome .sp-quote-outcome__status {
  margin: var(--sp-space-4) 0 0;
  font-size: var(--sp-fs-small);
  font-style: italic;
  color: var(--sp-muted);
}

.sp-quote-outcome__actions {
  display: flex;
  justify-content: center;
  margin-top: var(--sp-space-5);
}

.sp-quote-outcome__actions .sp-btn {
  min-width: 12rem;
}

@media (prefers-reduced-motion: reduce) {
  .sp-quote-outcome__icon--busy::after {
    animation-duration: 2.4s;
  }
}

@media (max-width: 575.98px) {
  .sp-quote-outcome .k-window-content {
    padding: var(--sp-space-5) var(--sp-space-4);
  }

  .sp-quote-outcome__brand img {
    max-height: 40px;
  }

  .sp-quote-outcome__icon {
    width: 72px;
    height: 72px;
  }

  .sp-quote-outcome__icon .k-svg-icon {
    width: 38px;
    height: 38px;
  }

  .sp-quote-outcome__title {
    font-size: var(--sp-fs-h2);
  }

  .sp-quote-outcome__actions .sp-btn {
    width: 100%;
  }
}

/* -- Reject this quotation? ------------------------------------------------------ */

/* The confirmation before a rejection: the portal's standard modal (.sp-modal), with its fields
   and buttons. The legacy sheet sizes every bare <p> at 18px. */
.sp-quote-reject.k-window {
  max-width: calc(100vw - 2 * var(--sp-space-4));
}

.sp-quote-reject .sp-quote-reject__intro {
  margin: 0 0 var(--sp-space-4);
  font-size: var(--sp-fs-body);
  line-height: var(--sp-lh-base);
  color: var(--sp-ink-soft);
}

.k-dialog-wrapper:has(.sp-quote-reject) .k-overlay {
  opacity: 1;
  background-color: rgba(0, 0, 0, .5);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}

/* -- Reset this quotation? (AdminQuoteReset.razor) ------------------------------ */

/* Held inside the viewport on a short screen: the details, warnings and lists scroll while the
   title and the Cancel / Reset buttons stay in view. The theme already makes .k-window a flex
   column and .k-window-content its flexible child; the content hands its padding to the two
   parts so the scrollbar sits at the window's edge. dvh after vh, so a mobile browser's toolbar
   is allowed for where it is understood. These follow the .sp-modal rules on purpose: equal
   specificity, so source order is what lets them win. */
.sp-quote-reset.k-window {
  max-width: calc(100vw - 2 * var(--sp-space-4));
  max-height: calc(100vh - 2 * var(--sp-space-4));
  max-height: calc(100dvh - 2 * var(--sp-space-4));
}

.sp-quote-reset .k-window-content {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 0;
  overflow: hidden;
}

.sp-quote-reset__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-space-5);
}

.sp-quote-reset .sp-modal__actions {
  flex: 0 0 auto;
  margin-top: 0;
  padding: var(--sp-space-4) var(--sp-space-5);
  border-top: 1px solid var(--sp-line);
}

/* -- Quotation closed pop-ups (QuoteClosedDialog.razor) ------------------------- */

/* "Quotation Rejected" and "Quotation Expired", laid out to the mockups attached to ClickUp
   869em4kg3: the logo over a blue rule, the icon badge, the title, then a pale "Need help?" band.
   The content loses .sp-modal's padding so the two bands reach the window's edges; each part pads
   itself. These follow the .sp-modal rules on purpose: equal specificity, so source order is what
   lets them win. */
.sp-quote-closed.k-window {
  max-width: calc(100vw - 2 * var(--sp-space-4));
  max-height: calc(100vh - 2 * var(--sp-space-4));
}

.sp-quote-closed .k-window-content {
  padding: 0;
  color: var(--sp-navy);
  text-align: center;
}

/* No drawn title: the bar is left holding only the close button, floated over the logo band's
   corner. Empty, and so invisible, for an expired quotation, which cannot be closed. */
.sp-quote-closed .k-window-titlebar {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1;
  padding: var(--sp-space-3);
  background: transparent;
  border-bottom: 0;
}

/* The theme fades the close button to .5 opacity; solid grey, as on .sp-modal--confirm. */
.sp-quote-closed .k-window-titlebar-action { color: var(--sp-muted); opacity: 1; }
.sp-quote-closed .k-window-titlebar-action:hover { color: var(--sp-ink); }

/* The page behind is dimmed and blurred, as it is for .sp-modal--confirm (see there for why the
   dim moves into the background colour). */
.k-dialog-wrapper:has(.sp-quote-closed) .k-overlay {
  opacity: 1;
  background-color: rgba(0, 0, 0, .5);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}

/* The side padding keeps the centred logo clear of the close button. */
.sp-quote-closed__brand {
  padding: var(--sp-space-5) var(--sp-space-7) var(--sp-space-4);
  border-bottom: 2px solid var(--sp-primary);
}

.sp-quote-closed__brand img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 52px;
  margin: 0 auto;
}

.sp-quote-closed__body {
  padding: var(--sp-space-6);
}

.sp-quote-closed__icon {
  display: grid;
  place-items: center;
  width: 128px;
  height: 128px;
  margin: 0 auto var(--sp-space-5);
  border-radius: 50%;
  background: var(--sp-primary-050);
  color: var(--sp-primary);
}

.sp-quote-closed__icon svg {
  width: 92px;
  height: 92px;
}

/* The disc's stroke is the badge's own fill, so it cuts a gap round the disc where it overlaps
   the document, as the mockup draws it. */
.sp-quote-closed__icon-disc {
  fill: var(--sp-danger);
  stroke: var(--sp-primary-050);
  stroke-width: 4;
}

.sp-quote-closed__icon-cross {
  stroke: #fff;
}

/* Sizes are restated in full: Bootstrap sizes every <h2> and <h3>, the legacy sheet every bare <p>. */
.sp-quote-closed__title {
  margin: 0;
  font-size: 2rem;
  font-weight: var(--sp-fw-bold);
  line-height: var(--sp-lh-tight);
  color: var(--sp-navy-900);
}

/* The short blue rule under the title. */
.sp-quote-closed__title::after {
  content: "";
  display: block;
  width: 64px;
  height: 2px;
  margin: var(--sp-space-4) auto var(--sp-space-5);
  background: var(--sp-primary);
}

.sp-quote-closed__lead,
.sp-quote-closed__message,
.sp-quote-closed__help-text {
  margin: 0;
  line-height: var(--sp-lh-base);
}

.sp-quote-closed__lead {
  margin-bottom: var(--sp-space-2);
  font-size: 1.1875rem;
  font-weight: var(--sp-fw-bold);
  color: var(--sp-navy-900);
}

.sp-quote-closed__message {
  font-size: 1.0625rem;
}

.sp-quote-closed a {
  font-weight: var(--sp-fw-semibold);
  text-decoration: none;
}

.sp-quote-closed a:hover {
  text-decoration: underline;
}

.sp-quote-closed__message a {
  color: var(--sp-primary);
}

.sp-quote-closed__actions {
  display: flex;
  justify-content: center;
  margin-top: var(--sp-space-5);
}

/* "Need help?" on the left, the email address and phone number on the right. */
.sp-quote-closed__help {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-space-5);
  padding: var(--sp-space-5) var(--sp-space-6);
  background: var(--sp-canvas);
  border-top: 1px solid var(--sp-line);
  text-align: left;
}

.sp-quote-closed__help-intro {
  display: flex;
  align-items: center;
  gap: var(--sp-space-4);
  min-width: 0;
}

.sp-quote-closed__help-badge {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--sp-primary-100);
  color: var(--sp-primary);
}

.sp-quote-closed__help-badge svg {
  width: 30px;
  height: 30px;
}

.sp-quote-closed__help-title {
  margin: 0 0 var(--sp-space-1);
  font-size: var(--sp-fs-h3);
  font-weight: var(--sp-fw-bold);
  line-height: var(--sp-lh-tight);
  color: var(--sp-navy-900);
}

.sp-quote-closed__help-text {
  font-size: var(--sp-fs-body);
  color: var(--sp-ink-soft);
}

.sp-quote-closed__contacts {
  display: grid;
  gap: var(--sp-space-3);
  flex: 0 0 auto;
  margin: 0;
  padding: 0;
  list-style: none;
}

.sp-quote-closed__contacts li {
  display: flex;
  align-items: center;
  gap: var(--sp-space-3);
  font-size: var(--sp-fs-body);
}

.sp-quote-closed__contacts a {
  color: var(--sp-navy);
}

.sp-quote-closed__contact-icon {
  display: inline-flex;
  color: var(--sp-primary);
}

.sp-quote-closed__contact-icon svg {
  width: 20px;
  height: 20px;
}

/* -- Narrower screens ------------------------------------------------------------ */

@media (max-width: 767.98px) {
  /* The logo on the top row; the title goes full width beneath it. */
  .sp-quote__header {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--sp-space-3);
    padding: var(--sp-space-3) var(--sp-space-4);
  }

  .sp-quote__header .sp-btn {
    padding-inline: var(--sp-space-4);
  }

  /* The header is two rows here signed out (the logo, then the title). */
  html:has(.sp-quote__header) {
    scroll-padding-top: 8.5rem;
  }

  .sp-quote__header-brand:empty,
  .sp-quote__header-actions:empty {
    display: none;
  }

  .sp-quote__header-actions {
    margin-left: auto;
  }

  .sp-quote__title {
    order: 3;
    flex: 1 1 100%;
    font-size: var(--sp-fs-h2);
  }

  /* Kept small on a phone, where the header stays stuck to the top. */
  .sp-quote__logo {
    max-height: 36px;
  }

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

  .sp-quote__col--offset {
    padding-top: 0;
  }

  .sp-quote__table-row {
    grid-template-columns: minmax(0, 1fr) 13rem;
  }
}

@media (max-width: 575.98px) {
  .sp-quote__row {
    grid-template-columns: minmax(0, 1fr);
  }

  .sp-quote__row .sp-quote__label {
    padding-top: 0;
    margin-bottom: var(--sp-space-1);
  }

  /* One cell per line: the header row has nothing to label once the cells stack. */
  .sp-quote__table-head {
    display: none;
  }

  .sp-quote__table-row {
    grid-template-columns: minmax(0, 1fr);
  }

  .sp-quote__table-row > * + * {
    border-left: 0;
    padding-top: 0;
  }

  .sp-quote__decision .sp-btn {
    width: 100%;
  }

  .sp-quote__loading-card {
    padding: var(--sp-space-5);
  }

  .sp-quote__pdf {
    height: 480px;
  }

  /* The closed-quotation pop-up: a smaller badge and title, and the help band's two halves
     stacked. The brand band keeps its side padding, which clears the close button. */
  .sp-quote-closed__brand {
    padding-top: var(--sp-space-4);
    padding-bottom: var(--sp-space-3);
  }

  .sp-quote-closed__brand img {
    max-height: 36px;
  }

  .sp-quote-closed__body {
    padding: var(--sp-space-5) var(--sp-space-4);
  }

  .sp-quote-closed__icon {
    width: 96px;
    height: 96px;
    margin-bottom: var(--sp-space-4);
  }

  .sp-quote-closed__icon svg {
    width: 68px;
    height: 68px;
  }

  .sp-quote-closed__title {
    font-size: var(--sp-fs-h1);
  }

  .sp-quote-closed__help {
    flex-direction: column;
    align-items: stretch;
    padding: var(--sp-space-5) var(--sp-space-4);
  }
}

/* -- Read-only field (Controls/Ui/ReadOnlyField.razor) --------------------- */

.sp-readonlyfield {
  margin-bottom: var(--sp-space-3, 0.75rem);
}

.sp-readonlyfield__label {
  display: block;
  font-weight: var(--sp-fw-bold, 700);
  font-size: 0.875rem;
  margin-bottom: var(--sp-space-1, 0.25rem);
}

.sp-readonlyfield__value {
  display: block;
  /* Addresses arrive as a single comma-joined string; preserve any newlines they do carry. */
  white-space: pre-line;
}

/* ============================================================================
   Invoice payment (Components/Pages/InvoicePayment.razor)
   Page-specific, like the Quote Acceptance block above. Laid out to the "New" mockup on ClickUp
   869f65ywx: one column of cards, each headed by a pale round icon and a navy title, with the
   card's content indented to line up with the title. Replaces the page's scoped two-column grid,
   whose `grid-row: 2 / 200` opened a ~4,700px gap on wide screens.
   Every paragraph has its own class restating its size: stroma-portal.css sizes a bare <p> at
   16-18px, and a blanket ".sp-pay__body p" rule would outrank these single classes.
   ========================================================================= */

.sp-pay {
  --sp-pay-icon: 48px;
  gap: var(--sp-space-4);
}

.sp-pay__card {
  border-radius: var(--sp-radius-md);
}

.sp-pay__heading {
  display: flex;
  align-items: center;
  gap: var(--sp-space-4);
  margin: 0 0 var(--sp-space-3);
  font-size: var(--sp-fs-h2);
  font-weight: var(--sp-fw-bold);
  line-height: var(--sp-lh-tight);
  color: var(--sp-navy);
}

.sp-pay__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: var(--sp-pay-icon);
  height: var(--sp-pay-icon);
  border-radius: 50%;
  background: var(--sp-primary-050);
  color: var(--sp-primary);
}

/* Lines the card's content up with the heading text, past the icon. */
.sp-pay__body {
  margin-left: calc(var(--sp-pay-icon) + var(--sp-space-4));
}

.sp-pay__due {
  margin: 0;
  font-size: 1.25rem;
  line-height: var(--sp-lh-tight);
  font-weight: var(--sp-fw-bold);
  color: var(--sp-danger);
}

/* Nothing due: no red. */
.sp-pay__due--none {
  color: var(--sp-ink-soft);
}

.sp-pay__muted {
  margin: var(--sp-space-2) 0 0;
  font-size: var(--sp-fs-body);
  line-height: var(--sp-lh-base);
  color: var(--sp-muted);
}

.sp-pay__text {
  margin: 0 0 var(--sp-space-4);
  font-size: var(--sp-fs-body);
  line-height: var(--sp-lh-base);
  color: var(--sp-ink-soft);
}

.sp-pay__notice {
  margin-block: var(--sp-space-4);
}

/* -- Invoice list ----------------------------------------------------------- */

.sp-pay__invoices {
  display: flex;
  flex-direction: column;
  gap: var(--sp-space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.sp-pay__invoice {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-space-4);
  padding: var(--sp-space-4) var(--sp-space-5);
  border: 1px solid var(--sp-line);
  border-radius: var(--sp-radius-md);
  background: var(--sp-surface);
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease;
}

.sp-pay__invoice:hover {
  border-color: var(--sp-primary-100);
}

.sp-pay__invoice--selected,
.sp-pay__invoice--selected:hover {
  border-color: var(--sp-primary);
  background: var(--sp-primary-050);
}

.sp-pay__check {
  flex: 0 0 auto;
  padding-top: 2px;
}

.sp-pay__check .k-checkbox:checked {
  border-color: var(--sp-primary);
  background-color: var(--sp-primary);
}

.sp-pay__invoice-main {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.sp-pay__invoice-title {
  font-size: 1rem;
  font-weight: var(--sp-fw-bold);
  color: var(--sp-navy);
}

.sp-pay__invoice-meta {
  font-size: var(--sp-fs-body);
  line-height: var(--sp-lh-base);
  color: var(--sp-ink-soft);
}

.sp-pay__invoice-status {
  margin-top: var(--sp-space-2);
}

.sp-pay__invoice-amount {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
  color: var(--sp-success);
}

.sp-pay__amount {
  font-size: 1.125rem;
  font-weight: var(--sp-fw-bold);
}

.sp-pay__amount-note {
  font-size: var(--sp-fs-small);
}

/* -- Totals ----------------------------------------------------------------- */

.sp-pay__summary {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--sp-space-1);
  margin-top: var(--sp-space-4);
}

.sp-pay__summary-line {
  margin: 0;
  font-size: var(--sp-fs-body);
  line-height: var(--sp-lh-base);
  color: var(--sp-muted);
}

.sp-pay__total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-space-4);
  min-width: min(100%, 26rem);
  margin-top: var(--sp-space-2);
  padding: var(--sp-space-3) var(--sp-space-4);
  border: 1px solid #b8e3c8;
  border-radius: var(--sp-radius-md);
  background: var(--sp-success-bg);
  color: var(--sp-success);
  font-weight: var(--sp-fw-bold);
}

.sp-pay__total-amount {
  font-size: var(--sp-fs-h2);
}

/* -- Reference and pay button ----------------------------------------------- */

/* Read-only, so the client can still select and copy it; grey like the mockup. */
.sp-pay__reference.k-input {
  background: var(--sp-canvas);
}

/* Kendo keeps button text on one line; the amount makes this label too long for a phone. */
.sp-pay__pay.k-button {
  white-space: normal;
}

/* -- "Payment in progress" on the Invoices page's Outstanding grid ---------- */

.sp-invoices__status {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-space-2);
}

.sp-invoices__progress {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-space-1);
}

/* stroma-portal.css sets every button in an .invoice-table grid to 16-18px text on a 24-28px line
   (".invoice-table .k-button", 0-2-0), which outscores .sp-btn--sm and made Pay Invoice outsize the row. */
.sp-invoices__status .sp-btn.sp-btn--sm {
  font-size: var(--sp-fs-small);
  line-height: 1.2;
}

@media (max-width: 575.98px) {
  .sp-pay {
    --sp-pay-icon: 40px;
  }

  .sp-pay__heading {
    gap: var(--sp-space-3);
    font-size: var(--sp-fs-h3);
  }

  .sp-pay__body {
    margin-left: 0;
  }

  .sp-pay__invoice {
    flex-wrap: wrap;
    padding: var(--sp-space-4);
  }

  /* The amount drops onto its own line under the invoice details. */
  .sp-pay__invoice-amount {
    flex-basis: 100%;
    flex-direction: row;
    align-items: baseline;
    justify-content: flex-end;
    gap: var(--sp-space-1);
  }

  .sp-pay__total {
    flex-wrap: wrap;
    width: 100%;
  }
}
