/* Public business register — institutional styling.
   ---------------------------------------------------------------------------
   Brand family: civic / government (docs/vl/public-search/brand.md).
   Calibrated against GOV.UK (structure, focus mechanics, tag construction),
   Companies House (a statutory register states its facts, it does not decorate
   them), and the two-band government masthead that ACRA/BizFile and the New
   Zealand Companies Register also use — an organisation band above a service
   band, so the reader learns WHOSE register this is before reading anything.
   BIPA's orange is the seam between the two, and the only saturated accent.

   The organisation band carries BIPA's REAL logo (static/brand/bipa-mark.png)
   on the white ground that lockup is drawn for, with the statutory name beside
   it as live text. Nothing asserts a seal, an Act number or a ministry — none
   are established in this repository. See templates/search/base.html.

   Constraints this file is bound by, none of them aesthetic:
     - Mobile first, on a cheap phone over a slow Namibian connection. No web
       fonts, ONE image (3.0 KB, the logo), no layout shift. The display face
       is a SYSTEM serif — Georgia on Apple/Windows, Noto Serif on Android — so
       the institutional voice costs zero bytes and zero requests.
     - Works with JavaScript disabled. HTMX is progressive enhancement.
     - Every colour pair carrying text is >= 4.5:1; interactive borders and the
       non-text data fills are >= 3:1. Verified, not eyeballed — the ratios are
       recorded beside each token below.
     - No gradients, no icons, no emoji, no shadows-as-decoration, no motion
       beyond an instant state change.
   --------------------------------------------------------------------------- */

:root {
  /* Ink and ground -------------------------------------------------------- */
  /* Sampled from BIPA's own lockup: the wordmark's black is #15171A (97,235
     px of it), so the register's ink IS the brand's ink rather than a near
     miss. 18.0:1 on white. */
  --color-text: #15171a;            /* 18.0:1 on white */
  --color-muted: #52585c;           /*  7.2:1 on white, 6.6:1 on sunken/paper */
  --color-bg: #ffffff;
  --color-sunken: #f3f5f6;

  /* "Paper" — a warm off-white for the regions that frame the page (the search
     hero, a record's identity header). Warm rather than grey so the page reads
     as a printed document rather than as a disabled form. Ink on it is 16.4:1,
     muted 6.6:1, link 7.7:1. */
  --color-paper: #f7f5f2;

  /* Ink used as a GROUND, not just as text: the organisation band, the
     statistics panel and the footer. This is what gives the page regions a
     reader can orient in without a single decorative device. */
  --color-ink-rule: #3d4348;        /* hairline on an ink ground (decorative) */
  --color-on-dark: #ffffff;         /* 17.8:1 on ink */
  --color-on-dark-muted: #c2c9ce;   /* 10.6:1 on ink */
  --color-on-dark-link: #9ccbf0;    /* 10.4:1 on ink */
  --color-on-dark-negative: #f3a6a1;/*  9.1:1 on ink */
  --color-on-dark-positive: #6fc3a0;/*  8.5:1 on ink */

  /* Rules. The decorative divider is deliberately light; anything that bounds
     an interactive control uses --color-border-strong (4.95:1). */
  --color-border: #c9ced1;
  --color-border-strong: #6b7175;

  /* Links keep the register's existing deep blue (8.4:1) — a conventional,
     highly legible link colour that does not compete with the brand accent. */
  --color-link: #0b4f8a;
  --color-link-hover: #073760;

  /* BIPA accent — ONE orange, measured off the authority's own logo rather
     than approximated. Decoding static/brand/bipa-logo-linear.png, 94.9% of
     its orange pixels (59,596 of 62,831) are exactly #F79448: hue 26.1deg,
     saturation 91.6%. The file previously carried three unrelated oranges
     (#f26a1b, #FF993D, #b8450c) at three different hues; the two below are now
     the SAME hue and saturation as the band, darkened until they carry text.

     #F79448 is 2.26:1 on white, so it can never be a text colour or a UI
     boundary — it is the solid seam between the two masthead bands and
     nothing else. That is a deliberate ceiling, not an oversight. */
  --color-brand-band: #f79448;      /* the real BIPA orange; band only, never text */
  --color-brand: #b05108;           /* 5.2:1 — carries white text (buttons) */
  --color-brand-deep: #893f06;      /* 7.6:1 — brand as a text colour, and hover */

  /* Focus: two channels, per GOV.UK. Yellow carries contrast on dark grounds
     (12.4:1 on ink), the black bar carries it on light ones, so focus is
     visible anywhere on a page that now has both. */
  --color-focus: #ffd400;
  --color-focus-ink: #16181a;

  /* Status tints — dark shade on light tint, so the pairs stay legible in
     greyscale and in print. Ratios: 8.9 / 9.4 / 7.3 / 9.8 : 1. */
  --color-positive-bg: #d6e8df;
  --color-positive-text: #08432c;
  --color-negative-bg: #f7dcdc;
  --color-negative-text: #6b1414;
  --color-warning-bg: #fbeccd;
  --color-warning-text: #6b4506;
  --color-neutral-bg: #e6eaec;
  --color-neutral-text: #31383d;
  --color-guidance-bg: #fdf4e0;     /* ink on this is 16.3:1 */

  /* The compliance bar sits on the ink panel, so its fills are lightened until
     they clear 3:1 against that ground (3.4:1 and 4.4:1) — the non-text
     contrast minimum. The dark table shades used on white would vanish. */
  --color-bar-negative: #c0403a;
  --color-bar-positive: #1f8f66;

  /* Type ------------------------------------------------------------------ */
  /* Body: system sans, nothing to download. */
  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif;
  /* Display: system SERIF, used for the organisation mark and page headings
     only. It is what makes this read as a document of record rather than as an
     app, and every platform already has one. Figures are deliberately NOT set
     in it — Georgia's numerals are old-style, which is wrong for a statistic. */
  --font-display: Georgia, "Times New Roman", "Noto Serif", serif;

  /* Spacing — 5px base, as GOV.UK, extended at the top end because the regions
     this page is now built from need room to read as regions. */
  --space-1: 0.3125rem;
  --space-2: 0.625rem;
  --space-3: 0.9375rem;
  --space-4: 1.25rem;
  --space-5: 1.875rem;
  --space-6: 2.5rem;
  --space-7: 3.75rem;
  --space-8: 5rem;

  /* Width. The shell is wide enough for five-column register tables; prose is
     separately capped near 75 characters, which is the readable measure. */
  --shell: 64rem;
  --measure: 42rem;

  --radius: 3px;
}

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

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--color-text);
  background: var(--color-bg);
  line-height: 1.55;
  /* 18px. GOV.UK's research settled on a large body size that does NOT shrink
     on mobile; this is a shade under theirs and still well above the 16px
     default, which matters for older readers on small screens. */
  font-size: 1.125rem;
}

