/* ==========================================================================
   Three Hearts Connect — base stylesheet
   ==========================================================================

   Load AFTER tokens.css; every value here comes from a token.

     <link rel="stylesheet" href="{% static 'css/tokens.css' %}">
     <link rel="stylesheet" href="{% static 'css/base.css' %}">

   Scope: a modern reset, page furniture, and the accessibility floor. Enough
   to render a clean, readable, keyboard-navigable page and no more —
   components arrive with the screens that need them.

   Mobile-first throughout. 390px is the design width, 320px must still work,
   and every media query below is min-width. There is no max-width query in
   this file, deliberately: they are how a layout ends up with rules that
   fight each other.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. Reset
   -------------------------------------------------------------------------- */

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

/* Margin is opted into, not fought against. */
* {
  margin: 0;
}

html {
  /* 100%, NOT a fixed px size: this keeps 1rem equal to whatever the reader
     has chosen in their browser. The 18px body minimum is applied on <body>
     as 1.125rem instead, so someone who has raised their default gets a
     proportionally larger interface rather than having it overridden. */
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Long place names and email addresses must not force a sideways scroll on a
   320px screen. */
body,
h1, h2, h3, h4, h5, h6,
p, li, dd, dt,
figcaption {
  overflow-wrap: break-word;
}

h1, h2, h3, h4, h5, h6 {
  text-wrap: balance;   /* progressive: ignored where unsupported */
}

p, li, dd {
  text-wrap: pretty;
}

img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

/* A textarea that cannot grow sideways is one less way to lose typed text. */
textarea {
  resize: vertical;
}

ul[role="list"],
ol[role="list"] {
  list-style: none;
  padding: 0;
}

table {
  border-collapse: collapse;
  width: 100%;
}

/* Anything wide enough to overflow scrolls inside its own box rather than
   dragging the whole page sideways. */
.scroll-x {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}


/* --------------------------------------------------------------------------
   2. Page
   -------------------------------------------------------------------------- */

body {
  min-height: 100svh;
  font-family: var(--font-ui);
  font-size: var(--size-body);          /* 1.125rem = 18px minimum */
  font-weight: var(--weight-regular);
  line-height: var(--leading-body);
  color: var(--text-body);              /* 9.79:1 on the page ground */
  background-color: var(--surface-page);
  /* Nunito's default figures are proportional; tabular figures keep dates and
     times from jittering between rows. */
  font-variant-numeric: tabular-nums;
}


/* --------------------------------------------------------------------------
   3. Headings and prose
   --------------------------------------------------------------------------
   Playfair Display for headings only. Grounding section 9: it is a display
   face and belongs on section headings and the occasional warm line, not on
   interface furniture — so buttons, labels, inputs and pills stay Nunito.
   -------------------------------------------------------------------------- */

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);      /* 700 */
  line-height: var(--leading-tight);
  color: var(--text-strong);            /* navy, 12.19:1 on the page ground */
  letter-spacing: -0.01em;
}

h1 {
  font-size: var(--size-2xl);           /* 36px at 390px */
  font-weight: var(--weight-heavy);     /* 800 */
}

h2 {
  font-size: var(--size-xl);
}

h3 {
  font-size: var(--size-lg);
  line-height: var(--leading-snug);
}

/* h4 and below are interface furniture rather than section headings, so they
   drop to Nunito. */
h4, h5, h6 {
  font-family: var(--font-ui);
  font-weight: var(--weight-bold);
  font-size: var(--size-md);
  line-height: var(--leading-snug);
  color: var(--text-strong);
}

/* Vertical rhythm: space above a heading that follows content, never above
   the first thing in a box. */
:is(h1, h2, h3, h4, h5, h6) + * {
  margin-top: var(--space-xs);
}

* + :is(h1, h2, h3, h4, h5, h6) {
  margin-top: var(--space-lg);
}

p + p,
p + ul,
p + ol,
ul + p,
ol + p {
  margin-top: var(--space-sm);
}

