/* The privacy notice's styles (R-2026-09-26-136 DL-1 b). Linked from privacy.html, which
   carries no script, so the design system's tokens and fonts are imported HERE rather
   than from a module; Vite resolves the imports and emits one same-origin stylesheet.
   style.css brings the emergency strip and the lockup exactly as the index draws them.

   Nothing here adds a word. A stacked table row's label is the column's own header,
   shown from the cell's data-label attribute, and is not part of the page's text. *//* The OpenBed design system's tokens (the design pass, D1). Each section below is its
   source file copied byte for byte, in the order of the design system's styles.css,
   under a header naming the file and its sha256; tests/compliance/design_package.test.ts
   re-hashes every section against its header, so a hand edit reds. The source's
   fonts.css is NOT copied: it @imports Google Fonts, which BC-6 forbids, and
   packages/design/fonts.css self-hosts the same two typefaces instead. To change a
   token, re-copy the file from the design system and record the new sha256 in the
   decision record. */

/* ---- tokens/colors.css (sha256 f4eace8408c7e822547090ec45900f603f8087a12c04c1866d14128cc267a6c8) ---- */
:root{
  /* ---- Brand: institutional navy + muted teal. Never used to signal bed status. ---- */
  --ob-navy-900:#12283f;
  --ob-navy-800:#16314d;
  --ob-navy-700:#1b3a5c;   /* brand primary */
  --ob-navy-500:#2d5680;
  --ob-navy-300:#8fa6bd;
  --ob-navy-100:#dde5ee;
  --ob-navy-050:#eef3f8;
  --ob-teal-800:#1f6b67;
  --ob-teal-600:#2f8f8a;   /* brand secondary */
  --ob-teal-300:#8fc4c1;
  --ob-teal-100:#dbebea;

  /* ---- Neutrals: cool, paper-like, official ---- */
  --ob-ink-900:#14181c;
  --ob-ink-700:#333d47;
  --ob-ink-500:#5a6672;
  --ob-ink-400:#78838f;
  --ob-line-strong:#b9c3cc;
  --ob-line:#d7dde3;
  --ob-line-soft:#e7ebef;
  --ob-white:#ffffff;
  --ob-paper:#f4f6f8;
  --ob-paper-sunken:#eaeef2;

  /* ---- Bed status: a separate, deliberately desaturated functional system ---- */
  /* Darkened from the brand sheet's #3f7d58 / #a5741f so label text clears WCAG AA
     on its own fill (4.21:1 and 3.49:1 before, 4.5:1+ after). Hue is unchanged and
     separation from Full holds under deuteranopia/protanopia and a dim-screen model. */
  --ob-status-available:#3c7653;
  --ob-status-available-bg:#e7f0e9;
  --ob-status-available-line:#bcd5c6;
  --ob-status-limited:#8b621a;
  --ob-status-limited-bg:#f5ecd9;
  --ob-status-limited-line:#ddc9a0;
  --ob-status-full:#a4423a;
  --ob-status-full-bg:#f5e3e1;
  --ob-status-full-line:#e3c0bc;
  --ob-status-unknown:#5a6672;
  --ob-status-unknown-bg:#eceff2;
  --ob-status-unknown-line:#ced6dd;

  /* ---- Freshness bands (packages/snapshot/src/freshness.ts) ---- */
  --ob-fresh-green:var(--ob-status-available);
  --ob-fresh-yellow:var(--ob-status-limited);
  --ob-fresh-grey:var(--ob-ink-500);
  --ob-fresh-suppressed:var(--ob-ink-500);

  /* ---- Emergency: the permanent 112 / 767 strip. Highest-contrast object on the page. ---- */
  --ob-emergency-bg:#2b1512;
  --ob-emergency-fg:#ffffff;
  --ob-emergency-accent:#e0a49d;

  /* ================= Semantic aliases ================= */
  --text-strong:var(--ob-ink-900);
  --text-body:var(--ob-ink-700);
  --text-muted:var(--ob-ink-500);
  --text-faint:var(--ob-ink-400);
  --text-on-dark:var(--ob-white);
  --text-on-dark-muted:#b6c5d4;
  --text-link:var(--ob-navy-700);
  --text-link-hover:var(--ob-teal-800);

  --surface-page:var(--ob-paper);
  --surface-card:var(--ob-white);
  --surface-sunken:var(--ob-paper-sunken);
  --surface-inverse:var(--ob-navy-700);
  --surface-inverse-deep:var(--ob-navy-900);
  --surface-accent-soft:var(--ob-navy-050);

  --border-hairline:var(--ob-line-soft);
  --border-default:var(--ob-line);
  --border-strong:var(--ob-line-strong);
  --border-inverse:#2f5578;

  --action-primary-bg:var(--ob-navy-700);
  --action-primary-bg-hover:var(--ob-navy-800);
  --action-primary-bg-active:var(--ob-navy-900);
  --action-primary-fg:var(--ob-white);
  --action-secondary-bg:var(--ob-white);
  --action-secondary-fg:var(--ob-navy-700);
  --action-secondary-border:var(--ob-line-strong);
  --action-secondary-bg-hover:var(--ob-navy-050);
  --action-quiet-fg:var(--ob-ink-700);
  --focus-ring:var(--ob-teal-600);
}