/* Every full-bleed region carries its own ground and holds its content in one
   of these. One rule, so a new region cannot drift out of alignment. */
.shell {
  max-width: var(--shell);
  margin: 0 auto;
  padding-left: var(--space-4);
  padding-right: var(--space-4);
}

/* --- typography ---------------------------------------------------------- */

h1,
h2,
h3 {
  line-height: 1.2;
  text-wrap: balance;
  margin: 0 0 var(--space-3);
}

/* The display face is scoped to the headings that carry the page's voice.
   Small headings inside data (h3, table captions, field labels) stay in the
   body sans, where a serif would only cost legibility at 15-19px. */
h1,
h2 {
  font-family: var(--font-display);
  font-weight: 700;
}

h1 {
  /* Decisive scale contrast: ~3x the body size at desktop. The previous 2.25rem
     ceiling put the page heading barely above a bold paragraph. */
  font-size: clamp(2.125rem, 1.55rem + 2.7vw, 3.25rem);
  letter-spacing: -0.015em;
  margin-bottom: var(--space-4);
}

h2 {
  font-size: clamp(1.4375rem, 1.2rem + 0.95vw, 1.9375rem);
  letter-spacing: -0.01em;
  margin-top: var(--space-7);
}

h3 {
  font-size: 1.125rem;
  font-weight: 700;
  margin-top: var(--space-5);
}

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

/* Prose stays near the readable measure (~75 characters, per GOV.UK's line
   length guidance); tables and result lists may use the full shell. */
.main-body > p,
.main-body > h1,
.main-body > h2,
section > p,
.guidance p,
.state,
.provenance,
.search-examples,
.result-count {
  max-width: var(--measure);
}

/* A whole document of prose — the privacy notice — is capped as one block, so
   a paragraph added later inherits the measure instead of running the full
   1024px shell. */
.prose {
  max-width: var(--measure);
}

a {
  color: var(--color-link);
  text-underline-offset: 0.15em;
}

a:hover {
  color: var(--color-link-hover);
}

/* Focus: yellow ground plus a black underline bar for text links, and a
   yellow/black double ring for controls. The transparent outline is what keeps
   focus visible in Windows High Contrast Mode, which discards box-shadows.
   Because the page now has ink grounds as well as white ones, this pair is
   what guarantees focus is visible on both — 12.4:1 yellow-on-ink. */
a:focus-visible {
  outline: 3px solid transparent;
  color: var(--color-focus-ink);
  background: var(--color-focus);
  box-shadow:
    0 -2px var(--color-focus),
    0 4px var(--color-focus-ink);
  text-decoration: none;
}

input:focus-visible,
button:focus-visible,
summary:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 0;
  box-shadow: inset 0 0 0 2px var(--color-focus-ink);
}

/* Standalone action links — the ones that are a control in their own right
   rather than a word inside a sentence — need a tappable target. WCAG 2.2
   SC 2.5.8 asks for 24x24 CSS px; these were 18px tall. Links inside running
   prose are exempt from that rule and are deliberately left alone, so the
   measure of a paragraph is not disturbed. */
.back-link,
.search-clear a,
.state-actions a,
.result-next-step a,
.footer-links a,
.footer-staff a {
  display: inline-block;
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: auto;
  background: var(--color-bg);
  padding: var(--space-2) var(--space-3);
  border: 2px solid var(--color-focus-ink);
  z-index: 20;
}

.skip-link:focus {
  left: var(--space-3);
  top: var(--space-3);
}

/* --- masthead ------------------------------------------------------------ */

/* ONE bar, closed by the BIPA orange seam: the authority's lockup at the left,
   the SERVICE NAME at the right, vertically centred on one ground. It was two
   full-width bands; the second carried one line and no navigation, so it read
   as vertical height rather than as structure. Measured: the masthead went
   from 216px to 106px at 1280 and from 198px to 137px at 375.

   THE GROUND IS FORCED, NOT CHOSEN — one bar has one ground and the logo picks
   it. The "bipa" wordmark is black on transparent, so the bar is white and the
   service name is ink on it (18.0:1) rather than reversed out. The page keeps
   its region structure regardless: white bar, orange seam, paper hero, and the
   ink grounds it lost at the top it still has at the statistics panel and the
   footer. See templates/search/base.html for the rest of the reasoning. */

.masthead-bar {
  background: var(--color-bg);
  /* The single saturated brand gesture on the page, doing structural work as
     the edge that closes the masthead. Decorative by construction: 2.26:1 on
     white means it may never carry text or bound a control. */
  border-bottom: 4px solid var(--color-brand-band);
}

/* Wraps rather than shrinks. Below the measured 730px fitting point the
   service name drops to its own line under the lockup — a deliberate stack,
   not a broken row: both items keep the bar's left margin, the gap between
   them is the bar's own rhythm, and the service name is still the largest text
   in the region. Nothing is hidden and nothing is reordered at any width. */
.masthead-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-5);
  padding-top: var(--space-3);
  padding-bottom: var(--space-3);
}

.masthead-org {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  min-width: 0;
}

/* Sized by HEIGHT so the bar's rhythm does not depend on the file's aspect
   ratio; the intrinsic width/height attributes in the markup reserve the box,
   a logo being the classic masthead layout shift — and, at 375px, the classic
   cause of horizontal overflow. */