/* THE PULL QUOTE, AND ONLY THE PULL QUOTE.

   The one Playfair accent the brand allows: 500 italic, for a warm line.
   Sage would be the tempting colour here and it is not usable — 3.26:1 as
   normal text. Kept at --size-lg (24px), which is the large-text threshold,
   so the sage variant below is legitimate at 3.26:1 against AA's 3:1 bar.

   NOT FOR BODY COPY, and that is a brand rule rather than a preference. The
   Brand Toolkit v1.0 is quoted verbatim at the top of deploy/preview/style.css:
   "Playfair Display 700 for headings, 500 italic for the pull quote. Never for
   body copy." A paragraph somebody has to READ — an instruction, an
   explanation, an apology — is body copy however important it is, and the more
   important it is the more certainly it belongs in Nunito. Use .lede--plain
   below. This class is for a line that is being QUOTED, not a line that is
   being followed. */
.lede {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);    /* 500 */
  font-style: italic;
  font-size: var(--size-lg);
  line-height: var(--leading-snug);
  color: var(--text-strong);
}

/* The opening paragraph of a screen, set as body copy.

   Same job — lead the page — done in the face the toolkit allows for it. The
   designed sign-in screen sets its instruction this way (upright Nunito,
   one step up from the body floor, ink rather than navy), and that paragraph
   is the most-read sentence in the whole application: it is what the front
   door says to somebody who has never been here before.

   --size-md is the type scale's own stated purpose — "20px — lead
   paragraphs". It is a step of emphasis, not a change of voice.

   Specificity 0,2,0, deliberately. Written as a bare `.lede--plain` this
   would tie at 0,1,0 with `.lede` and be decided by which rule came later in
   the file — and a paragraph that silently reverts to italic Playfair when
   somebody reorders a stylesheet is precisely the defect this variant exists
   to fix. Use both classes:

       <p class="lede lede--plain">…</p>  */
.lede.lede--plain {
  font-family: var(--font-ui);
  font-style: normal;
  font-weight: var(--weight-regular);
  font-size: var(--size-md);            /* 20px */
  line-height: var(--leading-body);
  color: var(--text-body);              /* 9.79:1 on page, 10.13:1 on raised */
}

.eyebrow {
  font-family: var(--font-ui);
  font-weight: var(--weight-black);     /* 900 — weight, not smaller type */
  font-size: var(--size-body);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);             /* 5.96:1 on the page ground */
}

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

small,
.text-meta {
  /* Not smaller. The 18px minimum has no exceptions here — <small> is
     re-pointed at the body size so an author reaching for it cannot drop
     below the floor by accident. Use weight or colour for de-emphasis. */
  font-size: var(--size-body);
  color: var(--text-muted);
}

strong, b {
  font-weight: var(--weight-bold);
}


/* --------------------------------------------------------------------------
   4. Links
   --------------------------------------------------------------------------
   Underlined, always. Grounding section 8: never colour alone to convey
   state — and a navy link on cream is distinguishable from navy body text by
   nothing except the underline.
   -------------------------------------------------------------------------- */

a {
  color: var(--link);                   /* 12.19:1 */
  text-decoration: underline;
  text-decoration-thickness: 0.08em;
  text-underline-offset: 0.18em;
}

a:hover {
  text-decoration-thickness: 0.14em;
}

/* Inline links inside a run of text still need a 44px target vertically;
   block-level links get the full treatment in section 6. This is the rule
   that comment used to only PROMISE, and the promise was load-bearing.

   A bare inline <a> is one line box high — 18px of text at 1.6 line-height is
   about 29px — which is under the 44px floor grounding section 8 sets without
   exception. That is not a rounding error on the two links this application
   currently has: both of them are escape hatches. "Not the right address?
   Change it" is one of the three things D-015 pays for the anti-enumeration
   wording with, and the person reaching for it is by definition the person who
   has just mistyped something. A control that is hard to hit for somebody with
   an unsteady hand is worst exactly where it matters most.

   inline-flex rather than inline-block: inline-block ignores min-height when
   the box has a single line of text in normal flow in some engines, and
   align-items keeps the label optically centred once the box is taller than
   the text. It stays an inline-level box, so it still sits in a sentence and
   still wraps at 320px; when it wraps to two lines it simply gets taller.

   Not applied to every `a`, deliberately. A 44px-tall box on every link in a
   paragraph of prose would blow the line spacing apart. It is opted into on
   the links that are targets rather than references. */