/* ---- tokens/typography.css (sha256 066c39948bcc139779ce6e20197f1b1e893df9b41daca908c02c96c7455f0430) ---- */
:root{
  --font-sans:"Public Sans","Helvetica Neue",Arial,sans-serif;
  --font-mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;

  /* Public Sans carries headlines and all UI text. */
  --text-display:700 34px/1.15 var(--font-sans);
  --text-title:600 24px/1.25 var(--font-sans);
  --text-heading:600 18px/1.3 var(--font-sans);
  --text-subheading:600 15px/1.35 var(--font-sans);
  --text-body-lg:400 17px/1.55 var(--font-sans);
  --text-body-md:400 15px/1.55 var(--font-sans);
  --text-body-sm:400 13px/1.5 var(--font-sans);
  --text-label:600 13px/1.3 var(--font-sans);

  /* IBM Plex Mono carries every number the system asserts: bed counts,
     timestamps, phone numbers, category codes. */
  --text-count-xl:600 40px/1 var(--font-mono);
  --text-count-lg:600 28px/1 var(--font-mono);
  --text-count-md:500 18px/1.2 var(--font-mono);
  --text-stamp:400 12px/1.4 var(--font-mono);
  --text-phone:500 16px/1.2 var(--font-mono);

  --tracking-caps:0.08em;
  --tracking-tight:-0.01em;

  /* Category and status labels are set in caps with mono tracking. */
  --text-eyebrow:600 11px/1.2 var(--font-mono);
}

/* ---- tokens/spacing.css (sha256 2cf2ffddbaf9dafb2d55d0c9e844bdaf78bd374ad94e673cf28f19875467e65e) ---- */
:root{
  --space-1:4px;
  --space-2:8px;
  --space-3:12px;
  --space-4:16px;
  --space-5:20px;
  --space-6:24px;
  --space-8:32px;
  --space-10:40px;
  --space-12:48px;
  --space-16:64px;

  --gutter-page:16px;
  --gutter-page-wide:24px;
  --measure-content:680px;
  --measure-app:960px;

  /* Touch targets. The call button is the primary action on every tile and is
     never smaller than this. */
  --hit-min:44px;
  --hit-primary:52px;
}

/* ---- tokens/surfaces.css (sha256 a31ddef7c358099de54aef5207490e042e6ce0b612b41229ca644ddcb56dbeaa) ---- */
:root{
  /* Squared-off institutional geometry. Nothing is pill-shaped except chips. */
  --radius-none:0px;
  --radius-sm:2px;
  --radius-md:4px;
  --radius-lg:6px;
  --radius-chip:999px;

  --border-width:1px;
  --border-width-strong:2px;
  /* The status accent on a tile is a left rule on a bordered card, not a bare
     coloured edge floating on paper. */
  --border-accent-width:3px;

  /* Shadows are rare. A card is defined by its border; elevation appears only
     on things that genuinely float (sticky bars, menus). */
  --shadow-none:none;
  --shadow-sticky:0 1px 0 rgba(20,24,28,.08);
  --shadow-raised:0 1px 2px rgba(20,24,28,.10),0 2px 8px rgba(20,24,28,.06);
  --shadow-overlay:0 8px 28px rgba(18,40,63,.18);
  --shadow-inset-top:inset 0 1px 0 rgba(255,255,255,.06);

  --focus-ring-width:2px;
  --focus-ring-offset:2px;
}