.org-logo {
  display: block;
  height: 3.75rem;
  width: auto;
  flex: 0 0 auto;
}

/* The CAPTION to the mark, not a competitor to the service name: small,
   uppercase, muted (7.2:1 on white). Who runs this is a quieter question than
   which service you are on, and the type sizes say so — 15-16px against the
   service name's 24-32px.

   The hairline between the mark and the statutory name is how an institutional
   lockup is built — and it is how BIPA's own horizontal lockup is built too.
   But it only works while the two sit on one line: on a phone the name wraps
   beneath the mark and the rule is orphaned against the left margin, so it is
   added at the width where the lockup actually holds together. */
.org-name {
  color: var(--color-muted);
  font-size: 0.9375rem;
  line-height: 1.35;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  max-width: 22ch;
}

/* The service name — what the reader came for, and the largest text in the
   bar. Right-alignment places it, it does not rank it: rank is carried by size
   (2rem against the organisation caption's 1rem), by the display serif, and by
   the full ink. */
.site-title {
  display: inline-block;
  font-family: var(--font-display);
  /* Flat across the phone range, then steep. Measured rather than guessed: on
     the old curve the name reached 28px by 768, which with the lockup is 20px
     wider than the shell — so a tablet wrapped to a stack and the bar was 153px
     tall. Held at 24px the pair fits from 730px, and 768 is 106px. */
  font-size: clamp(1.5rem, 0.6rem + 1.9vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.15;
  text-decoration: none;
  color: var(--color-text);
  max-width: 100%;
}

.site-title:hover {
  color: var(--color-text);
  text-decoration: underline;
}

@media (min-width: 34em) {
  .org-logo {
    height: 4.5rem;
  }

  .org-name {
    padding-left: var(--space-4);
    border-left: 1px solid var(--color-border);
    font-size: 1rem;
    /* Narrow enough that the caption and the service name fit the bar together
       from 600px up. It sets to three lines here and drops to two once there is
       room — three lines beside a 72px mark is a lockup; three lines beside an
       empty right half, which is what 26ch gave at 1280, is a mistake. */
    max-width: 20ch;
  }

}

/* Only once the two actually sit side by side — measured at 730px, so this is
   the first standard step above it. On the stacked layout a right rag would
   pull the service name away from the lockup's left margin and make the reflow
   read as a broken row rather than as a deliberate stack. */
@media (min-width: 48em) {
  .site-title {
    text-align: right;
  }
}

@media (min-width: 60em) {
  .org-name {
    /* Two lines, as BIPA's own horizontal lockup sets it. */
    max-width: 26ch;
  }
}

/* --- hero region --------------------------------------------------------- */

/* The band carrying the page's primary matter: the search on the search page,
   a record's identity on an entity page. Paper ground, full width, real
   vertical room — a citizen on a phone meets one obvious thing to do. It is a
   base-template region, not a search-page component, so the two cannot drift. */
.hero {
  background: var(--color-paper);
  border-bottom: 1px solid var(--color-border);
  padding-top: var(--space-6);
  padding-bottom: var(--space-6);
}

/* Not capped to the prose measure: a heading is not prose, and at 42rem
   "Search the business register" broke over two lines on a 1280 screen while
   the region around it stayed empty. A character cap keeps a long entity name
   from running the full shell without forcing a short heading to wrap. */
/* The heading sits close to whatever qualifies it; the air before the primary
   action is put on the action itself (below), so a lede line between them is
   attached to the heading rather than floating between two 30px gaps. A record
   page's heading is not affected — `.record-head h1` sets its own. */
.hero h1 {
  margin-bottom: var(--space-3);
  max-width: 32ch;
}

/* The reassurance that used to be the masthead's second band, relocated to the
   action it is about. Set between the heading and the body scale so it reads
   as the heading's qualifier and not as the page's first paragraph. 6.6:1 on
   the paper ground. */
.hero-lede {
  margin: 0;
  color: var(--color-muted);
  font-size: 1.0625rem;
  max-width: var(--measure);
}

.hero .search-form {
  margin-top: var(--space-5);
}

/* <main> carries no width: each region inside it (the hero, the body) sets its
   own ground and holds its content in a .shell. See base.html for why the hero
   is inside main rather than above it. */
main {
  min-height: 40vh;
}

.main-body {
  padding-top: var(--space-6);
  padding-bottom: var(--space-8);
}

/* --- footer -------------------------------------------------------------- */

/* Ink ground, so the page ends on a deliberate edge rather than trailing off
   into white. The authority is named here in full, as a printed statutory
   document repeats its issuer — but as TEXT, not a second lockup: the logo's
   wordmark is black and would vanish on this ground, and inventing a
   reversed-out version of the client's asset is not ours to do. */
.site-footer {
  background: var(--color-text);
  color: var(--color-on-dark-muted);
  font-size: 0.9375rem;
  padding-top: var(--space-6);
  padding-bottom: var(--space-7);
}

.site-footer-inner {
  display: grid;
  gap: var(--space-5);
}

.site-footer a {
  color: var(--color-on-dark-link);
}

.site-footer a:hover {
  color: var(--color-on-dark);
}

.footer-org {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-ink-rule);
}

.footer-org-name {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--color-on-dark);
}

.site-footer p {
  max-width: var(--measure);
}

.footer-links {
  margin-bottom: 0;
}

/* --- staff sign-in / footer navigation ------------------------------------ */

/* Deliberately the quietest region in the footer, and deliberately last. A
   citizen must never form the impression that searching the register needs an
   account — the whole point of the service is that it is open. Smaller than the
   surrounding text and behind a rule. Shared byte-for-byte between the public
   register and /office/ via templates/search/_footer_staff_nav.html, which
   both base.html templates include — see that partial for the routing rules. */
.footer-staff {
  margin: var(--space-4) 0 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-ink-rule);
  font-size: 0.875rem;
  color: var(--color-on-dark-muted);
}

.footer-staff p {
  margin-bottom: 0;
}