.tap-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  /* Both axes, not just the tall one. Every label this class currently
     carries is far wider than 44px, so this floor never fires today — which
     is exactly why it is written down now rather than when somebody adds a
     link whose label is "Edit". Grounding §8 says 44px, and a rule that holds
     only because of the words that happen to be inside it is not the rule. */
  min-width: var(--tap-min);
}


/* --------------------------------------------------------------------------
   5. Focus — WCAG 2.2 AA, SC 2.4.11 and 2.4.13
   --------------------------------------------------------------------------
   :focus-visible only, so a mouse click does not leave a ring behind but every
   keyboard and switch reader sees exactly where they are.

   Navy at 3px clears 3:1 against every surface the ring can land on:
   page 12.19, raised 12.62, tint 11.73, sage 3.74. The offset guarantees the
   ring is not swallowed by the control's own background.
   -------------------------------------------------------------------------- */

:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
  /* No border-radius here, deliberately.

     It used to sit in this rule, and it changed the SHAPE of a control the
     moment it was focused. At specificity 0,1,0 it outranked `button`,
     `textarea` and `select` (0,0,1) but lost to `.button`, `.pill` and the
     input rule in section 6 — so a <button> and a visually identical
     <a class="button"> snapped to DIFFERENT corner radii when tabbed
     through, and only for keyboard users.

     It bought nothing in exchange: an outline already follows the element's
     own border-radius in every browser this application supports. */
}

/* Remove the ring only where :focus-visible has already taken over, so
   browsers without it keep a visible focus state rather than losing it. */
:focus:not(:focus-visible) {
  outline: none;
}

/* On navy grounds the navy ring would disappear; sage-light gives 5.85:1. */
.surface-inverse :focus-visible {
  outline-color: var(--focus-ring-on-inverse);
}

/* ...but a LIGHT surface nested inside a navy band takes the navy ring back.

   The rule above is an unscoped descendant selector, so without this the
   sage-light ring keeps applying to a control sitting on a .card, .band-tint
   or .pill inside the band — where the ring is drawn on cream or tint, not
   on navy:

     sage-light ring on the raised surface   2.16:1   FAILS
     sage-light ring on the tint             2.00:1   FAILS
     navy ring on the raised surface        12.62:1   passes
     navy ring on the tint                  11.73:1   passes

   SC 1.4.11 wants 3:1 for a focus indicator, so those two were real losses
   of the focus ring, not cosmetic.

   Descendant only, never the surface itself: a focusable .card or
   <a class="pill"> sitting directly on the band has its ring drawn OUTSIDE
   itself, on navy, where sage-light is the right colour. Section 7 carries
   the full self-describing-surface reasoning. */
.surface-inverse :is(.card, .band-tint, .pill) :focus-visible {
  outline-color: var(--focus-ring);
}

/* Bypass blocks (SC 2.4.1). Visible the moment it is focused. */
.skip-link {
  position: absolute;
  left: var(--space-sm);
  top: var(--space-sm);
  z-index: 100;
  padding: var(--space-2xs) var(--space-sm);
  min-height: var(--tap-min);
  min-width: var(--tap-min);            /* both axes, like every other target */
  display: inline-flex;
  align-items: center;
  background-color: var(--action-primary-bg);
  color: var(--action-primary-text);
  font-weight: var(--weight-bold);
  border-radius: var(--radius-md);
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

/* Hidden from sight, still read aloud. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


/* --------------------------------------------------------------------------
   6. Interactive elements — 44px minimum
   --------------------------------------------------------------------------
   Grounding section 8: tap targets 44px minimum. The audience is on a phone,
   on their feet, sometimes in the rain.
   -------------------------------------------------------------------------- */

button,
[type="button"],
[type="submit"],
[type="reset"],
select,
summary,
.button {
  min-height: var(--tap-min);
  min-width: var(--tap-min);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs) var(--space-md);
  font-family: var(--font-ui);
  font-size: var(--size-body);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  text-align: center;
  text-decoration: none;
  border-radius: var(--radius-md);
  border: 2px solid transparent;
  cursor: pointer;
  /* Never let a label be clipped to fit a fixed height. */
  height: auto;
}

/* Primary action: navy ground, cream label — 12.49:1.
   NOT sage with a cream label, which measures 3.34:1 and fails AA. */