/* ---- tokens/motion.css (sha256 e4979114e041e614bf05461f1a633f0ab6e3f2fa8786d984992f68c4f2a6cad4) ---- */
:root{
  /* Short, flat, unshowy. Nothing bounces; nothing pulses except the live dot,
     and that only when a snapshot is genuinely current. */
  --duration-instant:80ms; /* @kind other */
  --duration-fast:120ms; /* @kind other */
  --duration-base:180ms; /* @kind other */
  --duration-slow:320ms; /* @kind other */
  --ease-standard:cubic-bezier(.2,0,.2,1); /* @kind other */
  --ease-out:cubic-bezier(0,0,.2,1); /* @kind other */
  --transition-control:background-color var(--duration-fast) var(--ease-standard),border-color var(--duration-fast) var(--ease-standard),color var(--duration-fast) var(--ease-standard);
  --press-scale:0.995; /* @kind other */
}
@media (prefers-reduced-motion:reduce){
  :root{--duration-instant:0ms; /* @kind other */ --duration-fast:0ms; /* @kind other */ --duration-base:0ms; /* @kind other */ --duration-slow:0ms; /* @kind other */}
}

/* ---- tokens/base.css (sha256 af85fa2eb2be8a89d0def18247aa9292df3333a873cbfb7139fe10b20ebbd533) ---- */
*,*::before,*::after{box-sizing:border-box}
body{margin:0;font:var(--text-body-md);color:var(--text-body);background:var(--surface-page);-webkit-font-smoothing:antialiased}
a{color:var(--text-link);text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1px}
a:hover{color:var(--text-link-hover)}
:focus-visible{outline:var(--focus-ring-width) solid var(--focus-ring);outline-offset:var(--focus-ring-offset)}
/* The design system's two typefaces, SELF-HOSTED (the design pass, D1).

   The design system's own fonts.css @imports Google Fonts. That hands every visitor's
   address to a third party on load and needs a font host in the CSP, which BC-6
   forbids. These rules point instead at the woff2 files of @fontsource/public-sans and
   @fontsource/ibm-plex-mono (both OFL-1.1; see NOTICE), which Vite copies into each
   app's build as hashed same-origin assets, so the CSP is unchanged: fonts fall under
   default-src 'self'.

   Only what the tokens use: Public Sans 400/600/700 and IBM Plex Mono 400/500/600, the
   latin subset (its unicode-range copied from fontsource's own latin rules), woff2 only.
   font-display: swap, so text shows at once in the fallback face on a slow handset. */