/* Signed in, the same strip states WHO — otherwise an officer who wandered onto
   the public page has no way to tell whether they still hold a session. */
.footer-staff strong {
  color: var(--color-on-dark);
}

.linkish {
  background: none;
  border: 0;
  padding: 0.25rem 0;
  font: inherit;
  color: var(--color-link);
  text-decoration: underline;
  text-underline-offset: 0.15em;
  cursor: pointer;
}

.linkish:hover {
  color: var(--color-link-hover);
}

/* Buttons, not a run of inline links: every footer destination (Staff sign-in,
   Back office, Sign out, Django admin) reads as an obviously interactive
   control, but the group stays subordinate to the page — outlined rather than
   filled, sized down from the search form's button, and drawn from tokens
   already in use on this ground (no new accent, per brand.md). A footer is not
   a call to action.

   Sign-out is a <form>, never a plain link (a GET logout is a one-pixel image
   away from firing on any page a signed-in officer visits) — its submit
   button gets the identical class so the row reads as one group of controls
   rather than three links and an odd button out. */
.footer-nav-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.footer-nav-signout {
  margin: 0;
}

/* Contrast, computed: white text (17.96:1) / the muted on-dark border
   (10.72:1) against the footer's ink ground; on hover, the border and text
   stay white (10.02:1) against the ink-rule fill used elsewhere as this
   ground's own hairline. All comfortably clear 4.5:1 text / 3:1 non-text. */
.footer-staff .footer-nav-button {
  display: inline-flex;
  align-items: center;
  /* WCAG 2.2 SC 2.5.8 wants a 24x24 CSS px target; the padding clears it even
     at this reduced footer type size. */
  min-height: 1.75rem;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--color-on-dark-muted);
  border-radius: var(--radius);
  background: transparent;
  color: var(--color-on-dark);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
}

.footer-staff .footer-nav-button:hover {
  border-color: var(--color-on-dark);
  background: var(--color-ink-rule);
  color: var(--color-on-dark);
}

/* The button's own `color`/`background` above are more specific than the
   sitewide `a:focus-visible` rule (two classes beat one class + one element),
   which would otherwise silently win the specificity war and leave a focused
   button's text white-on-white against the focus yellow. Restated here at
   matching specificity so a footer button gets the exact same visible focus
   as every other link and control on the page. */
.footer-staff .footer-nav-button:focus-visible {
  outline: 3px solid transparent;
  border-color: var(--color-focus-ink);
  color: var(--color-focus-ink);
  background: var(--color-focus);
  box-shadow:
    0 -2px var(--color-focus),
    0 4px var(--color-focus-ink);
  text-decoration: none;
}

/* The one control an anonymous visitor sees. Same shape as every other
   footer button — still obviously interactive — but the lighter weight keeps
   it from reading as a bigger action than the search field above it. */
.footer-nav-button-quiet {
  font-weight: 400;
}

.footer-nav-hint {
  margin-top: var(--space-2);
  font-size: 0.875rem;
}

/* --- search form --------------------------------------------------------- */

/* The primary action, and now sized like one: a 56px field at 19px, not a
   default input. Both controls share a height so the pair reads as one
   instrument. */
.search-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  /* Wider than the prose measure on purpose. This is the page's primary action
     and a register search is often a long registration number; a field that
     stops at the measure reads as a secondary control beside a 52px heading. */
  max-width: 46rem;
}

.search-form label {
  font-weight: 700;
  display: block;
  margin-bottom: var(--space-2);
  font-size: 1.0625rem;
}

.search-form input[type="search"] {
  font: inherit;
  font-size: 1.1875rem;
  /* 2px ink border, per GOV.UK's form-element treatment — a 1px light-grey
     input border is the commonest way a government form fails 1.4.11. It is
     the full ink here rather than the mid grey: on the paper ground the field
     has to be the most positive shape in the region. */
  border: 2px solid var(--color-text);
  border-radius: var(--radius);
  padding: 0.7rem 0.85rem;
  width: 100%;
  min-height: 3.5rem;
  background: var(--color-bg);
  color: var(--color-text);
}

.search-form button {
  align-self: flex-start;
  font: inherit;
  font-size: 1.0625rem;
  font-weight: 700;
  padding: 0.7rem 2rem;
  min-height: 3.5rem;
  border: 2px solid var(--color-brand);
  background: var(--color-brand);
  color: #fff;
  border-radius: var(--radius);
  cursor: pointer;
}

.search-form button:hover {
  background: var(--color-brand-deep);
  border-color: var(--color-brand-deep);
}

/* Po2 — a way to clear the search and get back to the landing state. A plain
   link, so it works with JavaScript off. */
.search-clear {
  font-size: 0.9375rem;
  margin-bottom: var(--space-3);
}

.search-examples {
  color: var(--color-muted);
  font-size: 0.9375rem;
  margin-bottom: 0;
}

.search-examples code {
  font-size: 0.9em;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0.05em 0.35em;
  white-space: nowrap;
}

.htmx-indicator {
  opacity: 0;
  font-size: 0.9375rem;
  color: var(--color-muted);
  transition: opacity 150ms linear;
}

.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .htmx-indicator {
    transition: none;
  }
}

/* --- result states -------------------------------------------------------- */

/* States are bordered blocks with a weighted left edge rather than tinted
   cards: the edge survives greyscale and printing, where a pale tint does not. */
.state {
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-left: 5px solid var(--color-border-strong);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--color-sunken);
  margin-bottom: var(--space-4);
}

/* Every state block reads as ink on a tint, with the colour carried by the left
   bar rather than by the body text. Tinted text on a tinted ground was legible
   but tiring over a long paragraph, and it made the important states the
   HARDEST to read — the ambiguity notice and the guidance aside are the two
   longest passages on the site. Keeping one rule here also stops the badge
   palette and the block palette drifting apart. */
.state-empty,
.state-truncated {
  color: var(--color-text);
}

.state-error,
.state-stale-cursor {
  background: var(--color-negative-bg);
  border-color: var(--color-negative-text);
  border-left-color: var(--color-negative-text);
  color: var(--color-text);
}

