/* =============================================================================
   ShareLadder — Component layer
   -----------------------------------------------------------------------------
   Hand-written here so the showcase (index.html) renders with zero build step.
   In the real app these are provided by BASECOAT (Tailwind + the same shadcn
   token names), so the markup and the token contract are identical — this file
   is the reference, Basecoat is the production implementation.
   ============================================================================= */

/* --- Reset / base ---------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--sl-font-sans);
  font-size: var(--sl-text-base);
  line-height: var(--sl-leading-normal);
  color: var(--foreground);
  background-color: var(--background);
  font-feature-settings: "ss01", "cv01";        /* friendlier humanist forms */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--sl-navy-100); color: var(--sl-navy-900); }

:where(a) { color: var(--primary); text-decoration: none; }
:where(a:hover) { text-decoration: underline; text-underline-offset: 0.2em; }

/* A link inside a run of prose, rather than one standing on its own as a row,
   a card or a button. It is underlined from the start: a link set apart from
   the words around it by colour alone is not a link to a reader who cannot see
   the difference, and the sentences that carry one are read rather than
   scanned. Hovering takes the underline off, which is how the rest of the
   product says the same thing the other way round. */
.sl-link { text-decoration: underline; text-underline-offset: 0.2em; }
.sl-link:hover { text-decoration: none; }

:where(img, svg) { display: block; max-width: 100%; }

/* Lucide icons: one family, inherit currentColor (so they take the state/text
   colour automatically), sized to their context. The brand logo is the only
   bespoke mark; everything else is a library glyph. */
.sl-alert__icon svg { width: 1.25rem;  height: 1.25rem; }
.sl-rung__node  svg { width: 0.95rem;  height: 0.95rem; }
.sl-stepper__marker svg { width: 0.95rem; height: 0.95rem; }
.sl-error       svg { width: 0.95rem;  height: 0.95rem; flex: none; }

/* Consistent, visible focus for keyboard users everywhere */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
  border-radius: var(--sl-radius-xs);
}

/* --- Typography ------------------------------------------------------------ */
.sl-display, .sl-h1, .sl-h2, .sl-h3 {
  font-family: var(--sl-font-display);
  font-weight: var(--sl-weight-bold);            /* sans display carries its presence in weight, not serifs */
  letter-spacing: -0.025em;
  line-height: var(--sl-leading-tight);
  color: var(--foreground);
}
.sl-hero    { font-family: var(--sl-font-display); font-weight: 800; font-size: var(--sl-text-hero);    line-height: 1.0;  letter-spacing: -0.03em; }
.sl-display { font-size: var(--sl-text-display); }
.sl-h1      { font-size: var(--sl-text-3xl); }
.sl-h2      { font-size: var(--sl-text-2xl); }
.sl-h3      { font-size: var(--sl-text-xl); line-height: var(--sl-leading-snug); }
.sl-h4      { font-family: var(--sl-font-sans); font-size: var(--sl-text-lg); font-weight: 600; letter-spacing: var(--sl-tracking-snug); line-height: var(--sl-leading-snug); }

/* Section heading: a page or in-form title, one step down from the .sl-h3/.sl-h4 pair above */
.sl-heading {
  font-family: var(--sl-font-display);
  font-weight: var(--sl-weight-bold);
  letter-spacing: -0.025em;
  line-height: var(--sl-leading-snug);
  color: var(--foreground);
  font-size: var(--sl-text-xl);
  margin: 0 0 var(--sl-space-3);
}
.sl-heading--sm { font-size: var(--sl-text-lg); margin-top: var(--sl-space-6); }

.sl-lead { font-size: var(--sl-text-md); line-height: var(--sl-leading-relaxed); color: var(--sl-ink-700); }
.sl-body { font-size: var(--sl-text-base); line-height: var(--sl-leading-relaxed); }
.sl-small { font-size: var(--sl-text-sm); }
.sl-muted, .sl-text--muted { color: var(--muted-foreground); }
.sl-mono  { font-family: var(--sl-font-mono); font-feature-settings: "tnum"; }
.sl-num   { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }
/* A paragraph held to a readable measure rather than the column's full width. */
.sl-prose { max-width: var(--sl-container-prose); }
.sl-nowrap { white-space: nowrap; }

.sl-eyebrow {
  font-size: var(--sl-text-xs);
  font-weight: var(--sl-weight-semibold);
  letter-spacing: var(--sl-tracking-wide);
  text-transform: uppercase;
  color: var(--sl-navy-600);
}

/* A subsection heading: titles a group of fields inside a form section (the
   contact details within "About you", the owned-home block within "Your
   current home"). The eyebrow's quieter sibling — the same small caps, but
   muted ink in place of navy and never a rule line above it. A section opens
   with an eyebrow; a group inside one gets this, never a second eyebrow. */
/* A confirmed declaration line: the record of a tick, not a tickable thing.
   The check carries the done colour (complete is a state, so it may use the
   state palette); the sentence stays body ink. */
.sl-declaration-confirmed { display: flex; gap: var(--sl-space-2); align-items: baseline; margin: 0; }
.sl-declaration-confirmed svg { color: var(--status-done-dot); flex: none; transform: translateY(2px); }

.sl-subheading {
  font-size: var(--sl-text-xs);
  font-weight: var(--sl-weight-semibold);
  letter-spacing: var(--sl-tracking-wide);
  text-transform: uppercase;
  color: var(--muted-foreground);
  /* A group heading opens a new cluster, so it takes extra air above beyond
     the stack gap its parent already provides. */
  margin-top: var(--sl-space-4);
}

/* --- Buttons --------------------------------------------------------------- */
.sl-btn {
  --_bg: var(--primary);
  --_fg: var(--primary-foreground);
  --_bg-hover: var(--primary-hover);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sl-space-2);
  font-family: var(--sl-font-sans);
  font-size: var(--sl-text-sm);
  font-weight: var(--sl-weight-semibold);
  line-height: 1;
  padding: 0 var(--sl-space-5);
  height: 2.75rem;                 /* 44px — comfortable touch target */
  border: 1px solid transparent;
  border-radius: var(--sl-radius-md);
  background: var(--_bg);
  color: var(--_fg);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--sl-dur-fast) var(--sl-ease-out),
              transform var(--sl-dur-fast) var(--sl-ease-out),
              box-shadow var(--sl-dur-fast) var(--sl-ease-out);
}
/* A button is never decorated, whatever element it happens to be: the product's
   link rule underlines an anchor on hover, and most buttons here are anchors. */
.sl-btn:hover { background: var(--_bg-hover); text-decoration: none; }
.sl-btn:active { transform: translateY(1px); }
.sl-btn:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; box-shadow: var(--sl-shadow-focus); }
.sl-btn[disabled], .sl-btn[aria-disabled="true"] { opacity: 0.5; pointer-events: none; }
.sl-btn svg { width: 1.05em; height: 1.05em; }

/* The secondary action, drawn tonally: a filled shape in a navy tint with a navy
   label and no border, taking the primary's radius and 44px height from the base.
   A primary and a secondary side by side are then one object at two weights. The
   tint is the navy-100 step, not the navy-50 interactive wash: navy-50 measures
   1.006:1 against the cream canvas, so a button filled with it has no edge at all.
   Hover is one step down the same ramp.
   There is one secondary action and three class names for it this release, so that
   the change to what people see is one reviewable rule; folding the names into one
   is a later mechanical change. */
.sl-btn--ghost,
.sl-btn--outline,
.sl-btn--secondary {
  --_bg: var(--btn-secondary-fill);
  --_fg: var(--accent-foreground);
  --_bg-hover: var(--btn-secondary-fill-hover);
}
/* Icon-only chrome (a dialog's close, the masthead's sign out) is not a secondary
   action and takes no tint and no border: it is a square target around a glyph,
   with the quiet interactive wash on hover. The compound rule below repeats
   padding because .sl-btn--sm sets its own and comes later in this file. */
.sl-btn--icon {
  --_bg: transparent;
  --_fg: var(--foreground);
  --_bg-hover: var(--accent);
  width: 2.75rem; padding: 0;
}
.sl-btn--icon.sl-btn--sm { width: 2.25rem; padding: 0; }
.sl-btn--primary {       /* Navy — the default submit. Spells out what the .sl-btn base already is, so intent reads in the markup. */
  --_bg: var(--primary); --_fg: var(--primary-foreground); --_bg-hover: var(--primary-hover);
}
.sl-btn--accent {        /* Teal — reserve for "your turn" / celebratory CTAs */
  --_bg: var(--sl-accent); --_fg: var(--sl-accent-foreground); --_bg-hover: var(--sl-teal-700);
}
.sl-btn--sm { height: 2.25rem; padding: 0 var(--sl-space-4); font-size: var(--sl-text-xs); }
.sl-btn--block { display: flex; width: 100%; }

/* --- Form fields ----------------------------------------------------------- */
.sl-field { display: flex; flex-direction: column; gap: var(--sl-space-2); }
/* Helper and error text hug the control they describe: the field's own gap
   drops to 4px before them, so the 20px stack gap between fields reads as
   the grouping boundary (internal gaps stay well under half the stack gap). */
.sl-field > .sl-hint, .sl-field > .sl-field-error { margin-top: calc(var(--sl-space-1) - var(--sl-space-2)); }
/* A short form's fields, laid out two-up once there's room. Fields sharing a
   row share a baseline: each field is label, control, then hint/error (helper
   text never sits between a label and its control) and row labels are written
   to fit one line, so every control in the row starts at the same height. */
.sl-field-grid { display: grid; gap: var(--sl-space-5) var(--sl-space-4); grid-template-columns: 1fr; }
@media (min-width: 481px) { .sl-field-grid { grid-template-columns: repeat(2, 1fr); } }
/* Two short selects that belong together (a duration's years/months): two
   capped columns that stay side by side at every width — two narrow controls
   fit fine on a 400px screen. */
.sl-field-grid.sl-field-grid--short-pair { grid-template-columns: repeat(2, minmax(0, 8rem)); }
/* A date's day / month / year trio: three short columns that stay side by
   side at every width — three narrow inputs fit fine on a 400px screen —
   with a wider year column and a tighter gap, so the trio reads as one
   answer. */
.sl-field-grid.sl-field-grid--date {
  grid-template-columns: minmax(0, var(--sl-space-16)) minmax(0, var(--sl-space-16)) minmax(0, var(--sl-space-24));
  gap: var(--sl-space-3);
}
/* Inside a multi-column row the grid template sizes the fields: the per-field
   width caps stand down so the controls in a row share consistent widths. */
.sl-field-grid .sl-field--xs, .sl-field-grid .sl-field--sm, .sl-field-grid .sl-field--md, .sl-field-grid .sl-field--lg { max-width: none; }
/* A back-office two-up field row: the same rhythm as .sl-field-grid, but each
   field keeps its own width cap. A staff card is three times the width of the
   applicant wizard the grid was drawn for, so a 1fr column would make a
   two-digit percentage as wide as an address. */
.sl-field-row {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sl-space-5) var(--sl-space-4); align-items: start;
}
@media (max-width: 640px) { .sl-field-row { grid-template-columns: 1fr; } }

/* A repeat-row's add action: a small ghost button under the rows, on the left
   rail. As a direct grid child a button stretches full-width and its centred
   content floats mid-column; this pins it to the start. */
.sl-add-row { justify-self: start; }

/* --- People list ------------------------------------------------------------
   A roster of entities (the household, an applicant's credit commitments) as
   ONE bordered container: every entity is a row, rows divided by hairlines.
   Locked facts (the applicants) and editable member rows are rows of the same
   list, so who's included reads at a glance. Derived counts render as a
   sentence below the list, never as editable-looking inputs. */
.sl-people-list {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  overflow: hidden;   /* rounds the first and last rows' corners with the container */
}
/* One person per row. An editable row stacks its two field lines (name and
   relationship, then date of birth) at the section-stack step of the rhythm
   ladder; the row's padding is what binds the lines into one person. */
.sl-people-list__row {
  display: grid;
  gap: var(--sl-space-5);
  padding: var(--sl-space-4);
}
.sl-people-list__row + .sl-people-list__row { border-top: 1px solid var(--border); }
/* A removed row is blanked and hidden, never deleted, so the row shown first is
   not always the list's first child; without this the row leading the list
   doubles its hairline against the container's own top edge. */
.sl-people-list__row[data-row-number="1"] { border-top: 0; }
/* Every person opens with the same head line: a name, then tags, with the
   row's action pinned right. The name mirrors the row's input live on
   editable rows, so locked and editable rows read identically at a glance. */
.sl-people-list__row-head {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sl-space-1) var(--sl-space-2);
}
.sl-people-list__row-head .sl-people-list__row-name { margin-right: auto; }
.sl-people-list__row-name { font-weight: var(--sl-weight-semibold); }
/* A locked person (an applicant): just a name and a role tag, muted, no
   inputs, sized to match a control's height. */
.sl-people-list__row--locked {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sl-space-1) var(--sl-space-3);
  min-height: 2.75rem;
  padding: var(--sl-space-2) var(--sl-space-4);
  background: var(--muted);
}

/* Field width scale — cap a field at the width its content needs, so a short
   answer (a title select, a postcode) doesn't stretch across the whole form
   column. Put the class on the .sl-field wrapper: the label, control and any
   hint or message share the cap. Sizes compose from the 4px space scale and
   release to full width below the mobile breakpoint. */
.sl-field--xs { max-width: calc(var(--sl-space-24) + var(--sl-space-8)); }   /* 8rem  — year/month selects, small counts */
.sl-field--sm { max-width: calc(var(--sl-space-32) + var(--sl-space-16)); }  /* 12rem — title select, date of birth, postcode */
.sl-field--md { max-width: calc(var(--sl-space-32) * 2); }                   /* 16rem — NI number, phone numbers, money amounts */
.sl-field--lg { max-width: calc(var(--sl-space-32) * 3 + var(--sl-space-16)); } /* 28rem: an email address, a postal address over several lines */
@media (max-width: 480px) {
  .sl-field--xs, .sl-field--sm, .sl-field--md, .sl-field--lg { max-width: none; }
}

.sl-label { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-medium); color: var(--sl-ink-800); }
/* A bare label directly inside a field reads as .sl-label automatically, so
   form partials don't need the class on every label. Check/radio labels
   (.sl-check) keep their own treatment. */
.sl-field > label:not(.sl-check),
.sl-field > legend {
  font-size: var(--sl-text-sm); font-weight: var(--sl-weight-medium); color: var(--sl-ink-800);
}
/* A yes/no (or option-cluster) question is a fieldset with the question as its
   legend, so assistive tech announces the question with every option. The
   fieldset chrome stands down and the legend reads exactly like a field label. */