button,
[type="button"],
[type="submit"],
.button--primary {
  background-color: var(--action-primary-bg);
  color: var(--action-primary-text);
  border-color: var(--action-primary-bg);
}

.button--secondary,
[type="reset"] {
  background-color: var(--action-secondary-bg);
  color: var(--action-secondary-text);           /* 12.19:1 */
  border-color: var(--action-secondary-border);
}

/* On a navy band both button styles have to invert.

   Section 7 gives headings, links, eyebrows and muted text an on-navy
   colour. Buttons were missing from that list entirely, and the result was
   not low contrast — it was an invisible control. Measured on the band:

     BEFORE  secondary label    navy on navy         1.00:1   invisible
     BEFORE  secondary border   navy on navy         1.00:1   invisible
     BEFORE  primary boundary   navy fill on navy    1.00:1   SC 1.4.11 fail

   The primary's LABEL was always fine at 12.49:1, but its fill and border
   are the only thing saying "this is a control", so the boundary is what
   carries the 3:1 requirement, and the boundary was not there.

   Both rules below use the one pair already measured safe on this ground —
   cream-on-navy #F7F5EC against navy #1C2E4A at 12.49:1. No new colour is
   invented, and no prohibited pair from tokens.css is reached for:

     AFTER   secondary label    cream on navy       12.49:1
     AFTER   secondary border   cream on navy       12.49:1
     AFTER   primary boundary   cream fill on band  12.49:1
     AFTER   primary label      navy on cream fill  12.49:1

   The primary inverts rather than keeping its navy fill and gaining a cream
   outline: outlined-versus-filled is what tells the two buttons apart, and
   grounding section 8 forbids colour alone as the signal. Swapping the
   primary's two colours keeps it the filled one on both grounds.

   The focus ring is unaffected — it lands on the band, outside the button,
   where sage-light measures 5.85:1. */
.surface-inverse
  :is(button, [type="button"], [type="submit"], .button--primary) {
  /* the primary's two colours simply change places */
  background-color: var(--action-primary-text);  /* cream fill            */
  color: var(--action-primary-bg);               /* navy label, 12.49:1   */
  border-color: var(--action-primary-text);      /* 12.49:1 vs the band   */
}

.surface-inverse :is(.button--secondary, [type="reset"]) {
  background-color: var(--action-secondary-bg);  /* transparent           */
  color: var(--text-on-inverse);                 /* 12.49:1               */
  border-color: var(--text-on-inverse);          /* 12.49:1 — the only
                                                    affordance there is   */
}

/* ...and a button inside a light surface nested in that band is a light
   button again. Same leak as the focus ring in section 5: the two rules
   above are unscoped descendant selectors, so without these a secondary
   button on a .card inside a navy band paints a cream label on cream at
   1.01:1, and an inverted primary paints a cream fill on cream at 1.01:1. */
.surface-inverse
  :is(.card, .band-tint, .pill)
  :is(button, [type="button"], [type="submit"], .button--primary) {
  background-color: var(--action-primary-bg);
  color: var(--action-primary-text);             /* 12.49:1 on the fill   */
  border-color: var(--action-primary-bg);
}

.surface-inverse
  :is(.card, .band-tint, .pill)
  :is(.button--secondary, [type="reset"]) {
  background-color: var(--action-secondary-bg);
  color: var(--action-secondary-text);           /* 12.62:1 on the card   */
  border-color: var(--action-secondary-border);
}