.state-ambiguous {
  background: var(--color-warning-bg);
  border-color: var(--color-warning-text);
  border-left-color: var(--color-warning-text);
  color: var(--color-text);
}

.state-actions {
  margin-bottom: var(--space-4);
}

.result-count {
  color: var(--color-muted);
  font-size: 0.9375rem;
  margin-bottom: var(--space-2);
}

.provenance {
  font-size: 0.9375rem;
  color: var(--color-muted);
  border-left: 3px solid var(--color-border);
  padding-left: var(--space-3);
  margin-bottom: var(--space-5);
}

.provenance strong {
  color: var(--color-text);
}

/* --- results list --------------------------------------------------------- */

/* A hairline-separated list, not a grid of bordered cards: this is a register
   of records, and Companies House's plain result list is the peer precedent.
   The top rule is now the full ink weight, so the list starts on a deliberate
   edge instead of fading in. */
.result-list {
  list-style: none;
  margin: 0 0 var(--space-6);
  padding: 0;
  border-top: 3px solid var(--color-text);
}

.result-card {
  border-bottom: 1px solid var(--color-border);
  padding: var(--space-5) 0;
}

/* Deliberately NOT the display serif, unlike the headings around it. An entity
   name in a result list is a data value, and it is frequently long, upper-case
   and full of abbreviations — the exact material a serif reads worst at. The
   serif is reserved for the page's own voice. */
.result-name {
  display: inline-block;
  font-size: 1.3125rem;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.01em;
  margin-bottom: var(--space-3);
}

.result-meta {
  margin: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3) var(--space-5);
}

.result-meta > div {
  display: grid;
  /* Label above value on a phone — the previous side-by-side flex row could not
     fit a long compliance label and pushed the whole page into a horizontal
     scroll at 375px and 768px. */
  grid-template-columns: 1fr;
  gap: 0.15rem;
  min-width: 0;
}

/* Field labels across the register: one treatment, so a result card and a
   record header state their fields in the same voice. */
.result-meta dt,
.record-summary dt {
  color: var(--color-muted);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.result-meta dd,
.record-summary dd {
  margin: 0;
  min-width: 0;
  overflow-wrap: break-word;
}

.result-next-step {
  margin: var(--space-3) 0 0;
  font-size: 0.9375rem;
}

.matched-on {
  color: var(--color-muted);
  font-size: 0.875rem;
  margin: var(--space-3) 0 0;
}

/* --- compliance and status badges ---------------------------------------- */

/* The most consequential element on the site: it states a legal position about
   a named business. Four things carry that, in order of reliability —
     1. the full sentence inside the badge (it never abbreviates to a word);
     2. the shape marker, which differs per state and survives greyscale;
     3. the left bar's weight;
     4. colour, last.
   Square-ish corners, not pills: GOV.UK user research found saturated pills
   are read as buttons and clicked. This must not look actionable. */
.badge {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45em;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.35;
  padding: 0.3rem 0.65rem;
  border-radius: var(--radius);
  border-left: 4px solid currentColor;
  /* Must wrap. Fixed the horizontal page overflow caused by nowrap. */
  white-space: normal;
  overflow-wrap: break-word;
  max-width: 100%;
}

/* Shape marker — redundant, non-colour encoding of the state. Decorative to
   assistive tech (the label already says it), meaningful in print and to a
   colour-blind reader. */
/* Sits on the FIRST line's baseline, not centred on the block: a compliance
   label wraps to two lines on a phone, and a centred marker floats away from
   the words it qualifies. */
.badge::before {
  content: "";
  flex: 0 0 auto;
  width: 0.6em;
  height: 0.6em;
  transform: translateY(-0.02em);
  background: currentColor;
}

/* compliant — solid disc */
.badge-positive {
  background: var(--color-positive-bg);
  color: var(--color-positive-text);
}

.badge-positive::before {
  border-radius: 50%;
}

/* not compliant — solid square, the visually heaviest marker */
.badge-negative {
  background: var(--color-negative-bg);
  color: var(--color-negative-text);
}

.badge-negative::before {
  border-radius: 0;
}

/* caution (e.g. on an inactive list) — solid diamond */
.badge-warning {
  background: var(--color-warning-bg);
  color: var(--color-warning-text);
}

.badge-warning::before {
  border-radius: 1px;
  transform: translateY(-0.02em) rotate(45deg);
  width: 0.55em;
  height: 0.55em;
}

/* not yet due / unknown — HOLLOW ring. Deliberately the only unfilled marker:
   "not yet due" and "not on record" are not claims of good standing, and must
   never read as a tick. */
.badge-neutral {
  background: var(--color-neutral-bg);
  color: var(--color-neutral-text);
}

.badge-neutral::before {
  background: transparent;
  border: 2px solid currentColor;
  border-radius: 50%;
}

/* --- register statistics (landing page) ---------------------------------- */

/* Reversed out on ink: a published statistical panel, which is what these
   figures are. 140,564 entities and 58.6% non-compliant are the most arresting
   facts this service holds and on white they were a paragraph with a big number
   in it. Contained rather than full-bleed because `width: 100vw` overflows by
   the scrollbar width — the exact defect class the last pass was fixing. */
.stats-panel {
  background: var(--color-text);
  color: var(--color-on-dark);
  border-radius: var(--radius);
  padding: var(--space-5) var(--space-4) var(--space-6);
  margin-bottom: var(--space-6);
}

.stats-panel h2 {
  margin-top: 0;
  margin-bottom: var(--space-2);
  color: var(--color-on-dark);
}

.stats-panel h3 {
  color: var(--color-on-dark);
  font-size: 0.875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-top: 0;
  margin-bottom: var(--space-3);
}

.stats-panel .scope-caveat,
.stats-panel caption,
.stats-panel .stat-total-label,
.stats-panel .compliance-figure-label,
.stats-panel .stat-status-caveat {
  color: var(--color-on-dark-muted);
}

.scope-caveat {
  font-size: 0.9375rem;
  max-width: var(--measure);
  margin-bottom: 0;
}

.stats-panel .scope-caveat strong {
  color: var(--color-on-dark);
}

/* The headline figure. The numbers are the most compelling thing on this page,
   so they are given room and weight — but no count-up animation: these are
   legal facts, not a marketing metric. Set in the body sans, not the display
   serif: a system serif's figures are old-style, which is wrong for a count. */
.stat-total {
  margin: var(--space-6) 0 var(--space-5);
  padding-bottom: var(--space-5);
  border-bottom: 1px solid var(--color-ink-rule);
}

.stat-number {
  display: block;
  font-size: clamp(3rem, 2rem + 5.2vw, 5rem);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
}

.stat-total-label {
  display: block;
  font-size: 1rem;
  margin-top: var(--space-3);
}

.stat-bo-compliance {
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-ink-rule);
}