fieldset.sl-field { border: 0; margin: 0; padding: 0; min-width: 0; }
/* A legend sits outside its fieldset's flex layout, so the field's label gap
   comes from an explicit margin rather than the flex gap. */
.sl-field > legend { padding: 0; margin: 0 0 var(--sl-space-2); }
.sl-hint  { font-size: var(--sl-text-xs); color: var(--muted-foreground); }
.sl-error { font-size: var(--sl-text-xs); color: var(--sl-red-700); display: flex; align-items: center; gap: var(--sl-space-1); }
.sl-field-error { font-size: var(--sl-text-xs); color: var(--status-problem-fg); }
/* When a field already carries a server-side error, hide its client-side format
   hint so the two never stack. Server errors carry id="<field>-error"; the format
   hints (x-show) have no id, so :not([id]) targets only the hint. */
.sl-field:has([aria-invalid="true"]) .sl-field-error:not([id]) { display: none !important; }

.sl-input, .sl-select, .sl-textarea {
  font-family: var(--sl-font-sans);
  font-size: var(--sl-text-base);
  color: var(--foreground);
  background: var(--card);
  border: 1px solid var(--input);
  border-radius: var(--sl-radius-md);
  padding: 0 var(--sl-space-4);
  height: 2.75rem;
  width: 100%;
  transition: border-color var(--sl-dur-fast) var(--sl-ease-out),
              box-shadow var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-textarea { height: auto; padding: var(--sl-space-3) var(--sl-space-4); min-height: 6rem; resize: vertical; line-height: var(--sl-leading-normal); }
.sl-input::placeholder, .sl-textarea::placeholder { color: var(--sl-ink-500); }
.sl-input:focus, .sl-select:focus, .sl-textarea:focus {
  outline: none; border-color: var(--ring); box-shadow: var(--sl-shadow-focus);
}
/* Keyboard focus mirrors the pointer focus treatment, so the ring is never
   lost to a user agent's :focus-visible default. */
.sl-input:focus-visible, .sl-select:focus-visible, .sl-textarea:focus-visible {
  outline: none; border-color: var(--ring); box-shadow: var(--sl-shadow-focus);
}
.sl-input[aria-invalid="true"], .sl-select[aria-invalid="true"], .sl-textarea[aria-invalid="true"] {
  border-color: var(--status-problem-fg); border-width: 2px; box-shadow: 0 0 0 3px var(--status-problem-bg);
}
.sl-input-group { position: relative; display: flex; align-items: center; }
.sl-input-group .sl-input-prefix {
  position: absolute; left: var(--sl-space-4); color: var(--muted-foreground); pointer-events: none;
  font-variant-numeric: tabular-nums;
}
.sl-input-group .sl-input--with-prefix { padding-left: 2.25rem; }
/* A percentage carries its unit on the trailing edge instead of the leading
   one, the mirror of the money prefix above. */
.sl-input-group .sl-input-suffix {
  position: absolute; right: var(--sl-space-4); color: var(--muted-foreground); pointer-events: none;
  font-variant-numeric: tabular-nums;
}
.sl-input-group .sl-input--with-suffix { padding-right: 2.25rem; }

/* A commercial figure that is stated rather than typed, standing in a field's
   place beside one that is. Same label and hint as the field next to it, so the
   row still reads as one row; the value carries the input's optical weight
   without borrowing its box, because nothing here can be typed into. */
.sl-fixed-value {
  margin: 0; padding-block: 0.375rem;
  font-size: var(--sl-text-lg); font-weight: var(--sl-weight-semibold);
  line-height: var(--sl-leading-tight); letter-spacing: var(--sl-tracking-tight);
}
/* A field label with its explainer beside it, on one line. The wrapper carries
   the row so the label element stays a label: an explainer's trigger is a
   button, and a button inside a label steals the click that should reach the
   control. */
.sl-label-tip { display: inline-flex; align-items: center; gap: var(--sl-space-2); }

/* Selects: replace the browser-default arrow with a token-coloured caret
   (two small gradient squares), consistent across platforms and themes. */
.sl-select { appearance: none; }
.sl-select:not([multiple]) {
  padding-right: calc(var(--sl-space-8) + var(--sl-space-2));
  background-image:
    linear-gradient(45deg, transparent 50%, var(--muted-foreground) 50%),
    linear-gradient(135deg, var(--muted-foreground) 50%, transparent 50%);
  background-position:
    calc(100% - var(--sl-space-4) - 0.3125rem) 50%,
    calc(100% - var(--sl-space-4)) 50%;
  background-size: 0.3125rem 0.3125rem;
  background-repeat: no-repeat;
}
/* Grouped options: a browser italicises the group label by default, which reads
   as an aside — the group name is what does the finding, so it carries the
   weight and the options under it stay regular. */
.sl-select optgroup { font-style: normal; font-weight: var(--sl-weight-semibold); }
.sl-select optgroup option { font-weight: var(--sl-weight-regular); }

/* Checkbox / radio (native, restyled accent) */
.sl-check {
  display: inline-flex; gap: var(--sl-space-3); align-items: flex-start;
  font-size: var(--sl-text-sm); line-height: var(--sl-leading-normal); cursor: pointer;
}
.sl-check input { accent-color: var(--primary); width: 1.15rem; height: 1.15rem; margin-top: 0.1rem; flex: none; }
.sl-check input:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
/* A row of yes/no radios (or checkbox options) inside a field: a touch more
   air between the options than the default cluster gap. */
.sl-field > .sl-cluster { column-gap: var(--sl-space-6); row-gap: var(--sl-space-2); }
/* A stack of checkbox options answered together, one per line. */
.sl-check-grid { display: grid; gap: var(--sl-space-2); margin-top: var(--sl-space-2); }

/* A group of checkboxes answered together (the declaration): when the server
   marks any of them, the whole group carries a left problem-colour bar so the
   error reads as weight, not only the small message under each box. */
.sl-check-group[data-error] {
  border-left: 3px solid var(--status-problem-fg);
  padding-left: var(--sl-space-4);
}

/* A radio whose label carries a second, quieter line saying what choosing it
   does. The same shape as the task row's name over its what. */
.sl-choice { display: grid; gap: var(--sl-space-3); }
.sl-choice .sl-check { display: flex; }
.sl-choice__what {
  display: block; margin-top: var(--sl-space-1);
  font-size: var(--sl-text-xs); color: var(--muted-foreground);
  line-height: var(--sl-leading-normal);
}

/* --- Cards ----------------------------------------------------------------- */
.sl-card {
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-radius: var(--sl-radius-lg);
  box-shadow: var(--sl-shadow-sm);
}
.sl-card--flat   { box-shadow: none; }
.sl-card--raised { box-shadow: var(--sl-shadow-md); }
.sl-card--feature {                  /* the one high-emphasis surface: navy brand-filled hero card */
  background: linear-gradient(160deg, var(--sl-navy-600), var(--sl-navy-900));
  color: #fbfaf6; border-color: transparent; box-shadow: var(--sl-shadow-lg);
}
.sl-card--feature .sl-muted   { color: var(--sl-navy-100); }
.sl-card--feature .sl-eyebrow { color: var(--sl-coral-300); }  /* the one coral flourish moment on navy */
/* Key/value labels were inheriting the light-background muted grey — illegible on navy. */
.sl-card--feature .sl-kv__key { color: var(--sl-navy-100); }
.sl-card--feature .sl-kv      { border-color: color-mix(in srgb, var(--sl-navy-100) 22%, transparent); }

/* --- Affordability decision page (/review/) -------------------------------- */
/* Tighten the eyebrow → title → subtitle rhythm and give the decision card and
   its actions consistent breathing room (was: subtitle jammed under the title). */
.sl-decision > h1        { margin-block: var(--sl-space-3) var(--sl-space-1); }
.sl-decision__sub        { margin: 0 0 var(--sl-space-6); }
.sl-decision > .sl-card--feature { margin-bottom: var(--sl-space-6); }
/* Primary action is the dominant, full-width control; declining is a quiet aside below it. */
.sl-decision__actions    { display: flex; flex-direction: column; gap: var(--sl-space-4); }
.sl-decision__aside      { margin: 0; text-align: center; font-size: var(--sl-text-sm); color: var(--muted-foreground); }
.sl-decision__decline-link { color: var(--foreground); font-weight: var(--sl-weight-medium); text-decoration: underline; text-underline-offset: 2px; }
.sl-decision__decline-link:hover { color: var(--sl-accent); }
.sl-decision__decline    { margin-top: var(--sl-space-2); }

/* --- Recording and reading back the affordability decision ------------------ */
/* The adviser's own surface: a stack of fields, a set of outcomes, and the
   parts of the form each outcome reveals. Reveals are hidden until Alpine has
   evaluated them, so the page never flashes a question it is about to hide.
   Scoped to this form: elsewhere a progressive reveal stays readable without
   Alpine, and hiding it outright would cost more than the flash it saves. */
.sl-decision-form [x-cloak] { display: none !important; }
.sl-decision-fields  { display: grid; gap: var(--sl-space-5); margin-top: var(--sl-space-3); }
.sl-decision-fields .sl-field-grid { max-width: 34rem; }
.sl-decision-reveal  { display: grid; gap: var(--sl-space-5); margin-top: var(--sl-space-3); }
.sl-decision-choice  { flex: 1; display: flex; flex-direction: column; gap: var(--sl-space-1); }
.sl-decision-alert   { margin-top: var(--sl-space-6); }
.sl-decision-facts   { margin: var(--sl-space-4) 0 0; }
.sl-decision-note    { margin-top: var(--sl-space-4); max-width: 62ch; }
/* Form actions sit at the end of a card footer, in reading order. */
.sl-form-actions     { display: flex; align-items: center; justify-content: flex-end; gap: var(--sl-space-3); }
.sl-card__body   { padding: var(--sl-space-6); }
/* The subject a card's figures are about, at the head of its body: a name and
   one line of context above the numbers that follow. */
.sl-card__subject { margin-bottom: var(--sl-space-5); }
.sl-card__subject h2 { margin: 0; }
.sl-card__subject p  { margin: var(--sl-space-1) 0 0; }
.sl-card__header { padding: var(--sl-space-6) var(--sl-space-6) 0; }
/* A header that carries a state pill beside its title: the title block takes
   the room it needs and the pill sits out at the end, top-aligned so it reads
   against the eyebrow rather than floating in the middle. */
.sl-card__header--split { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sl-space-4); }
.sl-card__footer { padding: var(--sl-space-4) var(--sl-space-6); border-top: 1px solid var(--border); }
/* A read view's footer: when the card was last changed and who by, and a link
   to the card's own trail. On a phone the pair stacks, the line first, so a
   long actor name never squeezes the link into a column of its own letters. */
.sl-card__footer--record { display: flex; align-items: center; justify-content: space-between; gap: var(--sl-space-3); flex-wrap: wrap; }
@media (max-width: 420px) {
  .sl-card__footer--record { flex-direction: column; align-items: flex-start; }
}
.sl-card__title  { font-size: var(--sl-text-lg); font-weight: var(--sl-weight-semibold); line-height: var(--sl-leading-snug); }

/* Cards whose content sits straight inside .sl-card, with no __body wrapper */
.sl-card--invite, .sl-card--aftersales {
  display: flex; flex-direction: column; gap: var(--sl-space-3);
  padding: var(--sl-space-6);
}
/* The completion card caps its own width: the applicant shell shrink-wraps to its
   widest child (see the "Page shells" note below), and an uncapped card's unwrapped
   paragraph stretches the shell to the full band — dragging the heading and ladder
   hard-left while every other journey state sits in a centred column. 40rem matches
   the .sl-panel reading column. */
.sl-card--aftersales { max-width: 40rem; }

/* --- Status pills (the C11 state machine, rendered) ------------------------ */
.sl-pill {
  display: inline-flex; align-items: center; gap: var(--sl-space-2);
  font-size: var(--sl-text-xs); font-weight: var(--sl-weight-semibold);
  line-height: 1; padding: 0.375rem 0.625rem 0.375rem 0.55rem;
  border-radius: var(--sl-radius-full); white-space: nowrap;
}
.sl-pill::before {
  content: ""; width: 0.5rem; height: 0.5rem; border-radius: 50%;
  background: var(--_dot); flex: none;
}
.sl-pill--neutral { color: var(--status-neutral-fg); background: var(--status-neutral-bg); --_dot: var(--status-neutral-dot); }
.sl-pill--active  { color: var(--status-active-fg);  background: var(--status-active-bg);  --_dot: var(--status-active-dot); }
.sl-pill--action  { color: var(--status-action-fg);  background: var(--status-action-bg);  --_dot: var(--status-action-dot); }
.sl-pill--waiting { color: var(--status-waiting-fg); background: var(--status-waiting-bg); --_dot: var(--status-waiting-dot); }
.sl-pill--done    { color: var(--status-done-fg);    background: var(--status-done-bg);    --_dot: var(--status-done-dot); }
.sl-pill--problem { color: var(--status-problem-fg); background: var(--status-problem-bg); --_dot: var(--status-problem-dot); }
/* Status pills carry a static state dot. The pulse is reserved for the
   deliberate "Live" affordance below — not applied to every in-progress pill,
   where a table of them reads as restless rather than informative. */
@keyframes sl-pulse { 0%,100% { box-shadow: 0 0 0 0 var(--status-active-dot); } 50% { box-shadow: 0 0 0 3px transparent; } }

/* Standalone pulsing dot — used as a Live indicator (the ScreenIntro "Live" pill) */
.sl-pulse {
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--status-active-dot);
    animation: sl-pulse 2s var(--sl-ease-in-out) infinite;
}
@media (prefers-reduced-motion: reduce) { .sl-pulse { animation: none; } }

/* --- Unit-status swatch tag (unit inventory table) ------------------------- */
.sl-swatch-tag { display:inline-flex; align-items:center; gap:var(--sl-space-2); font-size:var(--sl-text-xs); font-weight:var(--sl-weight-semibold); line-height:1; padding:2px 10px 2px 8px; border-radius:var(--sl-radius-full); background:var(--sl-surface-2); color:var(--foreground); border:1px solid var(--border); white-space:nowrap; }
.sl-swatch-tag::before { content:""; width:0.5rem; height:0.5rem; border-radius:2px; background:var(--_dot); flex:none; }
/* The six unit-status colours live here once. The swatch dot (below), the
   analytics unit-mix donut, and the home-page status donut all read them, so
   the palette never forks. */