button:disabled,
.button[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Form controls.
   Border is --border-control (5.96:1), not the decorative card border
   (#EAE7D8, 1.11:1) — on an input the outline is the only thing that says
   "you can type here", so SC 1.4.11's 3:1 applies to it. */
input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),
textarea,
select {
  min-height: var(--tap-min);
  width: 100%;
  padding: var(--space-2xs) var(--space-xs);
  font-size: var(--size-body);        /* 18px stops iOS zooming on focus */
  color: var(--text-body);
  background-color: var(--surface-raised);
  border: 2px solid var(--border-control);
  border-radius: var(--radius-md);
}

input::placeholder,
textarea::placeholder {
  color: var(--text-muted);           /* 6.17:1 on the raised surface */
  opacity: 1;                         /* Firefox dims placeholders by default */
}

/* Checkboxes and radios carry the full 44px themselves, in both axes.

   These were 1.5rem (24px), with .choice below cited as the mitigation. The
   mitigation was not real. .choice supplies min-height only, so the target
   stayed 24px wide however tall the row got, and nothing in CSS can make a
   template author wrap the control in .choice or make .choice a <label>.

   WCAG 2.2 SC 2.5.8 would have accepted 24x24 at AA. Grounding section 8
   does not: "Tap targets 44px minimum", no exception. That is the stricter
   number and it is the one that applies here, for the same reason --tap-min
   in tokens.css reasons in physical terms rather than in success criteria —
   44px is a fingertip measure, and this audience is 50-70 and 75+, on a
   phone, sometimes in the rain.

   So the floor is put where it cannot be forgotten. A rule that holds only
   when someone remembers to add a wrapper class is the rule that quietly
   stops holding six months from now; the type scale in tokens.css declines
   to offer a 15px step for exactly the same reason.

   var(--tap-min) is max(2.75rem, 44px): it grows with the reader's font
   size, and never drops under 44px for someone whose base size is small. */
[type="checkbox"],
[type="radio"] {
  width: var(--tap-min);
  height: var(--tap-min);
  accent-color: var(--navy);
  flex: none;
}

label {
  display: inline-block;
  font-weight: var(--weight-semibold);
  color: var(--text-body);
}

/* A checkbox or radio and its label on one row.

   Layout only. This is no longer what delivers the 44px target — the control
   above does that on its own, in both axes, whether or not anyone remembers
   this class. Use a <label> for the row so the text joins the control's hit
   area; the min-height then only keeps short rows from collapsing. */
.choice {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  min-height: var(--tap-min);
  cursor: pointer;
}

.field + .field {
  margin-top: var(--space-md);
}

.field > label {
  margin-bottom: var(--space-3xs);
}


/* --------------------------------------------------------------------------
   7. Layout
   --------------------------------------------------------------------------
   Fluid first. At 320px this is a single column with 16px gutters; the
   maximum width only starts mattering well above the 390px design width.
   -------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  /* D-096. base.html's viewport says viewport-fit=cover, so the tab bar can
     sit above a phone's home indicator — and that also lets the page run
     under the rounded corners and the camera notch of a phone on its side.
     The side insets are zero in portrait, so this is the ordinary gutter
     there, and the inset wherever the inset is wider. */
  padding-inline:
    max(var(--container-pad), env(safe-area-inset-left, 0px))
    max(var(--container-pad), env(safe-area-inset-right, 0px));
}

.stack > * + * {
  margin-top: var(--space-md);
}

main {
  padding-block: var(--space-lg);
}

/* SURFACES DESCRIBE THEMSELVES.

   Every class below that sets a background-color also sets a colour. A
   surface that sets only a background inherits whatever text colour it
   happens to land in — harmless on the page ground, wrong everywhere else.
   A .card inside the navy band below used to inherit --text-on-inverse and
   paint #F7F5EC on #F8F6EF at 1.01:1; .band-tint did the same at 1.07:1.
   That is invisible text, not merely low contrast.

   Scoping the on-navy rules to direct children was the alternative, and it
   is the weaker one: it fixes the single depth of nesting somebody thought
   of, and fails the moment a card sits inside a .container or a .stack,
   which is the ordinary way these are used. A surface carrying its own
   colour is correct at any depth, inside any wrapper. .pill below already
   worked this way, which is why it never showed the fault. */

.card {
  background-color: var(--surface-raised);
  color: var(--text-body);                /* 10.13:1 on the raised surface */
  border: 1px solid var(--border-soft);   /* decorative: the fill identifies it */
  border-radius: var(--radius-lg);
  padding: var(--space-md);
  box-shadow: var(--shadow-card);
}

.band-tint {
  background-color: var(--surface-tint);
  color: var(--text-body);                /* 9.41:1 on the tint */
}

/* Navy band. Sets its own text colour so anything nested inherits a legible
   one rather than inheriting --text-body onto a dark ground. */
.surface-inverse {
  background-color: var(--surface-inverse);
  color: var(--text-on-inverse);          /* 12.49:1 */
}

.surface-inverse :is(h1, h2, h3, h4, h5, h6) {
  color: var(--text-on-inverse);
}