@font-face {
  font-family: 'Public Sans';
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url('/assets/public-sans-latin-400-normal-8Rpg0ruU.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

@font-face {
  font-family: 'Public Sans';
  font-style: normal;
  font-display: swap;
  font-weight: 600;
  src: url('/assets/public-sans-latin-600-normal-Fru-LXNs.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

@font-face {
  font-family: 'Public Sans';
  font-style: normal;
  font-display: swap;
  font-weight: 700;
  src: url('/assets/public-sans-latin-700-normal-BqJmxWdE.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url('/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-display: swap;
  font-weight: 500;
  src: url('/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-display: swap;
  font-weight: 600;
  src: url('/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

/* The public dashboard's styles (the design pass, D1). Imported by src/main.ts AFTER
   @openbed/design's tokens and fonts, so every value here reads a design-system token.
   Moved out of index.html's inline \3c style> by PR 3.4b-app B (R-2026-09-24-93 BU-2 c):
   the CSP in public/_headers allows style-src 'self' only, with no hash and no
   'unsafe-inline', and an inline block would be blocked silently.

   Nothing here changes a word. Colour is never the only signal: every state the page
   shows is carried by its words, as before the design pass. Nothing is sticky or fixed. */

/* The call link: the tile's one full-width primary action, 52 px tall (R-2026-09-23-66
   C1 required at least 44 x 44; the design system's primary hit size is 52).
   tests/compliance/dashboard_identity_and_call.test.ts parses LITERAL px from this rule,
   so its sizes are written as numbers, never as var(--hit-primary). The label is centred
   with flex, not line-height: the font shorthand resets line-height, and a label that
   wraps on a narrow handset must stay inside the button. */
a.call { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; column-gap: 0.3em; min-height: 52px; min-width: 44px; padding: 8px 16px; text-align: center; font: var(--text-subheading); background: var(--action-primary-bg); color: var(--action-primary-fg); border-radius: var(--radius-md); text-decoration: none; transition: var(--transition-control); }
a.call:hover { background: var(--action-primary-bg-hover); color: var(--action-primary-fg); }
a.call:active { background: var(--action-primary-bg-active); }
/* THE SIZE ORDER (v1:243, "the bed count is visually subordinate to the phone number";
   R-2026-09-26-126 DB-3 with the founder's order): the facility name 24 > the number to
   call 20 > the count 18. Declared as LITERAL px in these three rules, because
   tests/compliance/dashboard_identity_and_call.test.ts compares them and cannot read a
   var(). The values are the design system's --text-title, the phone at 600/20 and
   --text-count-md. */
a.call .phone { font-family: var(--font-mono); font-weight: 600; font-size: 20px; line-height: 1.2; }

body { min-width: 0; }

/* 1. The emergency strip: the single high-contrast object on the page. */
#emergency-strip {
  background: var(--ob-emergency-bg);
  color: var(--ob-emergency-fg);
  text-align: center;
  padding: 0 var(--gutter-page);
  font: var(--text-body-md);
}
#emergency-strip a {
  display: inline-block;
  min-height: 44px;
  min-width: 44px;
  padding: 0 var(--space-2);
  color: var(--ob-emergency-fg);
  font: var(--text-phone);
  line-height: 44px; /* after the font shorthand, which would reset it */
  text-underline-offset: 3px;
}
#emergency-strip a:focus-visible { outline-color: var(--ob-emergency-fg); }

/* 2. The indicative banner. Persistent, never dismissible. */
#indicative-banner {
  background: var(--surface-accent-soft);
  color: var(--ob-navy-800);
  border-bottom: var(--border-width) solid var(--ob-navy-100);
  text-align: center;
  padding: var(--space-2) var(--gutter-page);
  font: var(--text-body-md);
}

/* 3. The header: the mark at 28 px and the live-text lockup, in the same 960 px centred
   column as the content (DB-5 b); the bar itself stays full width. */
.site-header {
  background: var(--surface-card);
  border-bottom: var(--border-width) solid var(--border-default);
  padding: var(--space-3) 0;
}
/* The same box as main#app -- 960 px, centred, with the same gutter INSIDE it -- so the
   lockup's left edge is the tiles' left edge at every width. */
.site-header-inner {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  max-width: var(--measure-app);
  margin: 0 auto;
  padding: 0 var(--gutter-page);
}
/* The mark and lockup are one link home (R-2026-09-28-159 EI). It looks exactly as the
   unlinked lockup did: no underline and no colour change in any state (the design system's
   a{} and a:hover{} would otherwise underline and recolour it), and no hover effect beyond
   the cursor. The tap target is 44 px tall; the -8 px block margin keeps it inside the
   header's 12 px padding, so the header is no taller than before. Its focus ring is the
   design system's :focus-visible rule, 2 px teal at a 2 px offset, not restated here.
   tests/compliance/dashboard_home_link.test.ts reads these rules from the built CSS. */
.home-link { display: flex; align-items: center; gap: var(--space-2); min-height: 44px; margin: -8px 0; }
.home-link, .home-link:hover, .home-link:active, .home-link:visited { color: inherit; text-decoration: none; }
.site-header .mark { display: block; width: 28px; height: 28px; }
.lockup { font: 700 20px/1 var(--font-sans); letter-spacing: -0.02em; }
.lockup-open { color: var(--ob-navy-700); }
.lockup-bed { color: var(--ob-teal-600); }

/* 4 and 5. The snapshot banner and the tiles, in one column of at most 960 px. */
main#app {
  display: grid;
  gap: var(--space-4);
  max-width: var(--measure-app);
  margin: 0 auto;
  padding: var(--space-4) var(--gutter-page);
}

/* The empty, outage and snapshot-stale states are a Notice: a sunken panel with a
   3 px left accent. The words are unchanged, and the snapshot banner keeps role=status. */
.empty-state,
.outage-state,
.snapshot-banner {
  margin: 0;
  background: var(--surface-sunken);
  border-left: var(--border-accent-width) solid var(--ob-navy-500);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  color: var(--text-strong);
  font: var(--text-body-md);
  max-width: var(--measure-content);
}

/* A facility tile: white, a 1 px border, 6 px radius, no shadow. */
section.facility {
  display: grid;
  gap: var(--space-3);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
}
section.facility h2 { margin: 0; font-family: var(--font-sans); font-weight: 600; font-size: 24px; line-height: 1.25; color: var(--text-strong); overflow-wrap: anywhere; }
section.facility ul { list-style: none; margin: 0; padding: 0; }

/* The location block under the name (R-2026-09-30-214 GN): the street address, "<LGA>, <State>" and the
   Directions link. All three are body text, well below the name's 24 px and the number's 20 px, so the
   size order in dashboard_identity_and_call.test.ts (name > number > count) is untouched. The grid's gap
   would space them like separate cards, so the block pulls its own lines together. Long unbroken text
   wraps rather than widening the card on a 375 px handset. */
section.facility p.facility-address,
section.facility p.facility-area { margin: 0; font: var(--text-body-md); color: var(--text-body); overflow-wrap: anywhere; }
section.facility p.facility-address { color: var(--text-strong); }
section.facility p.facility-address + p.facility-area { margin-top: calc(-1 * var(--space-2)); }
/* Directions: a text link with a 44 px tap target (the design system's minimum hit size), kept clear of
   the full-width call button below it. */
section.facility a.directions { display: inline-flex; align-items: center; justify-self: start; min-height: 44px; min-width: 44px; font: var(--text-subheading); }
/* The link's 44 px box centres its text, which left a gap under the area line that the lines above do not
   have. The box stays 44 px tall (the tap target); only its place is pulled up, by what the centring added. */
section.facility p + a.directions { margin-top: calc(-1 * var(--space-3)); }

/* The loading line: the empty-state's register, and nothing stronger. It is replaced, never joined. */
.loading-state { margin: 0; color: var(--text-muted); font: var(--text-body-md); max-width: var(--measure-content); }

/* A ward row. The li holds the whole sentence; the spans only style pieces of it. */
section.facility li {
  border-top: var(--border-width) solid var(--border-hairline);
  padding: var(--space-3) 0;
  font: var(--text-body-md);
  color: var(--text-body);
}
.ward-category { font: var(--text-subheading); color: var(--text-strong); }
.ward-words { color: var(--ob-status-unknown); }

/* The count badge. A status fill only while the claim is fresh (band GREEN) and carries
   no qualifier, and never under the page's stale banner (DB-1, DB-2): Available is
   accepting with a count above 0, Full is not accepting or 0. Every other case is the
   not-reporting fill. "Limited" is not used: no threshold for it has been ruled. The
   kickoff's --text-count-lg is superseded by DB-3: the count is subordinate to the phone. */
.badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 18px;
  line-height: 1.2;
  padding: var(--space-1) var(--space-2);
  border: var(--border-width) solid;
  border-radius: var(--radius-md);
  vertical-align: middle;
}
.status-available { background: var(--ob-status-available-bg); border-color: var(--ob-status-available-line); color: var(--ob-status-available); }
.status-full { background: var(--ob-status-full-bg); border-color: var(--ob-status-full-line); color: var(--ob-status-full); }
.status-unknown { background: var(--ob-status-unknown-bg); border-color: var(--ob-status-unknown-line); color: var(--ob-status-unknown); }

/* The age stamp takes its band's colour. The dot is static, and only on a fresh row that
   claims a count, on a page that is not itself stale (DB-1, DB-4). */
.stamp { font: var(--text-stamp); }
/* On a phone the stamp takes its own line under the claim, so it never breaks mid-phrase
   at the end of a long claim (DB-5 a). The words are unchanged. */
@media (max-width: 599px) {
  .stamp { display: block; margin-top: var(--space-1); }
}
.stamp-green { color: var(--ob-fresh-green); }
.stamp-yellow { color: var(--ob-fresh-yellow); }
.stamp-grey { color: var(--ob-fresh-grey); }
.stamp-green::before {
  content: '';
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: var(--space-1);
  border-radius: var(--radius-chip);
  background: var(--ob-fresh-green);
  vertical-align: middle;
}

/* 6. The footer: the general-enquiries address and the privacy notice's link (R-2026-09-26-136
   DL-1 d), side by side, wrapping on a narrow screen. */
#site-footer {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--space-6);
  max-width: var(--measure-app);
  margin: 0 auto;
  padding: var(--space-4) var(--gutter-page) var(--space-8);
  font: var(--text-body-sm);
  color: var(--text-muted);
}
#site-footer a { display: inline-block; min-height: 44px; line-height: 44px; }

@media (min-width: 720px) {
  #emergency-strip,
  #indicative-banner,
  .site-header-inner { padding-left: var(--gutter-page-wide); padding-right: var(--gutter-page-wide); }
  main#app { padding: var(--space-6) var(--gutter-page-wide); }
  #site-footer { padding-left: var(--gutter-page-wide); padding-right: var(--gutter-page-wide); }
}

/* 7. The search controls (R-2026-10-09 GO, C): outside main#app, in the same 960 px column, so the poll's
   re-render of the results never touches them. Every control is at least 44 px tall (the design system's
   minimum hit size), and nothing here is sticky or fixed. */
#search {
  display: grid;
  gap: var(--space-3);
  max-width: var(--measure-app);
  margin: 0 auto;
  padding: var(--space-4) var(--gutter-page) 0;
}
#search .field { display: grid; gap: var(--space-1); }
#search label { font: var(--text-label); color: var(--text-strong); }
#search .combo { position: relative; }
#search .combo-input,
#search .order-select {
  box-sizing: border-box;
  width: 100%;
  min-height: 44px;
  padding: 0 var(--space-3);
  font: var(--text-body-md);
  color: var(--text-strong);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-md);
}
#search .combo-list {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  margin: var(--space-1) 0 0;
  padding: 0;
  max-height: 260px;
  overflow-y: auto;
  list-style: none;
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-md);
}
#search .combo-option { min-height: 44px; box-sizing: border-box; display: flex; align-items: center; padding: 0 var(--space-3); font: var(--text-body-md); color: var(--text-strong); cursor: pointer; }
#search .combo-option[hidden] { display: none; }
#search .combo-option.is-active { background: var(--surface-accent-soft); }
#search .combo-option[aria-selected='true'] { font-weight: 600; }
/* THE hidden ATTRIBUTE MUST WIN. A rule that sets `display` outranks the browser's own [hidden] rule, so a control the script hides with
   `hidden` would stay on screen (the no-match message and its "Clear search" button did, in the first screenshot pass). jsdom lays nothing out
   and could not see it; tests/compliance/search_static.test.ts holds this rule in the stylesheet. */