:root {
  --sl-unit-status-unreleased:        #8e9299;
  --sl-unit-status-available:         #4e79a7;
  --sl-unit-status-under_application: #e0913a;
  --sl-unit-status-reserved:          #9b6fa8;
  --sl-unit-status-exchanged:         #3aa39a;
  --sl-unit-status-completed:         #4f9a5b;
}
.sl-swatch-tag--unreleased        { --_dot: var(--sl-unit-status-unreleased); }
.sl-swatch-tag--available         { --_dot: var(--sl-unit-status-available); }
.sl-swatch-tag--under_application { --_dot: var(--sl-unit-status-under_application); }
.sl-swatch-tag--reserved          { --_dot: var(--sl-unit-status-reserved); }
.sl-swatch-tag--exchanged         { --_dot: var(--sl-unit-status-exchanged); }
.sl-swatch-tag--completed         { --_dot: var(--sl-unit-status-completed); }

/* --- Home status donut: per-site six-state unit-status ring ----------------
   The ring is a conic-gradient composed per site from the unit-status palette
   above (the view builds the sweep stops from the counts); ::after punches the
   hole so the plot total reads in the centre. Legend rows reuse .sl-swatch-dot
   for their colour, so nothing here restates a hex. */
.sl-status-donut {
  width: 7.25rem; height: 7.25rem; border-radius: var(--sl-radius-full);
  flex: none; position: relative;
}
.sl-status-donut::after {
  content: ""; position: absolute; inset: 26%;
  border-radius: var(--sl-radius-full); background: var(--card);
}
.sl-status-donut__total {
  position: absolute; inset: 0; z-index: 1;
  display: grid; place-items: center; text-align: center; line-height: 1;
}
.sl-status-legend { display: grid; gap: var(--sl-space-1); font-size: var(--sl-text-xs); }
.sl-status-legend__row { display: inline-flex; align-items: center; gap: var(--sl-space-2); }

/* --- Site link-card: the whole card body is a link to its unit inventory --- */
.sl-site-link {
  display: block; text-decoration: none; color: inherit;
  transition: box-shadow 0.15s var(--sl-ease-in-out), transform 0.15s var(--sl-ease-in-out);
}
.sl-site-link:hover { transform: translateY(-2px); box-shadow: var(--sl-shadow-md); text-decoration: none; }
.sl-site-link:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }

/* --- Chat status fragment (inline status pill + detail inside chatbot reply) -- */
.sl-chat-status {
  display: flex;
  align-items: center;
  gap: var(--sl-space-2);
  margin-block-end: var(--sl-space-3);
}

.sl-chat-status__detail {
  font-size: var(--sl-text-sm);
  color: var(--color-text-secondary);
}

/* --- Action bar -----------------------------------------------------------
   The row that carries a screen's forward action. Layout is a design-system
   fact, not the author's to remember: the primary/forward action sits at the
   inline-END (right); an optional leading/secondary action (back / cancel /
   decline / previous) carries .sl-action-bar__lead and an auto margin pushes it
   to the inline-START, so a two-action bar (Cancel … Proceed) lays itself out
   for free. Gutterless by default so the bar shares its content column's edges;
   the --sticky modifier opts into the mobile full-bleed bottom band. */
.sl-action-bar {
  display: flex; align-items: center; gap: var(--sl-space-3);
  justify-content: flex-end;
  padding-block: var(--sl-space-4);
}
.sl-action-bar > form { margin: 0; }
.sl-action-bar__lead { margin-inline-end: auto; }
/* .sl-action-bar__forward: for a bar whose controls all submit one form. The
   browser presses the first submit button in the markup when Enter is pressed
   in a field, so the forward action has to be written first for Enter to mean
   "carry on"; this puts it back at the inline-END where it reads. */
.sl-action-bar__forward { order: 1; }
.sl-action-bar__passive {
  flex: 1; text-align: center; margin: 0;
  font-size: var(--sl-text-sm); color: var(--muted-foreground);
}
/* Stack full-width on narrow viewports for large tap targets. */
@media (max-width: 480px) {
  .sl-action-bar { flex-direction: column; align-items: stretch; }
  .sl-action-bar__lead { margin-inline-end: 0; }
  .sl-action-bar .sl-btn { width: 100%; }
}
/* --sticky: pin the bar to the bottom of the mobile viewport as a full-bleed
   band (the live-status CTA); on desktop it reverts to the static base. */
.sl-action-bar--sticky {
  position: sticky; bottom: 0; z-index: 40;
  margin-inline: calc(-1 * var(--sl-gutter));
  padding: var(--sl-space-4) var(--sl-gutter);
  background: color-mix(in srgb, var(--card) 90%, transparent);
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--border);
}
@media (min-width: 481px) {
  .sl-action-bar--sticky {
    position: static; margin-inline: 0; padding: var(--sl-space-4) 0;
    background: none; backdrop-filter: none; border-top: none;
  }
}

/* Plain tag (no dot) */
.sl-tag {
  display: inline-flex; align-items: center; gap: var(--sl-space-1);
  font-size: var(--sl-text-xs); font-weight: var(--sl-weight-medium);
  padding: 0.2rem 0.55rem; border-radius: var(--sl-radius-xs);
  background: var(--muted); color: var(--muted-foreground); border: 1px solid var(--border);
}

/* --- Alerts ---------------------------------------------------------------- */
.sl-alert {
  display: flex; gap: var(--sl-space-3); padding: var(--sl-space-4);
  border-radius: var(--sl-radius-md); border: 1px solid transparent;
  font-size: var(--sl-text-sm); line-height: var(--sl-leading-normal);
}
.sl-alert__icon { flex: none; width: 1.25rem; height: 1.25rem; margin-top: 0.05rem; }
.sl-alert__title { font-weight: var(--sl-weight-semibold); margin-bottom: 0.15rem; }
/* An alert whose body is a title over a line or two of detail, rather than a
   single sentence. The measure keeps the detail readable across a staff card. */
.sl-alert__body { flex: 1; }
.sl-alert__body p { margin: var(--sl-space-1) 0 0; max-width: 78ch; }
.sl-alert--info    { background: var(--status-active-bg);  color: var(--status-active-fg);  border-color: var(--sl-blue-100); }
.sl-alert--action  { background: var(--status-action-bg);  color: var(--status-action-fg);  border-color: var(--sl-teal-200); }
.sl-alert--success { background: var(--status-done-bg);    color: var(--status-done-fg);    border-color: var(--sl-green-200); }
.sl-alert--error   { background: var(--status-problem-bg); color: var(--status-problem-fg); border-color: var(--sl-red-100); }
/* An alert standing alone in the page flow (rather than inside an already-padded
   container) supplies its own block margins. */
.sl-alert--standalone { margin-block: var(--sl-space-5) var(--sl-space-4); }

/* The error summary reuses the error alert's colour but
   stacks the title over the list (instead of the alert's icon-and-body row),
   so there is no empty right-hand gutter. It lists every question that needs
   another look and links straight down to each field. */
#appform-error-summary, .sl-error-summary {
  flex-direction: column;
  gap: var(--sl-space-2);
  margin-bottom: var(--sl-space-4);
}
/* Keep the warning glyph inline with the title (the global svg{display:block}
   reset would otherwise stack it on its own line above the text). */
#appform-error-summary .sl-alert__title, .sl-error-summary .sl-alert__title {
  display: flex;
  align-items: center;
  gap: var(--sl-space-2);
}
#appform-error-summary ul, .sl-error-summary ul {
  margin: 0;
  padding-left: var(--sl-space-5);
  display: grid;
  gap: var(--sl-space-1);
}
#appform-error-summary li, .sl-error-summary li { padding-left: var(--sl-space-1); }
#appform-error-summary a, .sl-error-summary a {
  color: var(--status-problem-fg);
  font-weight: var(--sl-weight-medium);
  text-decoration: underline;
}
#appform-error-summary a:hover, .sl-error-summary a:hover { text-decoration: none; }

/* --- Progress -------------------------------------------------------------- */
.sl-progress { height: 0.5rem; background: var(--muted); border-radius: var(--sl-radius-full); overflow: hidden; }
.sl-progress__bar {
  display: block;                 /* the fill is a span — blockify it so width/height take */
  height: 100%; border-radius: inherit;
  background: linear-gradient(90deg, var(--sl-navy-500), var(--sl-teal-500));  /* brand → accent: the climb */
  transition: width var(--sl-dur-slower) var(--sl-ease-out);
}

/* --- Screen-reader-only text ------------------------------------------------ */
/* Kept in the accessibility tree but visually removed (display:none would
   silence it for screen readers too). */
.sl-visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* --- Stepper · horizontal wizard progress ----------------------------------- */
/* The application form's horizontal counterpart to the Ladder: one titled,
   numbered station per step, joined by a track that fills done-green as steps
   are completed. The current station carries the brand navy with a soft halo.
   Station count comes from the markup, so five- and six-step journeys both
   space evenly. Stations anchor to the start of their cells so the first
   marker (and its label) sits on the page's left rail, flush with the heading
   and the section content. Below the mobile breakpoint the titles hand over
   to the step count line above the bar; each keeps a screen-reader-only
   presence at the widths where it is visually retired. */
.sl-stepper {
  --_marker: 2rem; --_track-inset: 0.375rem;
  /* the undone track/marker tone: the strong border, deepened toward the muted
     text colour so the rail reads clearly on the canvas in either theme */
  --_track: color-mix(in srgb, var(--border-strong) 55%, var(--muted-foreground));
  max-width: 40rem; margin: 0 0 var(--sl-space-4);
}
.sl-stepper__count {
  margin: 0 0 var(--sl-space-3);
  font-size: var(--sl-text-sm); color: var(--muted-foreground);
}
.sl-stepper__steps { list-style: none; margin: 0; padding: 0; display: flex; align-items: flex-start; }
.sl-stepper__step {
  position: relative; flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sl-space-2);
  text-align: left;
}
/* the track: every station after the first draws its segment back to the
   previous marker (markers sit at the start of their cells) */
.sl-stepper__step + .sl-stepper__step::before {
  content: ""; position: absolute; height: 2px;
  top: calc(var(--_marker) / 2 - 1px);
  left: calc(-100% + var(--_marker) + var(--_track-inset));
  right: calc(100% + var(--_track-inset));
  border-radius: var(--sl-radius-full);
  background: var(--_track);
}
.sl-stepper__marker {
  width: var(--_marker); height: var(--_marker); border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--card); border: 2px solid var(--_track);
  color: var(--muted-foreground);
  font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold);
  font-variant-numeric: tabular-nums;
}
.sl-stepper__label {
  max-width: 9em; padding-inline: 0 var(--sl-space-1);
  font-size: var(--sl-text-sm); line-height: var(--sl-leading-snug);
  font-weight: var(--sl-weight-medium); color: var(--muted-foreground);
  /* every label reserves two lines, so one-line and two-line titles produce
     the same row height and the markers sit on one even rhythm */
  min-height: calc(2em * var(--sl-leading-snug));
}
/* completed stations read done-green; the track segments up to and including
   the current station fill to match */
.sl-stepper__step--done .sl-stepper__marker {
  background: var(--status-done-dot); border-color: var(--status-done-dot); color: #fbfaf6;
}
.sl-stepper__step--done .sl-stepper__label { color: var(--foreground); }
.sl-stepper__step--done::before,
.sl-stepper__step--current::before { background: var(--status-done-dot); }
.sl-stepper__step--current .sl-stepper__marker {
  background: var(--primary); border-color: var(--primary); color: var(--primary-foreground);
  box-shadow: 0 0 0 4px var(--accent);
}
.sl-stepper__step--current .sl-stepper__label { color: var(--foreground); font-weight: var(--sl-weight-semibold); }
/* tablet: keep every title, one size down and a touch narrower so six of
   them wrap cleanly instead of crowding their neighbours */
@media (min-width: 481px) and (max-width: 768px) {
  .sl-stepper__label { font-size: var(--sl-text-xs); max-width: 7em; }
}
/* wide: the titled stations say it all, so the count line goes screen-reader-only */
@media (min-width: 481px) {
  .sl-stepper__count {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; border: 0;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }
}
/* mobile: markers only; the count line takes over from the titles */
@media (max-width: 480px) {
  .sl-stepper { --_marker: 1.75rem; }
  .sl-stepper__marker { font-size: var(--sl-text-xs); }
  .sl-stepper__label {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; border: 0;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }
}

/* --- Next-step panel · the waiting-mode hand-off --------------------------- */
/* A feature-card variant: while the journey is gated on someone else, this is
   the page's one status statement. The eyebrow is constant ("What happens
   next") so applicants learn where to look; the coral comes from the feature
   card's one flourish rule. Where it renders, the status pill and the passive
   bottom bar stand down. */
.sl-next-step { padding: var(--sl-space-8); }
.sl-next-step .sl-eyebrow { display: block; margin-bottom: var(--sl-space-3); }
.sl-next-step__title {
  font-family: var(--sl-font-display);
  font-weight: var(--sl-weight-bold);
  letter-spacing: -0.025em;
  line-height: var(--sl-leading-snug);
  font-size: clamp(1.375rem, 1.1rem + 1.2vw, 1.75rem);
  text-wrap: balance;
}
.sl-next-step__body {
  margin-top: var(--sl-space-3);
  line-height: var(--sl-leading-relaxed);
  max-width: 58ch;
}
.sl-next-step__footer {
  display: flex; align-items: flex-start; gap: var(--sl-space-3);
  margin-top: var(--sl-space-6); padding-top: var(--sl-space-5);
  border-top: 1px solid color-mix(in srgb, var(--sl-navy-100) 22%, transparent);
}
.sl-next-step__bell { flex: none; margin-top: 0.1rem; color: var(--sl-navy-100); }
.sl-next-step__footer p { font-size: var(--sl-text-sm); line-height: var(--sl-leading-normal); }
.sl-next-step__note { color: var(--sl-navy-100); }
@media (max-width: 480px) { .sl-next-step { padding: var(--sl-space-6); } }

/* --- Journey card · the Ladder's titled home on the applicant home --------- */
.sl-journey {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--sl-radius-lg);
  box-shadow: var(--sl-shadow-sm);
}
.sl-journey__header { padding: var(--sl-space-6) var(--sl-space-6) 0; }
.sl-journey__title {
  font-size: var(--sl-text-lg); font-weight: var(--sl-weight-semibold);
  letter-spacing: var(--sl-tracking-snug); line-height: var(--sl-leading-snug);
}
.sl-journey__body { padding: var(--sl-space-5) var(--sl-space-6) var(--sl-space-6); }
@media (max-width: 480px) {
  .sl-journey__header { padding: var(--sl-space-5) var(--sl-space-5) 0; }
  .sl-journey__body { padding: var(--sl-space-4) var(--sl-space-5) var(--sl-space-5); }
}