/* A plain proportional bar for the compliance split. Solid fills, no gradient;
   aria-hidden because the figures beside it are the accessible statement. Both
   fills clear 3:1 against the ink ground. */
.compliance-bar {
  display: flex;
  height: 1rem;
  margin: 0 0 var(--space-5);
  border-radius: 1px;
  overflow: hidden;
  max-width: var(--measure);
}

.compliance-bar-negative {
  background: var(--color-bar-negative);
}

/* Takes whatever the non-compliant share leaves, so only ONE width in this
   component is data and needs an inline style. */
.compliance-bar-positive {
  background: var(--color-bar-positive);
  flex: 1;
}

.compliance-figures {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-4);
  max-width: var(--measure);
}

/* The two halves of the split are given the bar's own colours so the reader can
   tie a figure to a segment without a legend. Both clear 4.5:1 on ink. */
.compliance-figures li {
  border-left: 4px solid currentColor;
  padding-left: var(--space-3);
}

.compliance-figures li:first-child {
  color: var(--color-on-dark-negative);
}

.compliance-figures li:last-child {
  color: var(--color-on-dark-positive);
}

.compliance-figure-value {
  display: block;
  font-size: clamp(1.875rem, 1.5rem + 1.5vw, 2.5rem);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
}

.compliance-figure-label {
  display: block;
  font-size: 0.9375rem;
  margin-top: var(--space-1);
}

.stat-status-caveat {
  font-size: 0.9375rem;
  margin-top: var(--space-6);
  margin-bottom: 0;
  max-width: var(--measure);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-ink-rule);
}

/* The by-type table, reversed out with the panel. Hairlines in the ink rule
   shade; the header rule keeps the full white weight so the column heads read
   as a header and not as another row. */
.stats-panel table {
  color: var(--color-on-dark);
}

.stats-panel th,
.stats-panel td {
  border-bottom-color: var(--color-ink-rule);
}

.stats-panel thead th {
  border-bottom-color: var(--color-on-dark);
}

/* Counts read as a column of numbers, not as ragged text, and sit against the
   right edge of the panel where a table of figures belongs. */
.stats-panel td {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.stats-panel thead th:last-child {
  text-align: right;
}

/* The last row's hairline sat a few pixels above the compliance block's own
   top rule, reading as a double rule with an empty band between them. */
.stats-panel tbody tr:last-child th,
.stats-panel tbody tr:last-child td {
  border-bottom: 0;
}

/* --- entity detail -------------------------------------------------------- */

/* A record's identity — name, type, number, standing, as-at date — is lifted
   into the hero band, so the page opens with the thing a citizen came to check
   presented as a record header rather than as the first few lines of a
   document. Everything below it is supporting history. */
.record-head .back-link {
  display: inline-block;
  margin-bottom: var(--space-4);
  font-size: 0.9375rem;
}

.record-head h1 {
  margin-bottom: var(--space-5);
}

/* The record summary: label-above-value pairs, which is how Companies House
   presents the authoritative facts of a company record. */
.record-summary {
  margin: 0 0 var(--space-4);
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4) var(--space-5);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
}

.record-summary > div {
  min-width: 0;
}

.badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
}

.record-head .provenance {
  margin-bottom: 0;
}

/* Guidance: ink on a pale ground with a heavy left bar, rather than amber text
   on amber. The previous all-amber block was legible but tiring, and the
   heading disappeared into its own background. */
.guidance {
  border: 1px solid var(--color-warning-text);
  border-left: 6px solid var(--color-warning-text);
  background: var(--color-guidance-bg);
  color: var(--color-text);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: var(--space-5);
  margin: 0 0 var(--space-6);
  max-width: var(--measure);
}

.guidance h2 {
  margin-top: 0;
  font-size: 1.375rem;
  color: var(--color-warning-text);
}

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

/* Each part of a record is a section a reader can find: a full-weight rule
   above the heading, real room between them. Stacked blocks with a heading
   were what made this page read as one undifferentiated document. */
.entity-detail > section {
  margin-bottom: var(--space-7);
  padding-top: var(--space-5);
  border-top: 3px solid var(--color-text);
}

.entity-detail > section > h2 {
  margin-top: 0;
}

address {
  font-style: normal;
}

/* --- tables --------------------------------------------------------------- */

.detail-table-wrap {
  overflow-x: auto;
}

table {
  border-collapse: collapse;
  width: 100%;
  font-size: 0.9375rem;
}

caption {
  text-align: left;
  font-weight: 700;
  color: var(--color-muted);
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding-bottom: var(--space-3);
}

th,
td {
  text-align: left;
  padding: var(--space-3) var(--space-3) var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
  vertical-align: top;
  /* Cells wrap. Blanket `nowrap` forced a horizontal scroll on every register
     table at 375px, which is the width most of this audience will use. */
  white-space: normal;
}

thead th {
  border-bottom: 2px solid var(--color-text);
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding-bottom: var(--space-2);
}

tbody th {
  font-weight: 600;
}

td:last-child,
th:last-child {
  padding-right: 0;
}

/* --- wider screens -------------------------------------------------------- */