.surface-inverse a {
  color: var(--link-on-inverse);
}

.surface-inverse .eyebrow {
  color: var(--text-on-inverse-accent);   /* sage-light, 5.85:1 */
}

.surface-inverse .text-muted {
  color: var(--text-on-inverse-soft);     /* 9.74:1 */
}

/* A light surface nested in the band restores the light palette explicitly.

   The colour on .card and .band-tint above fixes inherited text, and that is
   as far as inheritance can go: the four rules immediately above — and the
   focus rule in section 5 — set colour ON the element, so a nested heading,
   link, eyebrow, muted span or focus ring never inherits anything and stays
   on-navy over a cream ground. Measured inside the band, before -> after:

     heading      #F7F5EC on card   1.01 -> navy      12.62
                  #F7F5EC on tint   1.07 -> navy      11.73
     link         #F7F5EC on card   1.01 -> navy      12.62
                  #F7F5EC on tint   1.07 -> navy      11.73
     .text-muted  #D7DAE0 on card   1.30 -> ink-muted  6.17
                  #D7DAE0 on tint   1.20 -> ink-muted  5.73
     .eyebrow     #A4B06B on card   2.16 -> ink-muted  6.17
                  #A4B06B on tint   2.00 -> ink-muted  5.73

   The eyebrow loses its sage-light accent inside a nested surface, and that
   is deliberate rather than a compromise: sage-light is an on-navy colour
   and measures 2.16:1 on cream, under even the large-text bar. tokens.css
   records that pair as prohibited.

   Scoped to .surface-inverse, not written unconditionally, so it can only
   fire where there is a leak to undo. That also leaves the reverse nesting —
   a navy band inside a card — rendering on-navy, which is correct. */
.surface-inverse :is(.card, .band-tint, .pill) :is(h1, h2, h3, h4, h5, h6) {
  color: var(--text-strong);
}

/* The second selector is for a surface that IS itself the link — the common
   case being <a class="pill"> used as a filter chip. Without it,
   --link-on-inverse paints #F7F5EC on the pill's own tint at 1.07:1. */
.surface-inverse :is(.card, .band-tint, .pill) a,
.surface-inverse a:is(.card, .band-tint, .pill) {
  color: var(--link);
}

.surface-inverse :is(.card, .band-tint, .pill) .eyebrow,
.surface-inverse :is(.card, .band-tint, .pill) .text-muted {
  color: var(--text-muted);
}

.pill {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);             /* interactive pills; static ones may
                                             drop this via .pill--static */
  padding: var(--space-3xs) var(--space-xs);
  background-color: var(--surface-tint);
  color: var(--text-body);                /* 9.41:1 on the tint */
  font-family: var(--font-ui);
  font-size: var(--size-body);
  font-weight: var(--weight-semibold);
  border-radius: var(--radius-pill);
}

.pill--static {
  min-height: 0;
}

/* The one <hr> in the application, templates/office/home.html:152, between
   the people and the rest of the office. It was 1px of --border-soft, which
   is 1.109:1 against the page — a separator nobody can see. It takes the same
   mark the office gives a section heading (office.css §3a): --accent at
   --space-3xs, 3.26:1, pill-ended, left-aligned where reading starts.
   `margin-inline: 0` is load-bearing — the UA sheet centres an hr.
   48 above and 24 below, 2:1, so the mark belongs to what follows it. */
hr {
  border: 0;
  inline-size: var(--space-xl);             /* 48px */
  block-size: var(--space-3xs);             /*  4px */
  margin-inline: 0;
  margin-block: var(--space-xl) var(--space-md);
  border-radius: var(--radius-pill);
  background-color: var(--accent);          /* 3.26:1 on the page ground */
}

/* THE 48 ABOVE HAS TO OUTRANK THE STACK, FOR THE SAME REASON office.css §3a
   spells out for a section. The only <hr> in the application is a direct
   child of <main class="container stack">, so `.stack > * + *` at (0,1,0)
   beats a bare `hr` at (0,0,1) and quietly held the gap above the mark at
   --space-md — 24 above and 24 below, which is not the 2:1 the comment above
   claims and leaves the mark belonging to neither side. This is the same
   selector shape at (0,1,1), so it wins on specificity rather than on being
   further down the file. `* + hr` and not `hr`, so an <hr> that opened a
   screen would not be pushed away from nothing. */