#search [hidden] { display: none !important; }
/* THE NO-MATCH MESSAGE IS AN OVERLAY, like the list (Addendum 2, item 4 c): out of flow, under the input, so the field never grows and the
   "Near me" button stays beside the input in every state. In flow, it pushed the button below the input. */
#search .combo-none { position: absolute; z-index: 2; left: 0; right: 0; top: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: var(--space-1); padding: var(--space-1) var(--space-3); box-sizing: border-box; background: var(--surface-card); border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-md); font: var(--text-body-md); color: var(--text-body); }
/* The area picker and "Near me" share a row, and stack when the handset is narrow. */
#search .area-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3); }
#search .area-row .field { flex: 1 1 220px; }
#search .near-me {
  min-height: 44px;
  min-width: 44px;
  padding: 0 var(--space-4);
  font: var(--text-subheading);
  color: var(--action-secondary-fg);
  background: var(--action-secondary-bg);
  border: var(--border-width) solid var(--action-secondary-border);
  border-radius: var(--radius-md);
  cursor: pointer;
}
#search .near-me:hover { background: var(--action-secondary-bg-hover); }
#search .link-button {
  min-height: 44px;
  min-width: 44px;
  padding: 0 var(--space-2);
  font: var(--text-body-md);
  color: var(--text-link);
  background: none;
  border: 0;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