@media (min-width: 40em) {
  .search-form {
    flex-direction: row;
    align-items: flex-end;
    gap: var(--space-3);
  }

  .search-form .search-field {
    flex: 1;
  }

  .result-meta {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .record-summary {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .compliance-figures {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5);
  }

  .hero {
    padding-top: var(--space-7);
    padding-bottom: var(--space-7);
  }

  .stats-panel {
    padding: var(--space-6) var(--space-6) var(--space-7);
  }

  /* The lead figure and the register's scope read side by side once there is
     room: the number takes the eye, the caveat sits beside it rather than
     three paragraphs away, which is where a caveat gets skipped. */
  .stat-total {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: baseline;
    gap: var(--space-3) var(--space-5);
  }

  .stat-total-label {
    margin-top: 0;
  }
}

@media (min-width: 60em) {
  .result-meta {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .record-summary {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* A record's sections become heading-beside-content once there is room for
     it — the layout a statutory publication uses, and the reason the desktop
     view no longer reads as a phone page stretched wide. No markup changes:
     the heading takes the first column, everything else stacks in the second. */
  .entity-detail > section {
    display: grid;
    grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
    column-gap: var(--space-6);
  }

  /* Stepped down from the full h2 scale: in a 15rem column the display size
     broke "Registered office address" over three lines, which reads as a
     mistake rather than as a heading. Its authority here comes from the rule
     above it and the space around it, not from its size. */
  .entity-detail > section > h2 {
    grid-column: 1;
    grid-row: 1;
    margin-bottom: 0;
    font-size: 1.375rem;
  }

  .entity-detail > section > :not(h2) {
    grid-column: 2;
  }

  .site-footer-inner {
    grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
    gap: var(--space-7);
  }

  .footer-org {
    padding-bottom: 0;
    border-bottom: 0;
    border-right: 1px solid var(--color-ink-rule);
    padding-right: var(--space-6);
  }
}

/* --- print ---------------------------------------------------------------- */

/* A register page is printed and filed. Tints are commonly dropped by printer
   settings, so the badge's meaning survives without them — the label and marker
   shape do that, and the border is forced back on. The ink grounds are dropped
   outright: reversed-out text is unreadable when colour is dropped, and a solid
   black slab when it is not. */
@media print {
  body {
    font-size: 11pt;
  }

  .masthead-bar,
  .stats-panel,
  .site-footer,
  .hero {
    background: transparent;
    color: #000;
    border-color: #000;
  }

  /* The orange seam is 2.26:1 and prints as an indeterminate grey; the bar
     still needs an edge, so it is redrawn in black. */
  .masthead-bar {
    border-bottom: 2px solid #000;
  }

  .site-title {
    color: #000;
  }

  .stats-panel {
    border: 1px solid #000;
    padding: 0.5cm;
  }

  .stats-panel h2,
  .stats-panel h3,
  .stats-panel table,
  .stats-panel .scope-caveat,
  .stats-panel .stat-total-label,
  .stats-panel .compliance-figure-label,
  .stats-panel .stat-status-caveat,
  .stats-panel .scope-caveat strong,
  .org-name,
  .footer-org-name,
  .compliance-figures li:first-child,
  .compliance-figures li:last-child {
    color: #000;
  }

  .stats-panel th,
  .stats-panel td,
  .stats-panel thead th,
  .stat-total,
  .stat-bo-compliance,
  .stat-status-caveat,
  .footer-org,
  .org-name {
    border-color: #000;
  }

  .search-form,
  .search-examples,
  .search-clear,
  .skip-link,
  .state-actions,
  .htmx-indicator,
  /* A staff sign-in prompt on a printed and filed register page is noise. */
  .footer-staff {
    display: none;
  }

  .badge {
    border: 1px solid #000;
    border-left-width: 4px;
    color: #000;
    background: transparent;
  }

  .provenance,
  .guidance {
    border-color: #000;
  }

  a {
    color: #000;
  }

  .detail-table-wrap {
    overflow: visible;
  }
}

/* --- Messages ------------------------------------------------------------ */

/* The public shell had no renderer for django.contrib.messages, so every
   refusal raised on a /my/ page was discarded before it reached a page. Colours
   match the office's so a refusal reads the same wherever it is met. */
.page-messages {
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: 0;
}

.page-message {
  padding: var(--space-3) var(--space-4);
  border-left: 5px solid var(--color-border-strong);
  background: var(--color-sunken);
  margin-bottom: var(--space-2);
  max-width: var(--measure);
  border-radius: var(--radius);
}

.page-message--success {
  border-left-color: var(--color-positive-text);
  background: var(--color-positive-bg);
  color: var(--color-positive-text);
}

.page-message--error {
  border-left-color: var(--color-negative-text);
  background: var(--color-negative-bg);
  color: var(--color-negative-text);
}

/* --- News and guidance --------------------------------------------------- */

.feed {
  list-style: none;
  margin: 0;
  padding: 0;
}

.feed__item {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--color-border);
  align-items: start;
}

/* Below this the image would be a postage stamp beside two lines of text.
   It goes full width above the words instead. */
@media (max-width: 40rem) {
  .feed__item {
    grid-template-columns: 1fr;
  }
}

.feed__image {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
}

.feed__item h2 {
  margin: 0 0 var(--space-2);
  font-size: 1.25rem;
}

.feed__kind {
  margin: 0 0 var(--space-1);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-brand-deep);
}

.feed__standfirst {
  margin: 0 0 var(--space-2);
  max-width: var(--measure);
}

.feed__date {
  margin: 0;
  font-size: 0.875rem;
  color: var(--color-muted);
}

.feed--compact li {
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
}

.feed--compact .feed__date {
  display: block;
}

.panel--notices {
  border-left: 4px solid var(--color-brand);
}

.article {
  max-width: var(--measure);
}

.article__standfirst {
  font-size: 1.15rem;
  line-height: 1.5;
  color: var(--color-text);
}

.article__meta {
  font-size: 0.875rem;
  color: var(--color-muted);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-border);
}

.article__hero {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  margin: var(--space-4) 0;
}

.article__body h2 { margin-top: var(--space-5); }
.article__body p,
.article__body ul { max-width: var(--measure); }

.image-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--space-4);
}