/* --- The Ladder · vertical journey timeline (signature motif) -------------- */
.sl-ladder { list-style: none; padding: 0; display: flex; flex-direction: column; }
.sl-rung {
  position: relative; padding: 0 0 var(--sl-space-6) var(--sl-space-10); min-height: 3.5rem;
}
.sl-rung::before {                         /* the rail */
  content: ""; position: absolute; left: 0.6875rem; top: 1.5rem; bottom: -0.25rem;
  width: 2px; background: var(--border-strong);
}
.sl-rung:last-child { padding-bottom: 0; }
.sl-rung:last-child::before { display: none; }
.sl-rung__node {                           /* the rung marker */
  position: absolute; left: 0; top: 0.15rem;
  width: 1.5rem; height: 1.5rem; border-radius: 50%;
  background: var(--card); border: 2px solid var(--border-strong);
  display: grid; place-items: center; color: var(--muted-foreground);
  font-size: 0.7rem; font-weight: 700;
}
.sl-rung__title { font-weight: var(--sl-weight-semibold); font-size: var(--sl-text-base); }
.sl-rung__meta  { font-size: var(--sl-text-sm); color: var(--muted-foreground); margin-top: 0.1rem; }
/* states */
.sl-rung--neutral .sl-rung__node { border-color: var(--status-neutral-dot); color: var(--status-neutral-fg); }
.sl-rung--done    .sl-rung__node { background: var(--sl-green-600); border-color: var(--sl-green-600); color: #fbfaf6; }
.sl-rung--done::before { background: var(--sl-green-500); }
.sl-rung--active  .sl-rung__node { border-color: var(--sl-blue-500); color: var(--sl-blue-700);
  box-shadow: 0 0 0 4px var(--sl-blue-100); }
.sl-rung--action  .sl-rung__node { background: var(--sl-teal-100); border-color: var(--sl-teal-500); color: var(--sl-teal-700); }
.sl-rung--waiting .sl-rung__node { color: var(--status-waiting-fg); border-color: var(--status-waiting-dot); }
.sl-rung--problem .sl-rung__node { color: var(--status-problem-fg); border-color: var(--status-problem-dot); background: var(--status-problem-bg); }

/* Appointment card: the booked adviser session as an event card on the active rung.
   Date at a glance on the left, the full line and reassurance on the right. */
.sl-appointment-card {
  display: flex; align-items: center; gap: var(--sl-space-4);
  margin-top: var(--sl-space-3); padding: var(--sl-space-4);
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--sl-radius-md); box-shadow: var(--sl-shadow-sm);
}
.sl-appointment-card__date {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  flex: none; width: 3.5rem; padding: var(--sl-space-2) 0;
  background: var(--chip); color: var(--chip-foreground);
  border-radius: var(--sl-radius-sm);
}
.sl-appointment-card__weekday, .sl-appointment-card__month {
  font-size: var(--sl-text-xs); font-weight: var(--sl-weight-semibold);
  letter-spacing: var(--sl-tracking-wide); line-height: var(--sl-leading-snug);
}
.sl-appointment-card__day {
  font-size: var(--sl-text-lg); font-weight: var(--sl-weight-bold);
  line-height: var(--sl-leading-snug); color: var(--accent-foreground);
}
.sl-appointment-card__body { display: flex; flex-direction: column; gap: var(--sl-space-1); }
.sl-appointment-card__title { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); }
.sl-appointment-card__when { font-size: var(--sl-text-sm); }
.sl-appointment-card__note { font-size: var(--sl-text-xs); color: var(--muted-foreground); }

/* Get-ahead cluster: optional early tasks inside the active rung. Quiet bordered
   rows — never the teal accent, which is reserved for "your turn" CTAs. */
.sl-get-ahead {
  display: grid; gap: var(--sl-space-3);
  margin-top: var(--sl-space-3); padding-top: var(--sl-space-3);
  border-top: 1px dashed var(--border);
}
.sl-get-ahead__row {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  column-gap: var(--sl-space-3);
  padding: var(--sl-space-3) var(--sl-space-4);
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--sl-radius-md);
  text-decoration: none; color: inherit;
  transition: background var(--sl-dur-fast) var(--sl-ease-out),
              border-color var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-get-ahead__row:hover { background: var(--muted); border-color: var(--border-strong); text-decoration: none; }
.sl-get-ahead__label { grid-column: 1; font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); }
.sl-get-ahead__why { grid-column: 1; font-size: var(--sl-text-xs); color: var(--muted-foreground); margin-top: 0.1rem; }
.sl-get-ahead__arrow { grid-column: 2; grid-row: 1 / span 2; color: var(--muted-foreground); font-size: var(--sl-text-sm); }
/* The end slot of a row that carries a state as well as an arrow. The rule
   above pins the arrow to the row's second column itself, so a pill beside it
   needs a holder that takes that position. */
.sl-get-ahead__end {
  grid-column: 2; grid-row: 1 / span 2;
  display: flex; align-items: center; gap: var(--sl-space-3);
}
.sl-get-ahead__end .sl-get-ahead__arrow { grid-column: auto; grid-row: auto; }
/* The same row with nothing to open: its title and its state, no arrow, no
   hover and no pointer. */
.sl-get-ahead__row--static { cursor: default; }
.sl-get-ahead__row--static:hover { background: var(--card); border-color: var(--border); }

/* The six-digit code field. Monospaced and spaced out, and about as wide as
   the six spaced digits it holds: six at 22px with a 0.35em space after each,
   plus the input's own side padding, which is why it is 13ch and why the space
   after the sixth digit comes back out of the right padding. */
.sl-input--code {
  font-family: var(--sl-font-mono);
  font-size: 22px; letter-spacing: 0.35em;
  width: 13ch; max-width: 100%;
  padding-right: calc(var(--sl-space-3) - 0.35em);
}

/* Journey status block rhythm. The pill, ladder and action bar stack as bare blocks
   in the shell with no inherited spacing, so the ladder breathes internally (even
   rungs) while its neighbours are jammed against it (measured: subtitle->pill 2px,
   pill->ladder 0px, ladder->passive 0px). Restore consistent vertical spacing. */
#status-partial { margin-top: var(--sl-space-6); }
#status-partial > .sl-pill { margin-bottom: var(--sl-space-5); }
#status-partial > .sl-next-step { margin-bottom: var(--sl-space-8); }
#status-partial > .sl-action-bar { margin-top: var(--sl-space-6); }

/* --- The account front door ------------------------------------------------
   The person's own page: every application they are a party to, one card each,
   newest first. Providers are named on the cards and nowhere in the chrome,
   because the account belongs to the person rather than to any one of them. */
.sl-app-list { display: flex; flex-direction: column; gap: var(--sl-space-4); margin-top: var(--sl-space-6); }
.sl-app-card {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--sl-space-6); padding: var(--sl-space-5) var(--sl-space-6);
  text-decoration: none; color: inherit;
  transition: box-shadow var(--sl-dur-fast) var(--sl-ease-out), transform var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-app-card:hover { box-shadow: var(--sl-shadow-md); text-decoration: none; }
.sl-app-card__main { min-width: 0; display: flex; flex-direction: column; gap: var(--sl-space-1); }
.sl-app-card__title {
  margin: 0; font-size: var(--sl-text-lg); font-weight: var(--sl-weight-bold);
  letter-spacing: var(--sl-tracking-tight);
}
.sl-app-card__meta { margin: 0; color: var(--muted-foreground); font-size: var(--sl-text-sm); }
.sl-app-card__side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sl-space-3); flex: none; }
.sl-app-card__open { display: inline-flex; align-items: center; gap: var(--sl-space-1); color: var(--sl-navy-600); }
/* An application that is not going ahead keeps its card and its status, dimmed. */
.sl-app-card--closed .sl-app-card__title { color: var(--muted-foreground); }
.sl-app-card--closed .sl-eyebrow { color: var(--muted-foreground); }
@media (max-width: 480px) {
  .sl-app-card { flex-direction: column; gap: var(--sl-space-3); }
  .sl-app-card__side { align-items: flex-start; flex-direction: row; justify-content: space-between; width: 100%; }
}

/* --- Provider band ----------------------------------------------------------
   Directly beneath the masthead on an application page: whose application this
   is, which home, and the way back to the account. The masthead's identity
   block is hidden at phone widths, so this is what names the provider there. */
.sl-provider-band {
  display: flex; align-items: center; gap: var(--sl-space-2); flex-wrap: wrap;
  padding: var(--sl-space-2) var(--sl-gutter);
  background: var(--sl-canvas-sunken); border-bottom: 1px solid var(--border);
  font-size: var(--sl-text-sm);
}
.sl-provider-band__org { font-weight: var(--sl-weight-semibold); color: var(--sl-navy-700); }
.sl-provider-band__sep { color: var(--muted-foreground); }
.sl-provider-band__home { color: var(--muted-foreground); }
.sl-provider-band__link {
  margin-left: auto; display: inline-flex; align-items: center; gap: var(--sl-space-1);
  font-weight: var(--sl-weight-semibold); text-decoration: none;
  color: var(--sl-navy-600); white-space: nowrap;
}

/* --- Navigation ------------------------------------------------------------ */
.sl-navbar {
  display: flex; align-items: center; gap: var(--sl-space-6);
  height: 4rem; padding: 0 var(--sl-gutter);
  background: color-mix(in srgb, var(--card) 80%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 50;
}
/* The masthead's two flexible ends: the account block never shrinks, and the
   nav cluster gives up room first (see the narrow-viewport rules below —
   wordmark, then padding and size) so real phone widths never reach it, and
   only scrolls within itself (labels never wrap mid-word) as the fallback
   for whatever's still too tight after that. */
.sl-navbar__nav {
  display: flex; gap: var(--sl-space-1); align-items: center;
  margin-left: auto; min-width: 0; overflow-x: auto;
}
.sl-navbar__account { display: flex; align-items: center; gap: var(--sl-space-2); margin-left: var(--sl-space-4); flex: none; }
.sl-navbar__identity { text-align: right; line-height: var(--sl-leading-snug); }
.sl-navbar__identity-name { font-size: var(--sl-text-xs); font-weight: var(--sl-weight-semibold); }
.sl-navbar__identity-org { font-size: var(--sl-text-xs); color: var(--muted-foreground); }
/* Narrow viewports: the avatar chip (which carries the name for assistive
   tech via its own aria-label) stands in for the name/organisation text, and
   the wordmark hands its accessible name to the anchor's aria-label — both
   free up room so the nav labels below don't have to clip. */
@media (max-width: 480px) {
  .sl-navbar { gap: var(--sl-space-3); }
  .sl-navbar__identity { display: none; }
  .sl-navbar__account { margin-left: var(--sl-space-2); }
  .sl-navbar__wordmark { display: none; }
}
.sl-nav-link {
  font-size: var(--sl-text-sm); font-weight: var(--sl-weight-medium);
  color: var(--sl-ink-600); padding: var(--sl-space-2) var(--sl-space-3);
  border-radius: 0; text-decoration: none; transition: color 0.15s ease;
  white-space: nowrap;
}
/* Hover is color-only (muted → full navy): no fill, no line, so the underline
   below stays exclusive to the active page and nothing competes with it. */
.sl-nav-link:hover { color: var(--sl-navy-700); background: transparent; text-decoration: none; }
.sl-nav-link[aria-current="page"] {
  color: var(--sl-navy-700); font-weight: var(--sl-weight-semibold);
  box-shadow: inset 0 -2px 0 0 var(--primary);
}
/* Smallest phones: hiding the identity text and the wordmark isn't enough
   room on its own, so the nav labels also give up their side padding and
   drop a size — still full words, just tighter. */
@media (max-width: 380px) {
  .sl-nav-link { padding-left: var(--sl-space-1); padding-right: var(--sl-space-1); font-size: var(--sl-text-xs); }
  .sl-navbar__nav { gap: 0; }
}
/* A nav item whose destination something else on the page already offers at
   phone widths (the way back to the account, which the provider band carries).
   It stands down there rather than crowding the labels that have nowhere else
   to go. */
@media (max-width: 480px) {
  .sl-nav-link--wide-only { display: none; }
}
/* --- Staff sidebar --------------------------------------------------------- */
/* The signed-in staff shell: a fixed left rail beside a content column. Applicants
   and professionals keep the horizontal .sl-navbar masthead above. */
.sl-layout--sidenav { flex: 1 0 auto; display: flex; align-items: stretch; }
/* The content column beside the rail. min-width:0 is load-bearing: without it a wide
   table inside the column forces the flex item wider than its track and the sidebar
   is pushed off-screen. */
.sl-layout__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.sl-sidenav {
  width: var(--sl-sidenav-width); flex: none;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
  display: flex; flex-direction: column;
  background: var(--card); border-right: 1px solid var(--border);
  padding: var(--sl-space-5) var(--sl-space-3) var(--sl-space-4);
}
.sl-sidenav__brand {
  display: flex; align-items: center; gap: var(--sl-space-2);
  font-weight: var(--sl-weight-bold); font-size: var(--sl-text-md);
  color: var(--primary); letter-spacing: var(--sl-tracking-snug);
  text-decoration: none; padding: 0 var(--sl-space-3) var(--sl-space-5);
}
.sl-sidenav__brand:hover { text-decoration: none; }
/* The quick action above the nav: a full-width primary button ("Generate
   application link") that starts a new application. Its own class, not
   .sl-sidenav__link, so the nav-link styling and label parsing stay clean. */
.sl-sidenav__cta {
  display: flex; align-items: center; justify-content: center; gap: var(--sl-space-2);
  margin-bottom: var(--sl-space-4);
  padding: var(--sl-space-3) var(--sl-space-3);
  background: var(--primary); color: var(--primary-foreground);
  border-radius: var(--sl-radius-md);
  font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold);
  text-decoration: none; line-height: var(--sl-leading-snug);
  transition: background var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-sidenav__cta:hover { background: var(--primary-hover); text-decoration: none; }
.sl-sidenav__cta svg { flex: none; }
.sl-sidenav__nav { display: flex; flex-direction: column; gap: var(--sl-space-1); }
.sl-sidenav__link {
  display: flex; align-items: center; gap: var(--sl-space-2);
  padding: var(--sl-space-2) var(--sl-space-3);
  border-radius: var(--radius); font-size: var(--sl-text-sm); font-weight: var(--sl-weight-medium);
  color: var(--foreground); text-decoration: none; line-height: var(--sl-leading-snug);
}
.sl-sidenav__link svg { flex: none; opacity: 0.7; }
.sl-sidenav__link:hover { background: var(--muted); text-decoration: none; }
.sl-sidenav__link[aria-current="page"] {
  background: var(--accent); color: var(--accent-foreground);
  font-weight: var(--sl-weight-semibold);
}
.sl-sidenav__link[aria-current="page"] svg { opacity: 1; }
.sl-sidenav__break { border: none; border-top: 1px solid var(--border); margin: var(--sl-space-3) var(--sl-space-3); }
/* The signed-in user chip, pinned to the bottom of the rail */
.sl-sidenav__user {
  margin-top: auto; display: flex; align-items: center; gap: var(--sl-space-2);
  padding: var(--sl-space-4) var(--sl-space-3) 0; border-top: 1px solid var(--border);
}
.sl-sidenav__user-name { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); line-height: var(--sl-leading-tight); }
/* The chip when the person works for more than one housing provider: the name
   they are acting as, labelled, with the way to change it under it. Layout
   only; the label, the button and the confirmation are existing styles. */