#search .link-button:hover { color: var(--text-link-hover); }
#search p { margin: 0; font: var(--text-body-md); color: var(--text-body); max-width: var(--measure-content); }
#search p[hidden] { display: none; }
/* The attribution, the coverage line and the share note are small print: smaller and quieter than the
   controls, and the coverage line is NOT a live region. */
#search .attribution,
#search .share-note { font: var(--text-body-sm); color: var(--text-muted); }
#search .coverage { font: var(--text-body-sm); color: var(--text-muted); }
#search .order-row { display: grid; gap: var(--space-1); }
#search .order-explain { font: var(--text-body-sm); color: var(--text-muted); }
#search .share-row { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--space-3); }
#search .aged-order { padding: var(--space-2) var(--space-3); background: var(--surface-sunken); border-left: var(--border-accent-width) solid var(--ob-navy-500); border-radius: var(--radius-md); color: var(--text-strong); }

/* The distance under the facility's area line, outside the ward rows. */
section.facility p.facility-distance { margin: 0; font: var(--text-body-md); color: var(--text-body); overflow-wrap: anywhere; }

@media (min-width: 720px) {
  #search { padding-left: var(--gutter-page-wide); padding-right: var(--gutter-page-wide); }
}

main#notice {
  max-width: var(--measure-app);
  margin: 0 auto;
  padding: var(--space-4) var(--gutter-page) var(--space-8);
  color: var(--text-body);
  font: var(--text-body-md);
  overflow-wrap: anywhere;
}
main#notice h1 { margin: 0 0 var(--space-2); font-family: var(--font-sans); font-weight: 700; font-size: 24px; line-height: 1.25; color: var(--text-strong); }
main#notice h2 { margin: var(--space-6) 0 var(--space-2); font: var(--text-subheading); color: var(--text-strong); }
main#notice p,
main#notice ul { margin: 0 0 var(--space-3); max-width: var(--measure-content); }
main#notice ul { padding-left: var(--space-5); }
main#notice li { margin-bottom: var(--space-1); }
main#notice a { color: var(--text-link); }
main#notice a:hover { color: var(--text-link-hover); }