.image-grid img {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  border: 1px solid var(--color-border);
}

/* --- Cookie choice ------------------------------------------------------- */

/* Anchored to the bottom and NOT modal. A citizen checking whether their
   company is about to be deregistered must not have to make a privacy decision
   before they can read the page. */
.consent {
  position: sticky;
  bottom: 0;
  background: var(--color-text);
  color: var(--color-on-dark);
  border-top: 4px solid var(--color-brand);
  padding: var(--space-4) 0;
}

.consent__inner {
  display: flex;
  gap: var(--space-4);
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
}

.consent__text {
  margin: 0;
  max-width: 60ch;
  font-size: 0.9375rem;
  line-height: 1.5;
}

.consent__actions {
  display: flex;
  gap: var(--space-2);
  flex-shrink: 0;
}

/* Explicitly styled. This sheet has no generic `button` rule — every button is
   styled by its context — so the consent buttons rendered as raw browser
   defaults until this existed. On a government service that reads as a
   third-party widget bolted on, which is exactly what a cookie banner must NOT
   look like: people dismiss those without reading them.

   The tap target is 44px, the accessibility minimum for a touch control, and
   both choices are given equal visual weight. A banner whose "Allow" is a
   button and whose "No thanks" is faint grey text is a dark pattern, and this
   one records a real consent decision. */
.consent__actions button {
  font: inherit;
  font-size: 1rem;
  font-weight: 700;
  min-height: 44px;
  padding: 0.55rem 1.4rem;
  border-radius: var(--radius);
  cursor: pointer;
  border: 2px solid var(--color-on-dark);
  background: var(--color-on-dark);
  color: var(--color-text);
}

.consent__actions .button--secondary {
  background: transparent;
  color: var(--color-on-dark);
}

.consent__actions button:hover {
  background: var(--color-on-dark-muted);
  border-color: var(--color-on-dark-muted);
  color: var(--color-text);
}

/* On a phone the banner is the last thing between a reader and the page, so it
   gets tighter and the buttons go full width — a 44px target is only a target
   if it is reachable with a thumb. */
@media (max-width: 34rem) {
  .consent {
    padding: var(--space-3) 0;
  }

  .consent__text {
    font-size: 0.875rem;
  }

  .consent__actions {
    width: 100%;
  }

  .consent__actions button {
    flex: 1;
  }
}

/* --- CSS-only bar chart -------------------------------------------------- */

/* No charting library: a national register should not pull a megabyte of
   JavaScript to draw thirty rectangles, and this works with scripting off. */
.bars {
  list-style: none;
  margin: var(--space-3) 0;
  padding: 0;
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 140px;
}

.bars__bar {
  flex: 1;
  min-width: 3px;
  height: var(--h, 1%);
  background: var(--color-brand);
  border-radius: 2px 2px 0 0;
}

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

/* --- Stat cards and the front page --------------------------------------- */

/* Figures given weight, rather than a definition list. The non-compliant count
   is the fact this service exists about, so it carries its own colour. */
.stat-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-3);
  margin: var(--space-4) 0 var(--space-3);
}

.stat-card {
  padding: var(--space-4);
  background: var(--color-paper);
  border-left: 4px solid var(--color-border-strong);
  border-radius: var(--radius);
}

.stat-card--good { border-left-color: var(--color-positive-text); }
.stat-card--attention { border-left-color: var(--color-brand); }

.stat-card__n {
  display: block;
  font-size: clamp(1.75rem, 1.3rem + 1.8vw, 2.5rem);
  font-weight: 700;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}

.stat-card__label {
  display: block;
  margin-top: var(--space-2);
  font-size: 0.9375rem;
  color: var(--color-muted);
  line-height: 1.4;
}

.home-news__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  border-bottom: 2px solid var(--color-text);
  padding-bottom: var(--space-2);
  margin-top: var(--space-7);
}

.home-news__head h2 { margin: 0; }

.home-news__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-5);
  padding-top: var(--space-4);
}

.home-news__list h3 {
  margin: 0 0 var(--space-2);
  font-size: 1.125rem;
}

/* Motion, deliberately small. The original brief for this sheet said "no motion
   beyond an instant state change"; that is relaxed here to a 2px lift and a
   border colour on the section cards, because a card that does not respond at
   all reads as an image rather than a link. Anything larger would make a
   statutory register feel like a marketing site, and anyone who has asked for
   less motion gets none. */
.home-section {
  transition: transform 140ms ease, border-color 140ms ease,
    box-shadow 140ms ease;
}

.home-section::after {
  transition: transform 140ms ease;
}

.home-section:hover,
.home-section:focus-visible {
  transform: translateY(-2px);
  border-color: var(--color-brand);
}

@media (prefers-reduced-motion: reduce) {
  .home-section,
  .home-section::after { transition: none; }
  .home-section:hover,
  .home-section:focus-visible { transform: none; }
  /* The chevron keeps its 45deg rotation — that is its SHAPE, not motion. Only
     the 2px slide is dropped, by not overriding the base transform. */
  .home-section:hover::after { transform: rotate(45deg); }
}

/* --- Filter rows --------------------------------------------------------- */

/* The office sheet styles `.filters`; the public one did not, so the news feed's
   period selector and its button rendered as raw browser defaults beside
   carefully-styled everything else. Found by rendering the page at 390px —
   the same class of defect as the consent buttons, and invisible to every
   other check we have. */
.filters {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  flex-wrap: wrap;
  margin: var(--space-4) 0;
}

.filters select {
  font: inherit;
  font-size: 1rem;
  min-height: 44px;
  padding: 0.5rem var(--space-3);
  border: 2px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
}

.filters button {
  font: inherit;
  font-size: 1rem;
  font-weight: 700;
  min-height: 44px;
  padding: 0.5rem var(--space-4);
  border: 2px solid var(--color-brand);
  background: var(--color-brand);
  color: #fff;
  border-radius: var(--radius);
  cursor: pointer;
}

.filters button:hover {
  background: var(--color-brand-deep);
  border-color: var(--color-brand-deep);
}