.sl-sidenav__user--acting { display: block; }
.sl-sidenav__user-row { display: flex; align-items: center; gap: var(--sl-space-2); }
.sl-sidenav__acting-label { margin: var(--sl-space-2) 0 1px; line-height: var(--sl-leading-tight); }
.sl-sidenav__user-org--acting {
  font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); color: var(--foreground);
}
.sl-sidenav__user--acting .sl-btn { margin-top: var(--sl-space-3); }
.sl-sidenav__user-org { font-size: var(--sl-text-xs); color: var(--muted-foreground); line-height: var(--sl-leading-tight); }
.sl-sidenav__user form { margin-left: auto; }
.sl-sidenav__logout {
  display: grid; place-items: center; width: var(--sl-space-8); height: var(--sl-space-8);
  border: none; background: none; border-radius: var(--radius);
  color: var(--muted-foreground); cursor: pointer;
}
.sl-sidenav__logout:hover { background: var(--muted); color: var(--foreground); }
/* Narrow viewports: the rail collapses to a full-width strip above the content.
   Staff work these screens at a desk, so the rail is laid out for a desktop
   first; this keeps a phone usable rather than polished. */
@media (max-width: 480px) {
  .sl-layout--sidenav { flex-direction: column; }
  .sl-sidenav {
    position: static; width: 100%; height: auto; overflow-y: visible;
    flex-direction: row; flex-wrap: wrap; align-items: center;
    border-right: none; border-bottom: 1px solid var(--border);
    padding: var(--sl-space-2) var(--sl-space-3);
  }
  .sl-sidenav__brand { padding: var(--sl-space-2) var(--sl-space-3); }
  .sl-sidenav__cta { margin-bottom: 0; }
  .sl-sidenav__nav { flex-direction: row; flex-wrap: wrap; width: 100%; }
  .sl-sidenav__break { display: none; }
  .sl-sidenav__user { margin-top: 0; margin-left: auto; border-top: none; padding: var(--sl-space-2) var(--sl-space-3); }
  /* The acting chip takes the whole width of the collapsed strip, so the label
     and the button read the same as they do on the rail. */
  .sl-sidenav__user--acting {
    margin-left: 0; width: 100%; margin-top: var(--sl-space-2);
    border-top: 1px solid var(--border); padding-top: var(--sl-space-3);
  }
}

/* Muted inline link back to the previous screen */
.sl-back-link {
  display: inline-flex; align-items: center; gap: var(--sl-space-1);
  font-size: var(--sl-text-sm); font-weight: var(--sl-weight-medium);
  color: var(--muted-foreground); text-decoration: none;
}
.sl-back-link:hover { color: var(--foreground); text-decoration: underline; text-underline-offset: 0.2em; }
/* Quiet text link in a card or section header ("View all", "View site status").
   Colour and hover come from the base anchor rule. */
.sl-card-link { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); white-space: nowrap; }

/* --- Footer ----------------------------------------------------------------- */
.sl-footer {
  border-top: 1px solid var(--border); background: var(--card);
  padding: var(--sl-space-8) var(--sl-gutter);
}
.sl-footer__row {
  max-width: var(--sl-container); margin-inline: auto;
  display: flex; flex-wrap: wrap; gap: var(--sl-space-6);
  align-items: center; justify-content: space-between;
}
.sl-footer__brand { display: flex; align-items: center; gap: 0.625rem; color: var(--primary); }
.sl-footer__name { font-weight: var(--sl-weight-bold); color: var(--primary); font-size: 0.9375rem; letter-spacing: -0.01em; }
.sl-footer__copyright { font-size: var(--sl-text-xs); color: var(--muted-foreground); }
.sl-footer__links {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sl-space-2) var(--sl-space-6); font-size: 0.8125rem;
  /* Keep clear of the assistant's floating button (fixed bottom-right, .chat-trigger):
     on short pages the footer sits at the viewport bottom and the button would
     otherwise cover the last link. */
  padding-inline-end: var(--sl-space-16);
}
.sl-footer__links a { color: var(--primary); text-decoration: none; }
.sl-footer__links a:hover { text-decoration: underline; text-underline-offset: 0.2em; }
.sl-footer__links a[href^="mailto:"] { font-weight: var(--sl-weight-semibold); }
.sl-footer__legal {
  max-width: var(--sl-container); margin-inline: auto;
  margin-top: var(--sl-space-4); padding-top: var(--sl-space-4);
  border-top: 1px solid var(--border);
}
.sl-footer__legal p {
  margin: 0; font-size: var(--sl-text-xs); color: var(--muted-foreground);
  max-width: 68ch; line-height: 1.5;
}

/* --- Page rail -------------------------------------------------------------
   The band above a data table: what the page is counting on the left, the one
   fact or control that scopes it on the right, sharing a single hairline. */
.sl-rail {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--sl-space-4); border-bottom: 1px solid var(--border);
  margin-block: var(--sl-space-4);
}
/* The plot inventory's rail: status counts left, the development's minimum
   share right, both sitting on the hairline's centre line. */
.sl-rail--inventory { align-items: center; margin-block: 0 var(--sl-space-5); padding-block-end: var(--sl-space-4); }
.sl-status-counts { display: flex; flex-wrap: wrap; gap: var(--sl-space-2); }
/* One standing fact about the page, stated rather than filtered on. */
.sl-page-fact { display: inline-flex; align-items: center; gap: var(--sl-space-2); white-space: nowrap; }
.sl-page-fact__value { font-size: var(--sl-text-base); font-weight: var(--sl-weight-semibold); font-variant-numeric: tabular-nums; }
/* A line under one value in a detail list, saying where the value came from —
   used where a plot shows a figure its development sets for it. */
.sl-detail-sub { font-size: var(--sl-text-xs); color: var(--muted-foreground); }

/* --- Tabs ------------------------------------------------------------------ */
.sl-tabs { display: flex; gap: var(--sl-space-1); border-bottom: 1px solid var(--border); }
.sl-tab {
  appearance: none; background: none; border: none; cursor: pointer;
  font-family: inherit; font-size: var(--sl-text-sm); font-weight: var(--sl-weight-medium);
  color: var(--muted-foreground); padding: var(--sl-space-3) var(--sl-space-3);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.sl-tab:hover { color: var(--foreground); }
.sl-tab[aria-selected="true"] { color: var(--primary); border-bottom-color: var(--primary); }

/* Queue-size chip on a work-queue tab (e.g. "Needs your action", "Dormant"). */
.sl-tab-count {
  background: var(--chip); color: var(--chip-foreground);
  border-radius: var(--sl-radius-full);
  font-size: var(--sl-text-xs); font-weight: var(--sl-weight-semibold);
  padding: 0 var(--sl-space-2);
  margin-inline-start: var(--sl-space-1);
  font-variant-numeric: tabular-nums;
}

/* Colour key for the six stage-pill states: a quiet row of swatch dot + plain
   label, sitting between a tab rail and the table it explains. */
.sl-stage-key {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sl-space-4);
  font-size: var(--sl-text-xs); color: var(--muted-foreground);
}
.sl-stage-key__item { display: inline-flex; align-items: center; gap: var(--sl-space-1); white-space: nowrap; }

/* --- Table ----------------------------------------------------------------- */
.sl-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.sl-table { width: 100%; border-collapse: collapse; font-size: var(--sl-text-sm); }
.sl-table th {
  text-align: left; font-weight: var(--sl-weight-semibold); color: var(--muted-foreground);
  font-size: var(--sl-text-xs); text-transform: uppercase; letter-spacing: var(--sl-tracking-wide);
  padding: var(--sl-space-3) var(--sl-space-4); border-bottom: 1px solid var(--border);
}
.sl-table td { padding: var(--sl-space-4); border-bottom: 1px solid var(--border); }
/* A column of figures: right-aligned so the digits line up, on the header too. */
.sl-table__num { text-align: right; font-variant-numeric: tabular-nums; }
/* The one row a table is being read against — the plot applied for, say. */
.sl-table__row--marked > td { background: var(--chip); }
/* A cell whose value reads as one name and must not break mid-name. */
.sl-table__cell--nowrap { white-space: nowrap; }
/* No whole-row hover tint: rows aren't clickable (actions are buttons/links in cells),
   no signed-off mockup shows a hovered row, and the frozen capture harness leaves the
   pointer resting on a row after the login click — which baked a stray hover into the
   render. Reintroduce behind an opt-in .sl-table--interactive modifier if ever needed. */
/* A table that folds on a phone. Above 480px every column is a column and the
   folded lines are not rendered at all. At 480px and below the cells marked
   --phone-hidden drop out and their values are carried on the lines inside the
   cell that stays, so the columns a reader opened the page for are on the
   screen rather than off the edge of a sideways scroll. Which cells fold is
   per table, because what has to stay visible differs: a work queue keeps the
   name beside the status pill, a roster of people folds to one cell the width
   of the card. */
.sl-table__phone-line { display: none; }
@media (max-width: 480px) {
  .sl-table--stacked .sl-table__phone-hidden { display: none; }
  .sl-table--stacked .sl-table__phone-line {
    display: block; margin-top: var(--sl-space-1);
    font-size: var(--sl-text-xs); color: var(--muted-foreground);
    overflow-wrap: anywhere;
  }
}

/* --- Avatar ---------------------------------------------------------------- */
.sl-avatar {
  width: 2.5rem; height: 2.5rem; border-radius: 50%; display: grid; place-items: center;
  background: var(--sl-navy-100); color: var(--sl-navy-700); font-weight: 600; font-size: var(--sl-text-sm);
}
.sl-avatar--sm { width: 2rem; height: 2rem; font-size: var(--sl-text-xs); }

/* --- Layout helpers (showcase only) ---------------------------------------- */
.sl-container { max-width: var(--sl-container); margin-inline: auto; padding-inline: var(--sl-gutter); }
.sl-stack > * + * { margin-top: var(--sl-space-4); }
.sl-cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sl-space-3); }
/* Options that stack instead of sitting in a row: what an option reveals when
   it is chosen appears under the whole group, so an inline row would put the
   revealed content beside the option that asked for it. */
.sl-cluster--stacked { flex-direction: column; align-items: flex-start; }
/* A row of stage-advance buttons, each its own tiny form */
.sl-advance-controls { display: flex; flex-wrap: wrap; gap: var(--sl-space-3); margin-top: var(--sl-space-4); }
.sl-grid { display: grid; gap: var(--sl-space-6); grid-template-columns: 1fr; }
@media (min-width: 481px) { .sl-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 769px) { .sl-grid { grid-template-columns: repeat(3, 1fr); } }
.sl-py-8 { padding-top: var(--sl-space-8); padding-bottom: var(--sl-space-8); }

/* Readable content column: a page's outer band when it holds a form or prose, not a data screen */
.sl-content {
  width: 100%; max-width: 45rem; margin-inline: auto;
  padding: var(--sl-space-6) var(--sl-gutter) var(--sl-space-16);
}
/* Form-page variant (the application-form wizard): the column caps at the
   panel well, so the nested .sl-panel's auto margins have no room to offset
   it and the heading, stepper, applicant pills and section content all start
   on one left edge — a form page has a single left rail. */
.sl-content--form { max-width: calc(40rem + 2 * var(--sl-gutter)); }

/* --- Content panel (centred, padded content well) -------------------------- */
.sl-panel { padding: var(--sl-space-8) var(--sl-gutter); }
@media (min-width: 481px) { .sl-panel { max-width: 40rem; margin-inline: auto; } }
/* .sl-content already supplies the page's own side gutter, so a panel nested inside
   it must not add a second one — otherwise the panel's action bar (below) is bled
   back out by only one gutter and sits inset by the other. */
.sl-content .sl-panel { padding-inline: 0; }
/* Subtle callout variant: a smaller note box rather than the page's own content well */
.sl-panel--note {
  max-width: none; margin-inline: 0;
  padding: var(--sl-space-4) var(--sl-space-5);
  background: var(--muted); border: 1px solid var(--border); border-radius: var(--sl-radius-md);
}
/* A stack of side notes alongside the main case content */
.sl-carve-outs { display: flex; flex-direction: column; gap: var(--sl-space-4); margin-top: var(--sl-space-8); }

/* --- Motion: staggered entrance for page-load reveals ---------------------- */
@keyframes sl-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.sl-reveal { animation: sl-rise var(--sl-dur-slower) var(--sl-ease-out) both; }

/* --- Skeleton shimmer placeholder ------------------------------------------ */
@keyframes sl-shimmer {
  from { background-position: -200% 0; }
  to   { background-position:  200% 0; }
}
.sl-skeleton {
  background: linear-gradient(
    90deg,
    var(--sl-canvas-sunken) 25%,
    var(--sl-canvas)        50%,
    var(--sl-canvas-sunken) 75%
  );
  background-size: 200% 100%;
  animation: sl-shimmer 1.4s var(--sl-ease-in-out) infinite;
}
/* An indicator skeleton must not reserve layout space while idle: htmx only
   toggles opacity, so a min-height box would leave a permanent gap under the
   content. Collapse it unless a request is in flight (htmx adds .htmx-request
   to the requesting element and to the hx-indicator target). */
.sl-skeleton.htmx-indicator { display: none; }
.htmx-request .sl-skeleton.htmx-indicator,
.htmx-request.sl-skeleton.htmx-indicator { display: block; }
/* The plot picker's filters redraw their table in place. While the request is
   in flight the loaded rows and the count line give way to a skeleton table and
   the sentence saying what is being looked for, so the toolbar and the table
   keep their height and nothing jumps. */