main#notice table { width: 100%; border-collapse: collapse; margin: 0 0 var(--space-4); font: var(--text-body-sm); }
main#notice th,
main#notice td { text-align: left; vertical-align: top; padding: var(--space-2); border-top: var(--border-width) solid var(--border-hairline); }
main#notice th { color: var(--text-strong); font-weight: 600; border-top: 0; border-bottom: var(--border-width) solid var(--border-default); }

/* Narrow screens: each row becomes a card, each cell labelled with its column's header,
   so no table ever scrolls sideways. */
@media (max-width: 719px) {
  main#notice thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  main#notice table,
  main#notice tbody,
  main#notice tr,
  main#notice td { display: block; width: auto; }
  main#notice tr { border: var(--border-width) solid var(--border-default); border-radius: var(--radius-lg); background: var(--surface-card); margin-bottom: var(--space-3); padding: var(--space-1) var(--space-3); }
  main#notice td { border-top: var(--border-width) solid var(--border-hairline); padding: var(--space-2) 0; }
  main#notice td:first-child { border-top: 0; }
  main#notice td::before { content: attr(data-label); display: block; font-weight: 600; color: var(--text-muted); }
}

@media (min-width: 720px) {
  main#notice { padding: var(--space-6) var(--gutter-page-wide) var(--space-8); }
}

/* The area reference points' attribution on the About page (R-2026-10-09 GO, GO-2 e): under the text,
   in the same column, small print. */
p.page-attribution { max-width: var(--measure-app); margin: 0 auto; padding: 0 var(--gutter-page); font: var(--text-body-sm); color: var(--text-muted); }
@media (min-width: 720px) {
  p.page-attribution { padding: 0 var(--gutter-page-wide); }
}