.stack > * + hr {
  margin-block-start: var(--space-xl);      /* 48px */
}


/* THE FOOTER. One link, on every signed-in screen — see the long comment in
   templates/base.html for why it exists at all, which is the more important
   half of this.

   IT IS IN base.css AND NOT components.css ON PURPOSE. This file says at the
   top of itself that its scope is "a modern reset, page furniture, and the
   accessibility floor", and that components arrive with the screens that need
   them. A footer rendered by the skeleton on every single page is the
   definition of page furniture; it belongs to no screen, so there is no screen
   for it to arrive with. Putting it in components.css would have worked and
   would have said the wrong thing about what it is.

   --surface-footer (navy-dark) exists in tokens.css, is used by nothing, and
   is deliberately NOT used here. A full-width dark band at the bottom of every
   page is the marketing site's footer, and it reads as a footer with a column
   of links in it — six things a family member then hunts through. There is one
   link. A quiet raised strip with a hairline above it separates it from the
   content, which is the whole job.

   --surface-raised carries its own colour, exactly as .card and .band-tint do
   above and for the same reason: a surface that sets only a background
   inherits whatever text colour it happens to land in. --text-body on the
   raised surface is 10.13:1. */
.site-footer {
  background-color: var(--surface-raised);
  color: var(--text-body);
  border-top: 1px solid var(--border-soft);
  padding-block: var(--space-sm);
}

/* Bold, the same weight `.back-link` gives the way back, because this is a
   target rather than a reference — and on a cream strip under a page of body
   copy the underline alone is easy to walk past. The 44px comes from
   .tap-link in section 4; nothing here sizes it. */
.site-footer a {
  font-weight: var(--weight-bold);
}


/* --------------------------------------------------------------------------
   8. Wider screens
   --------------------------------------------------------------------------
   min-width only. Everything above this point is the 320–390px layout.
   -------------------------------------------------------------------------- */

@media (min-width: 40em) {          /* ~640px */
  :root {
    --container-pad: var(--space-md);
  }

  h1 {
    font-size: var(--size-3xl);
  }

  main {
    padding-block: var(--space-xl);
  }

  .card {
    padding: var(--space-lg);
  }
}

@media (min-width: 64em) {          /* ~1024px */
  :root {
    --container-max: 48rem;
  }
}


/* --------------------------------------------------------------------------
   9. Reduced motion
   --------------------------------------------------------------------------
   Honours the operating-system setting. Durations collapse to near zero
   rather than to zero, so anything relying on a transitionend event still
   fires and does not leave the interface stuck mid-state.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }

  a,
  button,
  .button {
    transition: background-color var(--motion-fast) var(--motion-ease),
                color var(--motion-fast) var(--motion-ease),
                border-color var(--motion-fast) var(--motion-ease);
  }
}


/* --------------------------------------------------------------------------
   10. Forced colours (Windows high contrast)
   -------------------------------------------------------------------------- */

@media (forced-colors: active) {
  button,
  [type="button"],
  [type="submit"],
  .button {
    border: 2px solid ButtonText;
  }

  :focus-visible {
    outline: 3px solid Highlight;
  }

  /* The separator above is a background, and forced colours discards a
     background — which would take the whole mark with it. Same reason and
     same keyword as office.css §3a's section stub. */
  hr {
    background-color: CanvasText;
  }
}


/* --------------------------------------------------------------------------
   11. Print — a family member printing a visit log to take to a relative
   -------------------------------------------------------------------------- */

@media print {
  body {
    /* Paper is white; the cream ground would only waste ink. The text stays
       the brand ink rather than pure black — no colour is invented here. */
    background: white;
    color: var(--ink);
  }

  .skip-link,
  nav,
  /* Somebody printing a visit log to take to a relative is printing the visit
     log. "How I let you know" is an on-screen control that does nothing on
     paper, and it would be the last line of every printed page. */
  .site-footer {
    display: none;
  }

  .card {
    box-shadow: none;
    border: 1px solid var(--ink-muted);
  }

  /* A printed page loses every href, so put the target back in the text. */
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: var(--size-body);
    word-break: break-all;
  }
}