.sl-plot-picker__skeleton, .sl-plot-picker__status { display: none; }
.htmx-request .sl-plot-picker__skeleton { display: table-row-group; }
.htmx-request .sl-plot-picker__status { display: inline; }
.htmx-request .sl-plot-picker__rows, .htmx-request .sl-plot-picker__count { display: none; }

/* === Screen scaffolding ===================================================== */

/* --- Page shells: staff and professional screens share a contained column -- */
.sl-shell {
  max-width: var(--sl-container); margin-inline: auto;
  padding: var(--sl-space-6) var(--sl-gutter) var(--sl-space-16);
}
/* Staff (back-office + analytics) screens all use .sl-shell.sl-shell--backoffice,
   so every HA screen presents ONE uniform content band — the same left/right edges
   page to page (Dashboard, Sites, Applications, Content, Team …). Retune the band in
   one place via --sl-container-backoffice.

   width:100% is load-bearing, not cosmetic: base.html nests the shell in a flex COLUMN
   (body → content div), and .sl-shell centres itself with margin-inline:auto. In a flex
   context an auto cross-axis margin cancels the default stretch, so without an explicit
   width the shell SHRINK-WRAPS to its content — a wide table reaches ~1200 but a card
   grid or form collapses far narrower (this is why the Sites hub looked narrower than
   the Dashboard). width:100% makes the shell fill its band up to max-width regardless
   of content, so every staff screen is the same width.

   Rule: a staff screen fills this band; it must never cap its top-level content
   narrower. A form or prose column may set its OWN width for readability, but it sits
   INSIDE this shell — it never replaces the shell as the page's outer band. See the
   "Back-office content width" section in DESIGN.md. */
/* The professional portal shares the staff content band (mirrors .sl-shell--backoffice) */
.sl-shell--backoffice, .sl-shell--portal { width: 100%; max-width: var(--sl-container-backoffice); }
/* Staff screens render no screen header, so the first content block sets the band's
   top edge; give it more headroom than the base shell provides. */
.sl-shell--backoffice { padding-block-start: var(--sl-space-10); }
.sl-shell__inner { max-width: 52rem; }
/* What one page says to the next, in the same band as that page's content. */
.sl-messages {
  max-width: var(--sl-container-backoffice); width: 100%; margin-inline: auto;
  padding: var(--sl-space-6) var(--sl-gutter) 0;
  display: grid; gap: var(--sl-space-3);
}
.sl-portal-nav {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sl-space-1);
  margin-bottom: var(--sl-space-6); padding-bottom: var(--sl-space-3);
  border-bottom: 1px solid var(--border);
}
.sl-portal-nav a {
  padding: var(--sl-space-1) var(--sl-space-3); border-radius: var(--sl-radius-sm);
  font-size: var(--sl-text-sm); font-weight: var(--sl-weight-medium);
  color: var(--muted-foreground); text-decoration: none;
  transition: background var(--sl-dur-fast) var(--sl-ease-out), color var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-portal-nav a:hover { background: var(--muted); color: var(--foreground); }
.sl-portal-nav a[aria-current="page"] {
  background: var(--accent); color: var(--accent-foreground); font-weight: var(--sl-weight-semibold);
}
/* The signed-in user's name: a plain label, not a link, pushed to the far end of the nav row */
.sl-portal-nav__user {
  margin-left: auto;
  font-size: var(--sl-text-sm);
  color: var(--muted-foreground);
}

/* --- Screen header: eyebrow + title + optional sub and end slot ------------ */
.sl-screen-header {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--sl-space-4); margin-bottom: var(--sl-space-6); flex-wrap: wrap;
}
.sl-screen-header h1 { margin: 0; font-size: var(--sl-text-xl); font-weight: var(--sl-weight-bold); letter-spacing: var(--sl-tracking-tight); }
.sl-screen-header__sub { margin: var(--sl-space-1) 0 0; font-size: var(--sl-text-sm); color: var(--muted-foreground); }

/* --- Key-value row: paper documents, fact sheets, case facts --------------- */
/* --- Detail grid: a card's facts read across, not down ----------------------
   Three to a row on a wide card, one to a row on a narrow one. Used where a
   screen states a handful of figures somebody reads at a glance rather than a
   list they compare down a column (which is what .sl-kv is for). */
.sl-detail-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sl-space-4); margin: 0; }
.sl-detail-grid dt { font-size: var(--sl-text-sm); color: var(--muted-foreground); }
.sl-detail-grid dd { margin: var(--sl-space-1) 0 0; }
.sl-detail-grid__lead { font-size: var(--sl-text-lg); font-weight: var(--sl-weight-semibold); letter-spacing: var(--sl-tracking-tight); }
/* Two to a row, for a card whose facts are long enough that three columns
   break an email address or a postal address over a line. It folds to one
   column where the three-column grid does. */
.sl-detail-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 48rem) { .sl-detail-grid, .sl-detail-grid--2 { grid-template-columns: 1fr; } }

.sl-kv {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--sl-space-4);
  padding: var(--sl-space-2) 0; border-bottom: 1px solid var(--border);
  font-size: var(--sl-text-sm);
}
.sl-kv:last-child { border-bottom: none; }
.sl-kv__key { color: var(--muted-foreground); }
.sl-kv__value { font-variant-numeric: tabular-nums; text-align: right; }
.sl-kv--strong .sl-kv__value { font-weight: var(--sl-weight-bold); font-size: var(--sl-text-base); }

/* --- Paper document: the generated-document reading surface ---------------- */
.sl-paper {
  background: var(--sl-surface); border: 1px solid var(--border);
  border-radius: var(--sl-radius-lg); box-shadow: var(--sl-shadow-md);
  padding: var(--sl-space-8) var(--sl-space-8) var(--sl-space-6);
}
.sl-paper__eyebrow { display: block; margin-bottom: var(--sl-space-2); }
.sl-paper__title { margin: 0 0 var(--sl-space-4); font-size: var(--sl-text-xl); font-weight: var(--sl-weight-bold); letter-spacing: var(--sl-tracking-tight); }
.sl-paper__footer {
  margin-top: var(--sl-space-6); padding-top: var(--sl-space-3);
  border-top: 1px solid var(--border);
  font-size: var(--sl-text-xs); color: var(--muted-foreground);
}

/* --- Stat tile: the status board's headline numbers ------------------------ */
.sl-stat-tile {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--sl-radius-md); padding: var(--sl-space-4);
  box-shadow: var(--sl-shadow-xs);
}
.sl-stat-tile__label {
  font-size: var(--sl-text-xs); font-weight: var(--sl-weight-semibold);
  text-transform: uppercase; letter-spacing: var(--sl-tracking-wide);
  color: var(--muted-foreground);
}
.sl-stat-tile__value {
  font-size: var(--sl-text-3xl); font-weight: 800;
  letter-spacing: var(--sl-tracking-tight); font-variant-numeric: tabular-nums;
  line-height: var(--sl-leading-tight); margin-top: var(--sl-space-1);
}
.sl-stat-tile__value--compact { font-size: var(--sl-text-lg); }
/* The applicant screens carry their key numbers one step under the staff
   board's full-size figure. */
.sl-stat-tile__value--medium { font-size: var(--sl-text-2xl); }
.sl-stat-tile__sub { font-size: var(--sl-text-xs); color: var(--muted-foreground); margin-top: var(--sl-space-1); }
.sl-stat-tile__state { margin-top: var(--sl-space-1); }
.sl-stat-tile--problem .sl-stat-tile__value { color: var(--status-problem-fg); }

/* --- Application funnel: stage bars from a shared baseline ------------------
   The staff home's applications card. Bar heights are the data (each stage's
   share of starts); the pale wedge between bars is the drop-off to the next
   stage. Bars and their labels share one column template so they align. */
.sl-funnel { display: grid; grid-template-columns: 3fr 2fr 3fr 2fr 3fr 2fr 3fr; align-items: end; height: 6rem; }
.sl-funnel__bar {
  background: var(--sl-navy-600); color: #fbfaf6;
  border-radius: var(--sl-radius-sm) var(--sl-radius-sm) 0 0;
  display: grid; place-items: start center; padding-top: var(--sl-space-1);
  font-size: var(--sl-text-xl); font-weight: 800;
  font-variant-numeric: tabular-nums; line-height: 1.3;
}
.sl-funnel__drop { background: var(--sl-navy-50); height: 100%; }
.sl-funnel__labels { display: grid; grid-template-columns: 3fr 2fr 3fr 2fr 3fr 2fr 3fr; margin-block: var(--sl-space-2) var(--sl-space-4); text-align: center; }
.sl-funnel__stage { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); line-height: var(--sl-leading-snug); }
.sl-funnel__share { font-size: var(--sl-text-xs); color: var(--muted-foreground); margin-top: 2px; }

/* --- Journey insight tiles: icon in a status tint, value, defined label ----- */
.sl-insight-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sl-space-3); }
.sl-insight {
  display: flex; gap: var(--sl-space-3); align-items: center;
  border: 1px solid var(--border); border-radius: var(--sl-radius-md);
  padding: var(--sl-space-3) var(--sl-space-4); background: var(--card);
  box-shadow: var(--sl-shadow-xs);
}
.sl-insight__icon {
  width: 2.25rem; height: 2.25rem; border-radius: var(--sl-radius-full);
  display: grid; place-items: center; flex: none;
}
.sl-insight__icon--active  { background: var(--status-active-bg);  color: var(--status-active-fg); }
.sl-insight__icon--action  { background: var(--status-action-bg);  color: var(--status-action-fg); }
.sl-insight__icon--neutral { background: var(--status-neutral-bg); color: var(--status-neutral-fg); }
.sl-insight__icon--problem { background: var(--status-problem-bg); color: var(--status-problem-fg); }
.sl-insight__value { font-size: var(--sl-text-xl); font-weight: 800; line-height: var(--sl-leading-tight); font-variant-numeric: tabular-nums; }
.sl-insight__value small { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); }
.sl-insight__label { display: flex; align-items: center; gap: var(--sl-space-2); font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); line-height: var(--sl-leading-snug); }

/* --- Stat grid: a uniform row/grid of stat tiles ---------------------------- */
/* Labels flow as centred text (a long label wraps with its swatch dot inline);
   the value's auto margin bottom-anchors the number, so values stay aligned
   across the row even when one tile's label wraps to two lines. */
.sl-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); gap: var(--sl-space-4); }
.sl-stat-grid .sl-stat-tile { text-align: center; display: flex; flex-direction: column; align-items: center; gap: var(--sl-space-1); }
.sl-stat-grid .sl-stat-tile__label .sl-swatch-dot { margin-inline-end: var(--sl-space-1); }
.sl-stat-grid .sl-stat-tile__value { margin-top: auto; }
.sl-stat-grid .sl-stat-tile__state { margin-top: 0; }
/* Exactly two figures, read as a pair: side by side wherever the pair fits,
   and stacked on a narrow phone rather than pushed off the screen. The floor is
   the base grid's, raised, because these two carry money at the larger value
   size. */
.sl-stat-grid--two-up {
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  margin-bottom: var(--sl-space-6);
}
.sl-stat-grid--two-up .sl-stat-tile { min-width: 0; }

/* --- Metric groups: a band of stat grids under muted group headings --------- */
/* The development-status board reads as two questions, not one row of seven
   figures: what the development has sold, and at what share. Each group opens
   with its own subheading over its own grid. */
.sl-metric-block { margin-block-end: var(--sl-space-6); }
.sl-metric-group + .sl-metric-group { margin-block-start: var(--sl-space-6); }
.sl-metric-group .sl-subheading { display: block; margin: 0 0 var(--sl-space-3); }
/* Both groups share one four-column rhythm, so a tile is the same width
   wherever it sits and a group with fewer figures fills fewer cells instead of
   stretching across the band.

   The threshold is a VIEWPORT width but the grid sits in the content column
   beside the staff rail, so it has to be read off what that column is left
   with, not off the window: four 9.5rem tracks and three 1rem gaps need 41rem,
   the rail takes 15.5rem and the two gutters about 3.4rem between them, which
   comes to 60rem of window before the four fit. Fixed at a lower threshold the
   tracks cannot rewrap, so the fourth tile is pushed past the right edge of the
   screen and the page gains a horizontal scrollbar. Below it the grid keeps the
   auto-fit rule and wraps.

   The tracks floor at 0 rather than at 9.5rem for the same reason: the rail
   width, the gutters and the content band are all tokens, and a track that
   cannot shrink turns any future change to one of them into an off-screen
   tile. */
@media (min-width: 60rem) {
  .sl-metric-group .sl-stat-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --- Swatch dot: bare unit-status colour chip (legends, tile labels) -------- */
.sl-swatch-dot { display: inline-block; width: 0.5625rem; height: 0.5625rem; border-radius: 2px; background: var(--_dot); flex: none; }

/* --- Info tooltip: inline (i) trigger revealing a short definition ---------- */
.sl-tooltip { position: relative; display: inline-flex; }
.sl-tooltip__trigger {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1rem; height: 1rem; padding: 0; line-height: 1;
  border: 1px solid var(--border-strong); border-radius: var(--sl-radius-full);
  background: transparent; color: var(--muted-foreground);
  font-family: inherit; font-size: 0.625rem; font-weight: var(--sl-weight-semibold);
  cursor: help;
}
.sl-tooltip__trigger:hover, .sl-tooltip__trigger:focus { color: var(--foreground); border-color: var(--foreground); }
.sl-tooltip__bubble {
  position: absolute; bottom: calc(100% + var(--sl-space-2)); left: 50%;
  transform: translateX(-50%); z-index: 30; pointer-events: none;
  width: max-content; max-width: 16rem; padding: var(--sl-space-2) var(--sl-space-3);
  border-radius: var(--sl-radius-sm);
  background: var(--foreground); color: var(--background);
  font-size: var(--sl-text-xs); font-weight: var(--sl-weight-regular);
  line-height: var(--sl-leading-normal); letter-spacing: normal;
  text-transform: none; text-align: left; white-space: normal;
  opacity: 0; visibility: hidden;
  transition: opacity var(--sl-dur-fast) var(--sl-ease-out), visibility var(--sl-dur-fast);
}
.sl-tooltip__trigger:hover + .sl-tooltip__bubble,
.sl-tooltip__trigger:focus + .sl-tooltip__bubble { opacity: 1; visibility: visible; }
/* Explainer variant: two or three short paragraphs of rule text. The script
   toggles .is-open — opened on click, tap or focus, kept open until Escape,
   an outside click or focus moving away. Anchored to the trigger's left edge
   so it never centres off the edge of a card. */
.sl-tooltip__bubble--explainer { max-width: 22rem; left: 0; transform: none; pointer-events: auto; }
.sl-tooltip__bubble--explainer p { margin: 0; }
.sl-tooltip__bubble--explainer p + p { margin-top: var(--sl-space-2); }
/* Focus alone no longer reveals the explainer — the script opens it on focus
   instead, so Escape can close it while the trigger keeps focus. Hover still
   previews it either way. */
.sl-tooltip__trigger:focus + .sl-tooltip__bubble--explainer:not(.is-open) { opacity: 0; visibility: hidden; }
.sl-tooltip__trigger:hover + .sl-tooltip__bubble--explainer:not(.is-open) { opacity: 1; visibility: visible; }
.sl-tooltip__bubble.is-open { opacity: 1; visibility: visible; }
/* A trigger at the end of a rail or frame edge: the bubble hangs from the
   trigger's right edge and opens downward, staying inside the card. */
.sl-tooltip--end .sl-tooltip__bubble--explainer { left: auto; right: 0; bottom: auto; top: calc(100% + var(--sl-space-2)); }
/* Beside a card title on a phone, neither placement above fits: a 22rem bubble
   hanging off a trigger two thirds of the way across a 390px screen runs off
   one edge or the other. Inside a card header it takes the card's own width
   and opens under the title instead, which cannot overflow whatever the
   heading's length. */
@media (max-width: 480px) {
  .sl-card__header { position: relative; }
  .sl-card__header .sl-tooltip { position: static; }
  .sl-card__header .sl-tooltip__bubble--explainer {
    left: var(--sl-space-6); right: var(--sl-space-6);
    width: auto; max-width: none;
    bottom: auto; top: calc(100% + var(--sl-space-2));
  }
}
@media (prefers-reduced-motion: reduce) {
  .sl-tooltip__bubble { transition: none; }
}

/* --- Bar row: pipeline / funnel horizontal bars ----------------------------- */
.sl-bar-row { display: grid; grid-template-columns: 9rem 1fr auto; align-items: center; gap: var(--sl-space-3); padding: var(--sl-space-1) 0; }
.sl-bar-row__label { font-size: var(--sl-text-sm); color: var(--foreground); }
a.sl-bar-row__label { text-decoration: none; }
a.sl-bar-row__label:hover { text-decoration: underline; }
.sl-bar-row__track { height: 0.625rem; border-radius: var(--sl-radius-full); background: var(--sl-canvas-sunken); overflow: hidden; }
.sl-bar-row__fill { height: 100%; border-radius: var(--sl-radius-full); background: var(--sl-navy-500); }
.sl-bar-row--accent .sl-bar-row__fill { background: var(--sl-teal-500); }
.sl-bar-row__value { font-size: var(--sl-text-sm); font-variant-numeric: tabular-nums; font-weight: var(--sl-weight-semibold); }

/* --- Audit trail: the application's stage history --------------------------- */
.sl-trail { list-style: none; margin: 0; padding: 0; }
.sl-trail__row {
  position: relative; padding: 0 0 var(--sl-space-4) var(--sl-space-8);
}
.sl-trail__row::before {
  content: ""; position: absolute; left: 0.4375rem; top: 1rem; bottom: -0.25rem;
  width: 2px; background: var(--border-strong);
}
.sl-trail__row:last-child { padding-bottom: 0; }
.sl-trail__row:last-child::before { display: none; }
.sl-trail__dot {
  position: absolute; left: 0; top: 0.3rem;
  width: 1rem; height: 1rem; border-radius: 50%;
  background: var(--card); border: 2px solid var(--status-done-dot);
}
.sl-trail__row--current .sl-trail__dot { background: var(--status-active-dot); border-color: var(--status-active-dot); }
.sl-trail__label { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); }
.sl-trail__meta { font-size: var(--sl-text-xs); color: var(--muted-foreground); margin-top: 0.1rem; }

/* --- Check chip: a selectable tile wrapping a real checkbox ----------------- */
.sl-check-chip {
  display: inline-flex; align-items: center; gap: var(--sl-space-2);
  padding: var(--sl-space-2) var(--sl-space-3);
  border: 1px solid var(--border-strong); border-radius: var(--sl-radius-md);
  background: var(--card); cursor: pointer;
  font-size: var(--sl-text-sm); font-weight: var(--sl-weight-medium);
  transition: border-color var(--sl-dur-fast) var(--sl-ease-out), background var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-check-chip:hover { border-color: var(--sl-navy-400); }
.sl-check-chip:has(input:checked) { border-color: var(--sl-navy-500); background: var(--chip); }
.sl-check-chip:has(input:focus-visible) { box-shadow: var(--sl-shadow-focus); }
.sl-check-chip:has(input:disabled) { opacity: 0.5; cursor: not-allowed; }
.sl-check-chip input { accent-color: var(--primary); }

/* Selectable list row: choosing one option from a panelled list (a solicitor firm, a unit).
   A label wrapping a visually hidden radio — the whole row is the control, and the
   highlight + checkmark follow the LIVE selection (the checked radio), so clicking a
   row answers immediately rather than only after saving. */
.sl-firm-row {
  display: flex; align-items: center; gap: var(--sl-space-4);
  padding: var(--sl-space-4) var(--sl-space-5);
  cursor: pointer; position: relative;
  border-bottom: 1px solid var(--border);
  transition: background var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-firm-row:last-child { border-bottom: none; }  /* no stray divider before the action bar */
.sl-firm-row:hover { background: var(--muted); }
.sl-firm-row input[type="radio"] { position: absolute; opacity: 0; width: 0; height: 0; }
/* focus-within, scoped to keyboard focus: the hidden radio can't show its own ring */
.sl-firm-row:has(input:focus-visible) { outline: 2px solid var(--ring); outline-offset: -2px; }
.sl-firm-row__body { flex: 1; }
.sl-firm-row__name { font-weight: var(--sl-weight-semibold); }
/* .sl-firm-row--selected marks a server-rendered (saved) selection on read-only
   surfaces; live choosers get the same treatment from the checked radio. */
.sl-firm-row--selected, .sl-firm-row--selected:hover,
.sl-firm-row:has(input:checked), .sl-firm-row:has(input:checked):hover { background: var(--chip); }
/* The chooser's radio: the circle the team access drawer draws inline, here as
   a class, because a person must be able to see that the row is a choice. */
.sl-firm-row__radio {
  flex: none; box-sizing: border-box; width: 18px; height: 18px;
  border-radius: 999px; border: 1.5px solid var(--border);
  background-color: var(--background); display: grid; place-items: center;
  transition: border-color var(--sl-dur-fast) var(--sl-ease-out),
              background-color var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-firm-row:has(input:checked) .sl-firm-row__radio {
  border-color: var(--primary); background-color: var(--primary);
}
.sl-firm-row:has(input:checked) .sl-firm-row__radio::after {
  content: ""; width: 7px; height: 7px; border-radius: 999px;
  background: var(--primary-foreground);
}
.sl-firm-row__check {
  flex: none; color: var(--primary); opacity: 0;
  transition: opacity var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-firm-row--selected .sl-firm-row__check,
.sl-firm-row:has(input:checked) .sl-firm-row__check { opacity: 1; }

/* --- Share slider: the cost calculator's one control ------------------------ */
.sl-slider { width: 100%; margin: var(--sl-space-3) 0 var(--sl-space-1); accent-color: var(--primary); }
.sl-slider-head { display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: var(--sl-space-4); }
.sl-slider-head label { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); }
/* Held one step under the answers it drives: the control names the share, the
   tiles below carry the money. */
.sl-slider-head__value {
  font-size: var(--sl-text-lg); font-weight: 800;
  letter-spacing: var(--sl-tracking-tight); font-variant-numeric: tabular-nums;
}
.sl-slider-scale {
  display: flex; justify-content: space-between;
  font-size: var(--sl-text-xs); color: var(--muted-foreground);
  margin-bottom: var(--sl-space-5);
}

/* --- Unit row: one home in a list, with what it is priced from -------------- */
.sl-unit-list { display: grid; gap: var(--sl-space-2); }
/* What every price in the list is quoted at, stated once above them. */
.sl-unit-legend {
  font-size: var(--sl-text-xs); color: var(--muted-foreground);
  text-align: right; margin: 0 0 var(--sl-space-2);
}
.sl-unit-row {
  font: inherit; color: inherit; text-align: left; cursor: pointer; width: 100%;
  display: grid; grid-template-columns: 5rem minmax(0, 1fr) auto;
  gap: var(--sl-space-4); align-items: center;
  padding: var(--sl-space-4);
  border: 1px solid var(--border); border-radius: var(--sl-radius-md);
  background: var(--card);
  transition: background var(--sl-dur-fast) var(--sl-ease-out), border-color var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-unit-row:hover { border-color: var(--border-strong); }
.sl-unit-row--selected, .sl-unit-row--selected:hover {
  border: 1.5px solid var(--sl-navy-500); background: var(--sl-navy-50);
}
.sl-unit-row__plot { font-size: var(--sl-text-xs); }
.sl-unit-row__name { display: block; font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); }
.sl-unit-row__meta { display: block; font-size: var(--sl-text-xs); color: var(--muted-foreground); margin-top: 0.1rem; }
.sl-unit-row__cost { text-align: right; white-space: nowrap; }
.sl-unit-row__price {
  display: block; font-size: var(--sl-text-md); font-weight: var(--sl-weight-bold);
  letter-spacing: var(--sl-tracking-snug); font-variant-numeric: tabular-nums;
}
.sl-unit-row__monthly {
  display: block; font-size: var(--sl-text-sm); color: var(--muted-foreground);
  font-variant-numeric: tabular-nums; margin-top: 0.15rem;
}
/* On a phone the two figures sit under the home's name, in its column, so
   the row never grows wider than the screen. */
@media (max-width: 480px) {
  .sl-unit-row { grid-template-columns: 4rem minmax(0, 1fr); gap: var(--sl-space-2) var(--sl-space-3); }
  .sl-unit-row__cost { grid-column: 2; text-align: left; white-space: normal; }
}

/* --- Document card: a file the applicant can open --------------------------- */
.sl-doc-card {
  display: flex; align-items: center; gap: var(--sl-space-3);
  padding: var(--sl-space-3) var(--sl-space-4);
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--sl-radius-md); text-decoration: none; color: inherit;
  transition: box-shadow var(--sl-dur-fast) var(--sl-ease-out), border-color var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-doc-card:hover { box-shadow: var(--sl-shadow-sm); border-color: var(--border-strong); }
.sl-doc-card__icon {
  width: 2.25rem; height: 2.25rem; border-radius: var(--sl-radius-sm); flex: none;
  background: var(--chip); color: var(--chip-foreground);
  display: grid; place-items: center;
}
.sl-doc-card__body { display: flex; flex-direction: column; }
.sl-doc-card__title { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold); }
.sl-doc-card__meta { font-size: var(--sl-text-xs); color: var(--muted-foreground); margin-top: 0.1rem; }
/* A withdrawn version: still openable from the list, its status on the row. */
.sl-doc-card--withdrawn .sl-doc-card__title { color: var(--muted-foreground); font-weight: var(--sl-weight-medium); }
.sl-doc-card--withdrawn .sl-doc-card__icon { opacity: 0.6; }
.sl-doc-card__status {
  margin-left: auto; flex: none; padding-left: var(--sl-space-4);
  font-size: var(--sl-text-xs); color: var(--muted-foreground); white-space: nowrap;
}

/* A document row whose end slot holds a state and an action rather than one
   short word: the version list on a policy's page. Below 480px the slot wraps
   under the title, indented past the icon, so the title and the date keep
   their width. */
.sl-doc-card--actions .sl-doc-card__body { min-width: 0; flex: 1 1 auto; }
@media (max-width: 480px) {
  .sl-doc-card--actions { flex-wrap: wrap; }
  .sl-doc-card--actions .sl-doc-card__status {
    margin-left: 0; padding-left: calc(2.25rem + var(--sl-space-3)); flex-basis: 100%;
  }
}

/* --- Inline list of links, separated by middots ---------------------------- */
/* The policy versions one document printed, under its row on a case page. An
   optional lead word names the list and takes no separator after it. Below
   480px the list stacks one link per line with no separators, so no line
   starts or ends with one. */
.sl-links { display: flex; flex-wrap: wrap; column-gap: var(--sl-space-2); row-gap: 0; }
.sl-links > * + *::before { content: "·"; margin-right: var(--sl-space-2); color: var(--muted-foreground); }
.sl-links > .sl-links__lead + *::before { content: none; }
.sl-links__lead { margin-right: var(--sl-space-1); }
@media (max-width: 480px) {
  .sl-links { flex-direction: column; }
  .sl-links > * + *::before { content: none; }
}

/* --- File control: a button that opens the picker, and what was chosen ------ */
/* The input itself is hidden and the label is the button, because a file input
   cannot be styled and its own text is the browser's. The chosen file's name
   sits beside it. */
.sl-file { display: inline-flex; align-items: center; gap: var(--sl-space-3); flex-wrap: wrap; }

/* --- Locked card: a gated step explaining what unlocks it ------------------- */
.sl-locked-card { display: flex; gap: var(--sl-space-3); align-items: flex-start; }
.sl-locked-card__icon {
  width: 2.375rem; height: 2.375rem; border-radius: 50%; flex: none;
  background: var(--chip); color: var(--chip-foreground);
  display: grid; place-items: center;
}

/* --- Code block: the ask-the-data SQL surface -------------------------------- */
.sl-code-block {
  background: var(--sl-navy-950); color: var(--sl-navy-100);
  border-radius: var(--sl-radius-md); padding: var(--sl-space-4);
  font-family: var(--sl-font-mono); font-size: var(--sl-text-xs);
  line-height: var(--sl-leading-relaxed);
  overflow-x: auto; white-space: pre-wrap;
}

/* --- Empty state: nothing here yet, kindly ----------------------------------- */
.sl-empty-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sl-space-3); padding: var(--sl-space-10) var(--sl-space-6);
  text-align: center;
}
.sl-empty-state__icon {
  width: 3rem; height: 3rem; border-radius: 50%;
  background: var(--muted); color: var(--muted-foreground);
  display: grid; place-items: center;
}
.sl-empty-state__title { font-weight: var(--sl-weight-semibold); font-size: var(--sl-text-base); }
.sl-empty-state__body { font-size: var(--sl-text-sm); color: var(--muted-foreground); line-height: var(--sl-leading-relaxed); margin: 0; max-width: 24rem; }
/* The one way out an empty state offers, where it has one to offer. */
.sl-empty-state__action { margin-top: var(--sl-space-2); }

/* --- Error page: the request could not be served -----------------------------
   Empty state's blunter sibling: the same centred, calm treatment, but it owns
   the whole page rather than a panel, and always offers one way out. Every
   failure (400/403/404/500 and the CSRF page) renders this, so however a
   request fails it fails in the same voice. Note the 500 page loads this
   stylesheet WITHOUT the app shell around it — the handler renders that
   template with an empty context — so this block must stand on its own. */
.sl-error-page {
  flex: 1; display: grid; place-items: center;
  padding: var(--sl-space-12) var(--sl-space-8);
  text-align: center;
}
.sl-error-page__inner { max-width: 26rem; }
/* The reset makes images block-level, so text-align on the parent does not
   centre the mark — it needs the auto side margins itself. */
.sl-error-page__mark { margin: 0 auto var(--sl-space-6); }
.sl-error-page__code { margin: 0 0 var(--sl-space-2); }
/* Balance the headline rather than let a 36px centred line orphan its last word,
   the same treatment the next-step panel's title gets in its narrow well. */
.sl-error-page__title { margin: 0 0 var(--sl-space-3); text-wrap: balance; }
.sl-error-page__body {
  color: var(--muted-foreground); line-height: var(--sl-leading-relaxed);
  margin: 0 0 var(--sl-space-6);
}

/* --- Milestone gate: a tickable professional milestone with its chase state -- */
.sl-gate {
  display: flex; align-items: center; gap: var(--sl-space-3);
  padding: var(--sl-space-3) var(--sl-space-4);
  border: 1px solid var(--border); border-radius: var(--sl-radius-md);
  background: var(--card);
}
.sl-gate--done { background: var(--status-done-bg); border-color: var(--status-done-dot); }
.sl-gate__label { flex: 1; font-size: var(--sl-text-sm); font-weight: var(--sl-weight-medium); }
.sl-gate--done .sl-gate__label { color: var(--status-done-fg); }

/* --- Reservation threshold: whether a development may move its minimum share -
   A hairline section inside the commercial-settings card, the way the form
   sections separate themselves, carrying the state as a plate and the stock as
   a bar of one cell per home. */
.sl-threshold {
  border-top: 1px solid var(--border);
  padding-block-start: var(--sl-space-5);
  margin-block-start: var(--sl-space-6);
}
.sl-threshold .sl-subheading { margin-top: 0; }
/* Whether the figure can be moved, as a plate rather than a line of text. The
   closed state borrows the waiting tone, so it reads as not yet rather than
   wrong, and the open state the done tone. No new colour, no new state. */
.sl-threshold__state {
  display: inline-flex; align-items: center; gap: var(--sl-space-2);
  font-size: var(--sl-text-sm); font-weight: var(--sl-weight-semibold);
  padding: 0.35rem 0.6rem; border-radius: var(--sl-radius-xs);
  margin-block: var(--sl-space-3) var(--sl-space-4);
}
.sl-threshold__state--open   { color: var(--status-done-fg);    background: var(--status-done-bg);    border: 1px solid var(--sl-green-200); }
.sl-threshold__state--locked { color: var(--status-waiting-fg); background: var(--status-waiting-bg); border: 1px solid var(--border-strong); }

/* One cell per home on the development, and the line the development crosses
   to open the figure. Counting homes rather than filling a percentage keeps
   "one more home" a whole cell wide, and puts the destination to the right of
   the fill instead of a limit the fill is spending toward. */
.sl-threshold-bar { max-width: 30rem; }
.sl-threshold-bar__track {
  display: flex; align-items: flex-start; gap: 2px;
  padding-block: 0.4375rem 1.75rem;
}
.sl-threshold-bar__cell {
  flex: 1 1 0; min-width: 0; height: 0.625rem; border-radius: 1px;
  background: var(--sl-canvas-sunken);
}
.sl-threshold-bar__cell:first-child { border-start-start-radius: var(--sl-radius-full); border-end-start-radius: var(--sl-radius-full); }
.sl-threshold-bar__cell:last-child  { border-start-end-radius: var(--sl-radius-full);   border-end-end-radius: var(--sl-radius-full); }
/* A home reserved, exchanged or completed. */
.sl-threshold-bar__cell--taken { background: var(--sl-navy-500); }
/* A home still to reserve before the figure opens: drawn rather than filled,
   so what is missing counts as plainly as what is there. */
.sl-threshold-bar__cell--needed { background: transparent; box-shadow: inset 0 0 0 1.5px var(--status-waiting-dot); }
/* The line, standing in the gap after the last home needed, overhanging the
   cells so it reads as a threshold to reach rather than a cap. */
.sl-threshold-bar__line {
  position: relative; flex: none; width: 2px; height: 1.5rem;
  margin-block-start: -0.4375rem;
  background: var(--foreground); border-radius: 1px;
}
.sl-threshold-bar__line-label {
  position: absolute; top: 1.7rem; left: 50%; transform: translateX(-50%);
  font-size: var(--sl-text-xs); color: var(--muted-foreground); white-space: nowrap;
}
.sl-threshold-bar__legend {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sl-space-4); font-size: var(--sl-text-sm); max-width: 30rem;
}
.sl-threshold-bar__legend-value { font-weight: var(--sl-weight-semibold); }

/* --- Checklist item: a required document and its upload state ---------------- */
.sl-checklist-item {
  display: flex; align-items: center; gap: var(--sl-space-3);
  padding: var(--sl-space-3) 0; border-bottom: 1px solid var(--border);
  /* Some rows carry a second "who" line, some don't — pin every row to the
     two-line height (padding + label + who line) so the list reads evenly. */
  min-height: 4.125rem;
}
.sl-checklist-item:last-child { border-bottom: none; }
.sl-checklist-item__body { flex: 1; }
.sl-checklist-item__label { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-medium); }
.sl-checklist-item__who { font-size: var(--sl-text-xs); color: var(--muted-foreground); margin-top: 0.1rem; }

/* --- QR card: the apply link's scannable result ------------------------------ */
.sl-qr {
  display: grid; place-items: center;
  padding: var(--sl-space-4); border: 1px solid var(--border);
  border-radius: var(--sl-radius-md); background: var(--sl-white);
}
.sl-qr svg { width: 10rem; height: 10rem; }

/* --- Comms digest on the applicant home -------------------------------------- */
.sl-digest { display: grid; gap: var(--sl-space-3); margin-top: var(--sl-space-6); }

/* --- Outstanding answers on a locked declaration ----------------------------- */
/* Each section row is followed by the questions it is still waiting on, so the
   pair has to read as one block: the rows lose the cluster's gap and butt
   straight onto their own list. */
.sl-outstanding-sections { display: grid; gap: 0; }
.sl-outstanding {
  margin: var(--sl-space-2) 0 var(--sl-space-4);
  padding-left: var(--sl-space-5);
  display: grid; gap: var(--sl-space-1);
  font-size: var(--sl-text-sm); color: var(--muted-foreground);
}

/* --- Answer summary: the question, the answer, and the way to change it ------ */
/* The review's cards read as a list of settled facts, so a row is a label and a
   value, not a form field. The negative inline margin lets a row's hover and
   focus states bleed to the card's padding edge without the label losing its
   column. */
.sl-cya__sections { display: grid; gap: var(--sl-space-6); }
.sl-cya__home-name {
  margin: var(--sl-space-3) 0 0;
  font-size: var(--sl-text-base); font-weight: var(--sl-weight-medium);
  line-height: var(--sl-leading-normal);
}
.sl-card__note { margin: var(--sl-space-1) 0 0; font-size: var(--sl-text-sm); color: var(--muted-foreground); }

.sl-answers { margin: 0 calc(-1 * var(--sl-space-2)); }
.sl-answers__row {
  display: grid; grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
  gap: var(--sl-space-1) var(--sl-space-4); align-items: baseline;
  padding: var(--sl-space-3) var(--sl-space-2);
  border-bottom: 1px solid var(--border);
  border-radius: var(--sl-radius-xs);
}
.sl-answers__row:last-child { border-bottom: none; }
.sl-answers__row:hover { background: var(--sl-navy-50); }
.sl-answers dt { font-size: var(--sl-text-sm); font-weight: var(--sl-weight-regular); color: var(--muted-foreground); }
.sl-answers dd { margin: 0; min-width: 0; }
.sl-answers__value {
  font-size: var(--sl-text-base); font-weight: var(--sl-weight-medium);
  color: var(--foreground); overflow-wrap: break-word;
}
.sl-answers__value.sl-muted { color: var(--muted-foreground); }
.sl-answers__hint {
  display: block; font-size: var(--sl-text-sm); font-weight: var(--sl-weight-regular);
  color: var(--muted-foreground); margin-top: var(--sl-space-1);
}
/* The negative block margin buys the 44px touch target without pushing the
   rows apart. */
.sl-answers__change {
  display: inline-flex; align-items: center; min-height: 2.75rem;
  margin-block: calc(-1 * var(--sl-space-3)); margin-inline-start: var(--sl-space-3);
  font-size: var(--sl-text-sm); font-weight: var(--sl-weight-regular); color: var(--primary);
  text-decoration: underline; text-underline-offset: 0.2em; white-space: nowrap;
}
.sl-card__body > h3.sl-subheading { display: block; margin: var(--sl-space-6) 0 var(--sl-space-2); }
@media (max-width: 480px) {
  .sl-answers__row {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sl-space-1) 0;
    padding-block: var(--sl-space-2);
    padding-inline: var(--sl-space-1);
  }
  .sl-answers dt { line-height: var(--sl-leading-normal); }
  /* The 44px touch target is made with padding here, not a negative margin:
     on this narrower row the negative margin pushed the link box (and its
     focus ring) out through the label above and the divider below. */
  .sl-answers__change { margin-block: 0; padding-block: var(--sl-space-2); }
  .sl-answers { margin-inline: calc(-1 * var(--sl-space-1)); }
}

/* --- The application form's sections, opened up on the rung that owns them --- */
.sl-sections {
  max-width: 46rem;
  margin-top: var(--sl-space-4); padding-top: var(--sl-space-4);
  border-top: 1px dashed var(--border);
}
.sl-tasklist { list-style: none; margin: 0; padding: 0; }
.sl-tasklist > li + li { border-top: 1px solid var(--border); }
.sl-task {
  display: grid; grid-template-columns: minmax(0, 1fr) auto 1.25rem; align-items: center;
  column-gap: var(--sl-space-3);
  padding: var(--sl-space-4) var(--sl-space-3);
  margin-inline: calc(var(--sl-space-3) * -1);
  border-radius: var(--sl-radius-md);
  text-decoration: none; color: inherit;
  transition: background var(--sl-dur-fast) var(--sl-ease-out);
}
a.sl-task:hover { background: var(--accent); text-decoration: none; }
a.sl-task:hover .sl-task__name { text-decoration: underline; text-underline-offset: 0.2em; }
a.sl-task:hover .sl-task__arrow { transform: translateX(2px); }
.sl-task__body { display: block; min-width: 0; }
.sl-task__name { display: block; font-size: var(--sl-text-base); font-weight: var(--sl-weight-semibold); color: var(--primary); }
.sl-task__what { display: block; font-size: var(--sl-text-sm); color: var(--muted-foreground); margin-top: 0.1rem; }
.sl-task__status { justify-self: end; }
/* Link rows only. The closed row has no arrow, and the missing arrow is the
   affordance statement: the arrow is how this list says "this opens". */
.sl-task__arrow {
  justify-self: end; color: var(--muted-foreground);
  font-size: var(--sl-text-md); line-height: 1;
  transition: transform var(--sl-dur-fast) var(--sl-ease-out);
}
.sl-task--locked .sl-task__name { color: var(--muted-foreground); }
@media (max-width: 480px) {
  /* The status drops under the row's own text so the tap target keeps the full
     width of the column. */
  .sl-task { grid-template-columns: minmax(0, 1fr) 1.25rem; row-gap: var(--sl-space-2); }
  .sl-task__body { grid-column: 1 / -1; }
  .sl-task__status { justify-self: start; grid-column: 1; }
  .sl-task__arrow { grid-column: 2; }
}

/* --- The other applicant, inside the rung the two of them share --------------
   Rung 2 is one joint gate, not two parallel ones, so the second applicant sits
   inside it rather than on a card of their own. The block is built as the
   inverse of a task row: a bordered inset (the same shape the rung already uses
   for its quiet rows), a body-ink name instead of a navy link, no hover and no
   arrow. Nothing here opens. */
.sl-coapplicant { margin-top: var(--sl-space-5); margin-bottom: var(--sl-space-2); }
.sl-coapplicant .sl-subheading { margin: 0 0 var(--sl-space-2); }
/* A bordered inset, never a filled well: every fill in this system carries a
   state meaning, and this block is not claiming a state. */
.sl-coapplicant__panel {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--sl-space-3); row-gap: var(--sl-space-1);
  align-items: start;
  /* Narrower than the section rows above, so its right edge falls well short of
     the column their status pills stand in. */
  max-width: 34rem;
  padding: var(--sl-space-4);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--sl-radius-md);
}
/* The badge hangs off the name's own line, not the centre of the block. On a
   phone the name and the status pill wrap onto two lines, and a centred badge
   then lands level with the pill instead of the person it belongs to. The
   -0.25rem is half the difference between the 2rem badge and the 1.5rem line
   box, so the badge and the name share a centreline at every width. */
.sl-coapplicant__avatar {
  grid-column: 1; grid-row: 1 / span 2;
  align-self: start; margin-top: -0.25rem;
}
/* Their status rides beside their name, not out in the right-hand column where
   the six section pills live, so it can never be scanned as a seventh section. */
.sl-coapplicant__head {
  grid-column: 2; display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sl-space-1) var(--sl-space-3);
}
.sl-coapplicant__name {
  font-size: var(--sl-text-base); font-weight: var(--sl-weight-semibold);
  color: var(--foreground);
}
.sl-coapplicant__count { grid-column: 2; font-size: var(--sl-text-sm); color: var(--muted-foreground); }
.sl-coapplicant__note {
  grid-column: 1 / -1;
  margin-top: var(--sl-space-3); padding-top: var(--sl-space-3);
  border-top: 1px solid var(--border);
  font-size: var(--sl-text-sm); color: var(--muted-foreground);
  line-height: var(--sl-leading-normal);
}
.sl-coapplicant__note strong { color: var(--foreground); font-weight: var(--sl-weight-semibold); }
@media (max-width: 480px) {
  /* The pill drops under the name; name, pill and count keep one left edge. */
  .sl-coapplicant__panel { padding: var(--sl-space-3); }
}
