/* === tokens.css === */
/*
 * tokens.css — every colour, measure, weight and rhythm the site knows.
 *
 * Nothing in this file selects anything. It exists so that a value lives in
 * exactly one place: the mockup carried two different border colours on the
 * same input and three different greys for "muted text", because each block
 * was typed from memory. If you are about to write a literal colour, size or
 * duration in any other file, it belongs here instead.
 */

:root {

  /* --- Ground ---------------------------------------------------------- */
  --paper: #FFF8EE;          /* cream calico, the page ground */
  --paper-raised: #FFFDF8;   /* panel and field fill, a shade above the page */
  --linen: #F6E3C8;          /* warm second ground, and the hairline rule */

  /* --- Ink ------------------------------------------------------------- */
  --ink: #2B2440;
  --ink-soft: #5B5170;       /* 6.9:1 on --paper — safe for body and captions */
  /* --ink-faint measures 3.4:1 on --paper and 2.9:1 on --linen. That fails AA
     for body copy outright and does not even clear the 3:1 floor for a rule on
     the warm ground, so nothing in this stylesheet uses it: captions take
     --ink-soft and hairlines take --tan. It stays declared because it is part
     of the approved palette. Do not promote it to text. */
  --ink-faint: #8C82A8;
  --on-ink: #FFF8EE;
  --on-ink-soft: #C9C2DC;    /* 8.6:1 on --ink */

  /* --- Thread colours, taken off the actual bears ----------------------- */
  --gold: #FFC93C;           /* the sun hat, the yellow pinafore */
  --gold-deep: #DDA518;
  --gold-light: #FFE08A;
  --coral: #FF6B6B;          /* the red bias binding, the nurse's cross */
  --coral-deep: #D94A4A;     /* 4.1:1 on the panel fill: fine as an edge, not as text */
  /* The same coral taken down until it is safe to read. --coral-deep is used
     for the error edges and thread, where 4.1:1 clears the 3:1 floor for a
     non-text line; the error MESSAGE and the eyebrow are text at 11–17px and
     need 4.5:1, which this clears at 6.5:1. Two values because they are two
     different jobs, not because anybody forgot. */
  --coral-ink: #A83232;
  --coral-light: #FF9A8B;
  --sky: #C7EEFB;            /* the cot-sheet print */
  --sky-mid: #7BD6F0;
  --sky-deep: #14607C;
  --grape: #7C5CD6;          /* the ribbon bow */
  --grape-deep: #5B3FB0;
  --grape-light: #C3B0F5;
  --tan: #A0714B;            /* the hairlines inside a care label, 3.4:1 on --linen */
  /* Approved as #C2410C, which is 4.9:1 on --paper but only 4.1:1 on --linen —
     and both the "Fresh off the machine" strip and the whole enquiry page are
     linen grounds, so links there would have shipped under AA. Darkened here
     along the same hue to 6.3:1 on paper and 5.3:1 on linen. */
  --link: #A8340B;

  /* --- Type ------------------------------------------------------------- */
  /* Both faces are loaded once in partials/head.php. The fallbacks matter:
     Google Fonts is a third-party request and it does fail. */
  --font-display: 'Baloo 2', 'Trebuchet MS', 'Segoe UI', system-ui, sans-serif;
  --font-body: Karla, 'Segoe UI', system-ui, -apple-system, sans-serif;

  --size-body: 1.0625rem;    /* 17px — the floor is 16px, this sits above it */
  --size-small: 0.9375rem;
  --lh-body: 1.6;
  --lh-display: 1.05;

  /* The third register, and the only one: the woven care label voice. Every
     .label, chip, eyebrow, caption and legal line reads in exactly this. */
  --label-size: 0.72rem;
  --label-weight: 700;
  --label-track: 0.16em;

  /* --- Measure and gutters ---------------------------------------------- */
  --wrap: 72rem;
  --gutter: clamp(1.25rem, 5vw, 4.5rem);
  --measure: 60ch;           /* body copy cap */
  --measure-tight: 46ch;     /* lead paragraphs and panel copy */

  /* --- Vertical rhythm --------------------------------------------------- */
  /* Section spacing is set by .band in layout.css and by nothing else. */
  --band-space: clamp(3.5rem, 7vw, 6.25rem);
  --stack: clamp(1rem, 2vw, 1.5rem);
  --stack-tight: 0.6rem;
  --grid-gap: clamp(1.25rem, 3vw, 2.25rem);

  /* --- The seam ---------------------------------------------------------- */
  /* One rhythm for every stitch on the site, so every seam reads as the same
     hand. Change these four and the whole site is re-sewn at once. */
  --stitch-dash: 6px;
  --stitch-gap: 4px;
  --stitch-weight: 2.5px;
  --stitch-inset: 6px;       /* how far the stitch sits in from the panel edge */
  /* One period of the running stitch, and what every hover marches by. DERIVED,
     not typed: written as a literal it silently stops matching the moment
     anyone changes the dash or the gap, and the stitch then reads as a broken
     rhythm that no single value in this file explains. */
  --stitch-period: calc(var(--stitch-dash) + var(--stitch-gap));
  --thread: var(--ink);      /* per-component override; grounds flip it */
  /* The two ready-made runs of stitch built from these, --stitch-h and
     --stitch-v, are declared in seam.css and not here. They have to be
     re-declared per element to pick up that element's --thread, which means a
     selector, and this file selects nothing. */

  --edge: 2px;               /* the solid panel edge the stitch sits inside */
  --radius: 1.125rem;
  --radius-sm: 0.5rem;
  --radius-pill: 999px;

  /* --- Focus ------------------------------------------------------------- */
  /* 6.8:1 on --paper. Coloured grounds flip it in layout.css. */
  --focus: var(--grape-deep);

  /* --- Motion ------------------------------------------------------------ */
  --speed: 140ms;            /* hover and focus only — 150ms is the ceiling */
  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);
  --settle: 480ms;           /* the one orchestrated moment, in hero.css */
}

/* === base.css === */
/*
 * base.css — element defaults and the two document-level pieces of furniture
 * (the skip link and the focus ring).
 *
 * Everything here is unclassed. If a rule needs a class name it belongs in the
 * file for that component.
 */

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

/* Author margins only. Every spacing decision on this site is deliberate and
   comes from a token; inherited UA margins are how two sections end up with
   different gaps for no reason anybody can name. */
body, h1, h2, h3, p, ul, ol, dl, dd, figure, fieldset, legend {
  margin: 0;
}

ul, ol {
  padding: 0;
  list-style: none;
}

fieldset {
  padding: 0;
  border: 0;
  min-inline-size: 0;   /* fieldsets refuse to shrink in a grid without this */
}

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

/*
 * A column the height of the viewport, so the footer can be pushed to the
 * bottom of a short page. The 404 is three sentences long and without this its
 * ink footer floats halfway up the screen with paper underneath it, which
 * looks like the page failed to load rather than like a page.
 */
body {
  display: flex;
  flex-direction: column;
  min-block-size: 100svh;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--size-body);
  font-weight: 400;
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* slap_img() always emits width and height, so the intrinsic ratio is known
   before the file arrives. These two lines are what stop that ratio from
   forcing the image past its column. */
img {
  max-width: 100%;
  height: auto;
  display: block;
}

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

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

strong {
  font-weight: 700;
}

/* Inputs do not inherit type. Everything the enquiry form renders is a real
   control, so this is not cosmetic. */
input, textarea, select, button {
  font: inherit;
  color: inherit;
}

textarea {
  resize: vertical;
}

::selection {
  background: var(--gold);
  color: var(--ink);
}

/* One ring, everywhere, on whichever ground the element sits on: coloured
   bands re-point --focus rather than each component inventing its own. */
:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
}

/*
 * The skip link. Off-screen rather than display:none, so it stays in the tab
 * order and in the accessibility tree; it only becomes visible once it has
 * focus, which is the moment it is useful.
 */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
}

.skip:focus {
  left: var(--gutter);
  top: 0.75rem;
  z-index: 20;
  padding: 0.75rem 1.25rem;
  background: var(--ink);
  color: var(--on-ink);
  text-decoration: none;
  border-radius: var(--radius-sm);
  font-weight: 700;
}

/* === layout.css === */
/*
 * layout.css — the measure, the section rhythm, and the section-level furniture
 * that sits directly inside a band.
 *
 * SPECIFICITY DISCIPLINE: .band is the ONLY rule in the whole stylesheet that
 * sets section-level vertical spacing. Modifiers (.band--ink, .band--coral) and
 * the per-page section classes (.gallery, .recent, .cta, .enquiry, .page-head)
 * change ground, thread and colour and nothing else. The moment a second rule
 * sets padding-block on a section, the two start cancelling each other and the
 * fix is always another rule on top — which is how a stylesheet acquires
 * override flags. There are none anywhere in this system, by design.
 */

.wrap {
  inline-size: 100%;
  max-inline-size: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.band {
  padding-block: var(--band-space);
}

/* A page head and the section under it are one block of content, so the two
   rhythms between them collapse to one. Coloured bands are excluded: a ground
   change needs its full run-in or the colour looks like it slipped. */
.page-head + .band:not(.band--ink):not(.band--coral) {
  padding-block-start: 0;
}

.band--ink {
  background: var(--ink);
  color: var(--on-ink);
  --thread: var(--on-ink-soft);
  --focus: var(--gold);
}

.band--coral {
  background: var(--coral);
  color: var(--ink);
  --thread: var(--ink);
  --focus: var(--ink);
}

/* --- Page head ---------------------------------------------------------- */

.page-head .lead {
  margin-block-start: var(--stack);
}

/* --- Section head: a title with a link parked at the end of its line ----- */

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--stack-tight) var(--stack);
  margin-block-end: var(--grid-gap);
}

/* --- Home: the recent strip --------------------------------------------- */

.recent {
  background: var(--linen);
}

/* --- Gallery ------------------------------------------------------------- */

/* Photographs need more air between them than blocks of text do: at the default
   gap the bear panels start reading as one contact sheet rather than as nine
   separate bears. */
.gallery {
  --grid-gap: clamp(1.5rem, 3.5vw, 2.75rem);
}

.gallery__count {
  margin-block-end: var(--grid-gap);
  color: var(--ink-soft);
  font-size: var(--size-small);
}

/* --- Enquiry ------------------------------------------------------------- */

/* The warm ground is what lifts the form panel off the page: the panel fill is
   only a shade above paper, and on paper the form has no edge worth seeing. */
.enquiry {
  background: var(--linen);
}

.enquiry__grid {
  display: grid;
  gap: var(--grid-gap);
}

.enquiry__intro .lead {
  margin-block-start: var(--stack);
}

/* Grid children default to min-width: auto, which means one unbreakable string
   in the textarea would widen the column and push the page sideways. */
.enquiry__form {
  min-inline-size: 0;
}

@media (min-width: 60rem) {
  .enquiry__grid {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: clamp(2rem, 5vw, 4.5rem);
    align-items: start;
  }
}

/* --- The closing call to action ------------------------------------------ */

/* The CTA is the one block that appears on every page, and it has to set in
   the same shape on all of them — hence its own measure rather than whatever
   the surrounding page happens to be using. */
.cta {
  --measure-tight: 44ch;
}

.cta__inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--stack);
}

.cta__title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(1.75rem, 4vw, 2.75rem);
  line-height: var(--lh-display);
  letter-spacing: -0.02em;
  max-inline-size: 18ch;
}

.cta__copy {
  max-inline-size: var(--measure-tight);
}

@media (min-width: 60rem) {
  .cta__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    column-gap: clamp(2rem, 5vw, 4rem);
  }

  /* The button rides on the second column under the copy, so the eye lands on
     the sentence and then on the thing to press, not the other way round. */
  .cta__title {
    grid-row: span 2;
    align-self: center;
  }

  /* Grid items stretch by default and a full-column-wide button reads as a
     banner rather than a button. */
  .cta__inner .btn {
    justify-self: start;
  }
}

/* === seam.css === */
/*
 * seam.css — THE signature.
 *
 * A memory bear is a garment taken apart and put back together, so every
 * structural edge on this site is a running stitch. Never a drop shadow, never
 * an offset block, never a fake 3D lip on a button. That is the one bold idea
 * and it lives entirely in this file, so there is exactly one place to change
 * the hand that sewed the site.
 *
 * WHY THE STITCH IS DRAWN AND NOT `border-style: dashed`
 * ------------------------------------------------------
 * A dashed border lets the browser choose the dash length so that a whole
 * number of dashes fits each edge. The length therefore changes with the size
 * of the box, every engine picks differently, and a run of short even dashes
 * reads as a discount coupon rather than as thread. Drawing the dashes with
 * repeating-linear-gradient fixes the rhythm: --stitch-dash of thread, then
 * --stitch-gap of nothing, at --stitch-weight thick, identically on every
 * component at every size.
 *
 * All three primitives paint on a pseudo-element with pointer-events: none, so
 * nothing here can ever swallow a click or a hover.
 */

/* --- 0. The stitch itself ------------------------------------------------ */
/*
 * One run of running stitch, horizontal and vertical. EVERY seam on this site
 * is one or more of these two values and nothing else — before they existed the
 * same gradient was retyped 29 times across 8 files, which is 29 chances for
 * one component's rhythm to drift from the rest.
 *
 * WHY `*` AND NOT `:root`. A var() inside a custom property is substituted
 * where that property is DECLARED, not where it is used. Declared once on
 * :root these would bake in :root's --thread (ink) and inherit that literal
 * everywhere, so .band--ink, .chip--gold, .field--error and every other
 * re-threading would be silently ignored — the seams would all come out ink and
 * nothing would look broken enough to notice. Declaring them on every element
 * lets each one resolve its own --thread. Specificity 0, so any component rule
 * still wins on --thread itself.
 */
* {
  --stitch-h: repeating-linear-gradient(90deg, var(--thread) 0 var(--stitch-dash), transparent var(--stitch-dash) var(--stitch-period));
  --stitch-v: repeating-linear-gradient(180deg, var(--thread) 0 var(--stitch-dash), transparent var(--stitch-dash) var(--stitch-period));
}

/* --- 1. The stitched panel ---------------------------------------------- */

.panel-stitched {
  position: relative;
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  border: var(--edge) solid var(--thread);
  border-radius: var(--radius);
  background: var(--paper-raised);
}

.panel-stitched::after {
  content: "";
  position: absolute;
  inset: var(--stitch-inset);
  border-radius: calc(var(--radius) - var(--stitch-inset));
  pointer-events: none;

  /* Four separate lines, one per edge, rather than one repeating border: the
     corners then meet as two stitches crossing, which is how a seam actually
     turns a corner. The border-radius above clips them so the crossing sits
     inside the rounded corner instead of poking out of it. */
  background-image:
    var(--stitch-h),
    var(--stitch-h),
    var(--stitch-v),
    var(--stitch-v);
  background-size:
    100% var(--stitch-weight),
    100% var(--stitch-weight),
    var(--stitch-weight) 100%,
    var(--stitch-weight) 100%;
  background-position:
    left top,
    left bottom,
    left top,
    right top;
  background-repeat: no-repeat;
}

/* --- 2. The section seam -------------------------------------------------- */
/*
 * One running stitch across a section boundary. .masthead carries the bottom
 * one, .cta and .footer the top one. The thread colour comes from the ground
 * the seam lands on, which the band modifiers in layout.css already set.
 */

.seam-top,
.seam-bottom {
  position: relative;
}

.seam-top::before,
.seam-bottom::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  block-size: var(--stitch-weight);
  pointer-events: none;
  background-image:
    var(--stitch-h);
}

.seam-top::before {
  inset-block-start: var(--stitch-inset);
}

.seam-bottom::before {
  inset-block-end: var(--stitch-inset);
}

/* --- 3. The appliquéd patch ---------------------------------------------- */
/*
 * A scrap of gold fabric sewn onto the headline, used on the word "jersey" and
 * on the brand mark. It is inline-block so it wraps with the line rather than
 * breaking it, and the padding is deliberately mean: a patch with generous
 * padding stops being a patch and starts being a highlighter.
 *
 * `rotate` rather than `transform: rotate()` because hero.css animates the
 * headline's `translate` on load, and the independent transform properties do
 * not overwrite each other the way two `transform` declarations would.
 */

.patch {
  position: relative;
  display: inline-block;
  padding: 0.02em 0.3em 0.08em;
  border-radius: var(--radius-sm);
  background: var(--gold);
  color: var(--ink);
  rotate: -1.5deg;
  --thread: var(--ink);
}

/* .brand__patch is the same object cut square for the masthead. Its geometry
   lives in nav.css; the stitch on it is THIS stitch, listed here rather than
   retyped there — the two blocks were byte-identical copies of each other. */
.patch::after,
.brand__patch::after {
  content: "";
  position: absolute;
  inset: 4px;
  border-radius: 3px;
  pointer-events: none;
  background-image:
    var(--stitch-h),
    var(--stitch-h),
    var(--stitch-v),
    var(--stitch-v);
  background-size:
    100% var(--stitch-weight),
    100% var(--stitch-weight),
    var(--stitch-weight) 100%,
    var(--stitch-weight) 100%;
  background-position: left top, left bottom, left top, right top;
  background-repeat: no-repeat;
}

/* === type.css === */
/*
 * type.css — three registers and nothing else.
 *
 *   display  Baloo 2 800/600, tight and confident, for headlines only
 *   body     Karla 400–700 at 17px / 1.6, capped at --measure
 *   label    Karla 700, 0.72rem, uppercase, 0.16em tracking — the woven care
 *            label voice, and the ONLY third register on the site
 *
 * A fourth register is how a small site starts looking like a template. If a
 * piece of text does not fit one of these three, the fix is the words.
 */

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 800;
  line-height: var(--lh-display);
  letter-spacing: -0.02em;
}

.page-title {
  font-size: clamp(2.25rem, 5vw, 3.5rem);
  letter-spacing: -0.03em;
  max-inline-size: 16ch;
}

.section-title {
  font-size: clamp(1.75rem, 3.2vw, 2.5rem);
  max-inline-size: 18ch;
}

.lead {
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
  line-height: 1.55;
  color: var(--ink-soft);
  max-inline-size: var(--measure-tight);
}

/* Body copy on a coloured ground cannot keep using the muted ink — it was
   chosen for contrast against paper. */
.band--ink .lead,
.band--coral .lead {
  color: inherit;
}

/*
 * The label register. Everything that speaks in it — .label itself, .eyebrow,
 * the chips, the care-label captions, the footer legal line — reads these same
 * three tokens, so the voice cannot drift between components.
 */
.label {
  font-family: var(--font-body);
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  line-height: 1.4;
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--ink-soft);
}

.band--ink .label {
  color: var(--on-ink-soft);
}

.eyebrow {
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  line-height: 1.4;
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--coral-ink);
  margin-block-end: var(--stack);
}

/*
 * .link-arrow — a link with the seam under it instead of an underline. The
 * stitch marches one period to the right on hover: the site's single permitted
 * micro-interaction, and it is the same thread as every other edge.
 */
.link-arrow {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  /* The top padding is the 44px thumb target and nothing else — it is taken
     ABOVE the words on purpose. Growing the box downwards, or with
     min-block-size, would drag the seam away from the text it underlines, and
     the seam sitting tight under the word is the whole device. Padding does not
     move a baseline, so this cannot disturb the baseline alignment .section-head
     relies on either. */
  padding-block: 0.7rem 0.35em;
  font-weight: 700;
  text-decoration: none;
  color: var(--link);
  /* This one seam is sewn in the link's own colour rather than the page thread:
     it is an underline, and an underline in a different colour from the word
     above it reads as two things. --thread is re-pointed rather than the
     gradient rewritten, so it is still the one stitch from tokens.css. */
  text-decoration: underline;
  text-underline-offset: 0.25em;
  text-decoration-thickness: 2px;
  transition: color var(--speed) var(--ease);
}

.link-arrow::after {
  content: "\2192";
  font-weight: 400;
}

.link-arrow:hover {
  color: var(--ink);
  background-position: var(--stitch-period) bottom;
}

.band--ink .link-arrow,
.band--coral .link-arrow {
  color: inherit;
}

/* === button.css === */
/*
 * button.css
 *
 * The affordance is the ground and the stitch. Explicitly NOT a fake 3D lip
 * (box-shadow: 0 5px 0) and NOT an offset block shadow — those were the
 * mockup's devices, they belong to a different site, and a button that pretends
 * to be 5px tall has to pretend to be pressed as well, which is two lies to
 * maintain instead of none.
 *
 * On hover the stitch marches one full period sideways. That is the whole
 * interaction, it is the same thread as every seam on the site, and it costs
 * one animatable property.
 */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  padding: 0.85em 1.6em;
  /* At 15px/1.2 the padding above lands the button at ~43.5px, which is a hair
     under the 44px thumb target. This sets the floor without touching the
     padding the stitch inset is tuned to. */
  min-block-size: 2.75rem;
  border: var(--edge) solid var(--thread);
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--size-small);
  line-height: 1.2;
  letter-spacing: 0.01em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  background: transparent;
  color: var(--ink);
  transition: background-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

/* --- Variants: ground and thread only ----------------------------------- */

/* Gold thread, but NOT a gold focus ring. The ring is drawn 3px outside the
   button, which means it lands on the cream page, where gold measures 1.5:1 and
   effectively disappears. The ground a ring sits on is the page behind the
   element, not the element — so this keeps the page's own --focus. */
.btn--ink {
  background: var(--ink);
  color: var(--on-ink);
  --thread: var(--gold);
}

.btn--ink:hover {
  background: var(--grape-deep);
  color: var(--on-ink);
}

/* Ink on coral is 5.3:1 — the coral button keeps dark text rather than white,
   which would be 2.6:1 and unreadable in daylight on a phone. */
.btn--coral {
  background: var(--coral);
  color: var(--ink);
  --thread: var(--ink);
}

.btn--coral:hover {
  background: var(--coral-light);
  color: var(--ink);
}

.btn--ghost {
  background: transparent;
  color: var(--ink);
  --thread: var(--ink);
}

.btn--ghost:hover {
  background: var(--linen);
  color: var(--ink);
}

/* Sits on the coral band, so it needs its own ground rather than inheriting. */
.btn--paper {
  background: var(--paper);
  color: var(--ink);
  --thread: var(--ink);
}

.btn--paper:hover {
  background: var(--gold);
  color: var(--ink);
}

/* === nav.css === */
/*
 * nav.css — the masthead, the primary menu, and the chip.
 *
 * The chip lives here rather than in panel.css because there is only one chip:
 * the gallery filter links and the two route kind-labels are the same object
 * doing the same job, and giving them two definitions is how they end up two
 * different sizes.
 *
 * THE MENU COLLAPSE. partials/header.php renders the menu as
 * <ul class="menu" id="site-menu" data-open="false">. The script only ever
 * flips that attribute and aria-expanded on the button; every decision about
 * what is shown is made here. That means the open/closed behaviour can be read
 * in one file and cannot drift out of step with the script.
 */

.masthead {
  background: var(--paper);
  padding-block: 1rem;
  /* A softer thread than a panel's. This seam runs the full width of the page,
     so at ink weight it read as a cut-here line across the top rather than as
     a join, and it out-shouted the stitched panels it sits above. */
  --thread: var(--tan);
}

.masthead__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  /* No row gap: below the collapse the closed menu is a zero-height flex line,
     and a row gap would leave a phantom band of space under the brand. */
  gap: 0 0.75rem;
}

/*
 * The flex item here is the <nav>, not the .menu inside it, so the full-width
 * second line has to be claimed on the nav — putting flex-basis on .menu does
 * nothing, because .menu is not a child of the flex container.
 */
.masthead__inner > nav {
  flex-basis: 100%;
}

/* --- Brand --------------------------------------------------------------- */

/* The 2.5rem patch sets the height, which lands the link at 40px — 4px under a
   thumb target. The floor is on the link, not the patch, so the mark keeps its
   size and only the hit area grows. */
.brand {
  display: inline-flex;
  align-items: center;
  min-block-size: 2.75rem;
  gap: 0.75rem;
  text-decoration: none;
  color: var(--ink);
}

/* The same scrap of gold fabric as the headline patch, cut square and carrying
   the S. Geometry only: the stitch on it is drawn by the .brand__patch::after
   half of the .patch::after rule in seam.css, so there is one definition of the
   patch seam and not two. */
.brand__patch {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 2.5rem;
  block-size: 2.5rem;
  border-radius: var(--radius-sm);
  background: var(--gold);
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.25rem;
  line-height: 1;
  rotate: -3deg;
  flex: none;
}

.brand__names {
  display: grid;
}

.brand__name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.125rem;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.brand__tagline {
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* --- The toggle ---------------------------------------------------------- */

/*
 * NOT shown by default. The toggle only does something once assets/js/site.js
 * has run, and that script announces itself with data-js on <html>; the rule
 * that reveals this button is therefore qualified by :root[data-js] and lives
 * in the narrow-width block below. Shown unconditionally it is a dead control
 * for a visitor with scripting off — and, worse, its partner rule would have
 * hidden the menu it cannot open.
 */
.masthead__toggle {
  display: none;
  align-items: center;
  gap: 0.5rem;
  /* 44px minimum in both directions: this is a phone control and the label
     inside it is 11px, which on its own padding comes out at about 30px. */
  min-block-size: 2.75rem;
  min-inline-size: 2.75rem;
  justify-content: center;
  padding: 0.55rem 0.9rem;
  border: var(--edge) solid var(--ink);
  border-radius: var(--radius-pill);
  background: var(--paper-raised);
  cursor: pointer;
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  transition: background-color var(--speed) var(--ease);
}

.masthead__toggle[aria-expanded="true"] {
  background: var(--gold);
}

/* The button says "Menu" in words. The stitched bars beside it are aria-hidden
   decoration — do not swap this for an icon-only control. */
.masthead__toggle-text {
  line-height: 1;
}

/* Three rows of running stitch rather than three solid bars: the hamburger is
   the only icon on the site and it may as well be sewn too. */
.masthead__toggle-bar {
  inline-size: 1.25rem;
  block-size: 0.75rem;
  background-image:
    linear-gradient(var(--ink), var(--ink)),
    linear-gradient(var(--ink), var(--ink)),
    linear-gradient(var(--ink), var(--ink));
  background-size: 100% var(--stitch-weight);
  background-position: left top, left center, left bottom;
  background-repeat: no-repeat;
}

/* --- The menu ------------------------------------------------------------ */

/*
 * Visible by default, in every case. Hiding it is the enhancement, not the
 * baseline: see the :root[data-js] block below. With scripting off this stays a
 * plain stacked list of links, which is what the contract at the top of
 * assets/js/site.js requires.
 */
.menu {
  display: grid;
  justify-items: start;
  gap: 0.5rem;
  padding-block: 0.75rem;
}

.menu__item {
  display: contents;
}

/* The seam under a menu link is its state: nothing under a plain link, a full
   run of stitch under the current page and under whatever the pointer is on.
   Never colour alone — aria-current carries the same fact to a screen reader. */
.menu__link {
  display: inline-flex;
  align-items: center;
  /* 44px minimum. The extra height is padding, so the seam still lands just
     under the words rather than floating away from them. */
  min-block-size: 2.75rem;
  padding: 0.55rem 0;
  font-weight: 600;
  text-decoration: none;
  color: var(--ink);
  /* A solid rule that grows from the left on hover. The seam is reserved for
     structural joins; a nav underline is an underline. */
  background-image: linear-gradient(var(--coral), var(--coral));
  background-size: 0 var(--stitch-weight);
  background-position: left bottom;
  background-repeat: no-repeat;
  transition: background-size var(--speed) var(--ease), color var(--speed) var(--ease);
}

.menu__link:hover,
.menu__link[aria-current="page"] {
  background-size: 100% var(--stitch-weight);
  color: var(--ink);
}



/*
 * THE COLLAPSE, and the only place it is decided.
 *
 * Both rules are qualified by :root[data-js], which assets/js/site.js sets on
 * <html> before first paint. Unqualified, they are the classic silent failure:
 * scripting off means a menu hidden by CSS behind a button that cannot open it,
 * i.e. a phone visitor with no navigation at all and nothing on screen to say
 * so. 47.99rem rather than 48rem so this and the wide block below cannot both
 * match at exactly the breakpoint.
 */
@media (max-width: 47.99rem) {
  :root[data-js] .masthead__toggle {
    display: inline-flex;
  }

  :root[data-js] .menu[data-open="false"] {
    display: none;
  }
}

@media (min-width: 48rem) {
  /* Above the collapse the menu is simply a row and the button has no job. */
  .masthead__toggle,
  :root[data-js] .masthead__toggle {
    display: none;
  }

  .masthead__inner {
    gap: 1rem;
  }

  .masthead__inner > nav {
    flex-basis: auto;
  }

  .menu,
  .menu[data-open="true"],
  :root[data-js] .menu[data-open="false"] {
    display: flex;
    align-items: center;
    gap: clamp(1rem, 2.5vw, 2rem);
    padding-block: 0;
  }

  .menu__item {
    display: block;
  }
}

/* --- The chip ------------------------------------------------------------ */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-block-start: var(--stack);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.4em 0.9em;
  border: var(--edge) solid var(--thread);
  border-radius: var(--radius-pill);
  background: var(--paper-raised);
  color: var(--ink-soft);
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  letter-spacing: var(--label-track);
  line-height: 1.4;
  text-transform: uppercase;
  text-decoration: none;
  transition: background-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

/*
 * Only the gallery filters are links; .chip--gold and .chip--sky are <p> route
 * labels and must keep their small pill shape. So the 44px minimum target is
 * hung on a.chip, not on .chip — a filter is a thumb target on a phone, and at
 * the label register the pill is otherwise about 25px tall.
 */
a.chip {
  min-block-size: 2.75rem;
  padding-inline: 1.1em;
}

a.chip:hover {
  background: var(--linen);
  color: var(--ink);
}

/*
 * The active filter. It is marked three ways and only one of them is colour:
 * a filled marker square appears in front of the label, the ground inverts and
 * the label goes to full-strength ink. The marker is an empty pseudo-element
 * rather than a tick glyph so no screen reader reads a stray character —
 * aria-current on the link already says which one is on.
 */
.chip--on {
  background: var(--ink);
  color: var(--on-ink);
  --thread: var(--ink);
}

.chip--on::before {
  content: "";
  inline-size: 0.5em;
  block-size: 0.5em;
  border-radius: 1px;
  background: var(--gold);
  flex: none;
}

a.chip--on:hover {
  background: var(--grape-deep);
  color: var(--on-ink);
}

/* The two route kind-labels. Non-interactive, so they carry ground only. */
.chip--gold {
  background: var(--gold-light);
  color: var(--ink);
  --thread: var(--gold-deep);
}

/* --sky-deep on --sky is 4.3:1, and this label is 11px uppercase — text that
   small needs 4.5:1. The deep sky stays as the edge; the words go to ink. */
.chip--sky {
  background: var(--sky);
  color: var(--ink);
  --thread: var(--sky-deep);
}

/* === hero.css === */
/*
 * hero.css
 *
 * The hero is a <section class="hero"> and NOT a .band, which is why it sets
 * its own vertical space here. That is the one exception to the rule in
 * layout.css, and it is an exception because the hero has no ground of its own
 * to run out to — the run-in above it is the masthead.
 *
 * Copy first in the source and in the single-column stack, because the claim
 * has to arrive before the proof. Two columns only from 60rem.
 */

.hero {
  padding-block: clamp(1.5rem, 3.5vw, 3rem) var(--band-space);
}

.hero__inner {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
}

.hero__copy {
  min-inline-size: 0;
}

.hero__title {
  font-size: clamp(2.75rem, 6vw, 5.25rem);
  line-height: 0.95;
  letter-spacing: -0.03em;
  margin-block-end: var(--stack);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-block-start: clamp(1.5rem, 3vw, 2.25rem);
}

/* --- The proof: two stitched panels -------------------------------------- */

.hero__proof {
  display: grid;
  gap: var(--stack);
  min-inline-size: 0;
}

.hero__panel {
  padding: 0.6rem;
  margin: 0;
  max-inline-size: 21rem;
}

.hero__photo {
  inline-size: 100%;
  /* 3/4 is the source photographs' own ratio. Any other value crops the bear,
     and the hero photo is the one image on the site that must not be cropped:
     the care label beside it names the badge that has to stay visible. */
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: calc(var(--radius) - 0.75rem);
}

/* The smaller second photo, offset so the pair reads as two pieces laid down
   rather than as a two-cell grid. */
.hero__panel--minor {
  --thread: var(--grape-deep);
  justify-self: start;
  max-inline-size: 11rem;
}

.hero__panel--minor .hero__photo {
  aspect-ratio: 1 / 1;
}

.hero__minor-caption {
  padding: 0.6rem 0.35rem 0.15rem;
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--ink-soft);
}

@media (min-width: 40rem) {
  /* The minor panel steps in from the right edge, so the pair reads as two
     pieces laid down by hand. It deliberately does NOT overlap the main panel:
     the care label lives on that panel's lower corner and an overlap would put
     a photo on top of the one caption that carries the whole argument. */
  .hero__panel--minor {
    justify-self: end;
    margin-inline-end: clamp(0rem, 4vw, 3rem);
  }
}

@media (min-width: 60rem) {
  .hero__inner {
    grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
    align-items: center;
    gap: clamp(2.5rem, 6vw, 5rem);
  }
}

/*
 * MOTION — the only orchestrated moment on the site.
 *
 * The headline settles onto its seam on load: the line eases up a few px, and
 * the appliquéd patch lands just after it, as though it were sewn on last.
 * Everything else on the site is still.
 *
 * The whole thing is inside prefers-reduced-motion: no-preference, so a
 * reduced-motion visitor gets the finished state with no animation to override
 * and no chance of being left mid-fade if an animation is interrupted.
 *
 * `translate` rather than `transform`, because .patch already holds a `rotate`
 * and the independent transform properties do not overwrite one another.
 */
@keyframes slap-settle {
  from {
    opacity: 0;
    translate: 0 0.6rem;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .hero__title {
    animation: slap-settle var(--settle) 60ms var(--ease) backwards;
  }

  .hero__title .patch {
    animation: slap-settle var(--settle) 220ms var(--ease) backwards;
  }
}

/* === facts.css === */
/*
 * facts.css — the four claims on the ink band.
 *
 * The tone modifier colours the claim and nothing else. Detail text stays on
 * --on-ink at full strength: four differently-coloured paragraphs would be a
 * rainbow, and the colour is doing one job here, which is to separate four
 * claims that are read at a glance.
 */

/* There are no panel edges between these four, only the hairline above each
   claim, so the separation has to come from the gap. At the site default they
   read as one paragraph in four colours. */
.facts {
  --grid-gap: clamp(1.75rem, 4vw, 3rem);
}

.facts__grid {
  display: grid;
  gap: var(--grid-gap);
}

/* Each claim hangs off a short run of its own thread. A solid rule would be the
   one plain border on the site and it would show — every other structural edge
   here is stitched. */
.facts__item {
  min-inline-size: 0;
  padding-block-start: var(--stack);
  border-block-start: var(--stitch-weight) solid var(--thread);
}

.facts__claim {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(1.375rem, 2.2vw, 1.75rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin-block-end: 0.4rem;
  color: var(--thread);
}

.facts__detail {
  color: var(--on-ink-soft);
  font-size: var(--size-small);
  max-inline-size: 32ch;
}

/*
 * Each tone points --thread at a value that clears WCAG AA on --ink for the
 * claim, which is large display text.
 *   gold        9.6:1
 *   sky        16.0:1
 *   coral       5.3:1
 * --grape (#7C5CD6) is only 3.1:1 on ink — it scrapes AA for large text and
 * fails outright the moment anyone reuses it at body size. It is replaced here
 * by --grape-light at 7.6:1; the bow colour survives, the contrast problem
 * does not.
 */
.facts__item--gold {
  --thread: var(--gold);
}

.facts__item--sky {
  --thread: var(--sky);
}

.facts__item--coral {
  --thread: var(--coral);
}

.facts__item--grape {
  --thread: var(--grape-light);
}

@media (min-width: 40rem) {
  .facts__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

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

/* === panel.css === */
/*
 * panel.css — the two routes.
 *
 * Two panels joined down a centre seam, because the choice really is a fork.
 * The join is drawn on the pair, not on either panel: a seam belongs to the
 * two pieces it holds together, and drawing it once means it cannot end up as
 * two slightly different lines.
 */

.routes .section-title {
  margin-block-end: var(--grid-gap);
}

.routes__pair {
  position: relative;
  display: grid;
  gap: var(--grid-gap);
}

.routes__panel {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--stack-tight);
  min-inline-size: 0;
}

.routes__title {
  font-size: clamp(1.375rem, 2.4vw, 1.875rem);
  margin-block-start: 0.25rem;
}

.routes__copy {
  color: var(--ink-soft);
  max-inline-size: var(--measure);
}

/* margin, not padding: .link-arrow's own padding-block-start is what gives it a
   44px target, and overriding it here would quietly take that back. */
.routes__panel .link-arrow {
  margin-block-start: auto;
}

/* Ground and thread only. Both grounds are near-white tints so the body copy
   keeps its contrast against them. */
.routes__panel--gold {
  --thread: var(--gold-deep);
  background: var(--paper-raised);
}

.routes__panel--sky {
  --thread: var(--sky-deep);
  background: var(--paper-raised);
}

@media (min-width: 40rem) {
  .routes__pair {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch;
  }

  /* The centre seam: one running stitch down the gap between the two panels,
     in the neutral thread, joining them. It is decoration on top of empty
     space, hence pointer-events: none. */
  .routes__pair::after {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 50%;
    translate: -50% 0;
    inline-size: var(--stitch-weight);
    pointer-events: none;
    background-image:
      var(--stitch-v);
  }
}

/* === bear.css === */
/*
 * bear.css — the bear card, the grid it sits in, and the care label.
 *
 * The care label lives in this file because it is the bear's label: the rows
 * come from lib/bears.php and say what is true of that one bear. The hero
 * borrows it for its lead photo, which is why the --on-photo variant is here
 * too rather than in hero.css — one definition, two placements.
 */

.bear-grid {
  display: grid;
  gap: var(--grid-gap);
}

/*
 * The gallery: as many ~19rem columns as fit, so the number of bears can change
 * without anyone editing a breakpoint.
 *
 * The min() is not decoration. A bare minmax(19rem, 1fr) sets a hard 19rem
 * floor, and 19rem is 304px — wider than the content box of a 320px phone once
 * the gutters are taken off. The track then refuses to shrink and the whole
 * page scrolls sideways. min(19rem, 100%) lets the last column collapse to the
 * width actually available.
 */
.bear-grid--full {
  grid-template-columns: repeat(auto-fill, minmax(min(19rem, 100%), 1fr));
}

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

@media (min-width: 40rem) {
  .bear-grid--brief {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 60rem) {
  .bear-grid--brief {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* --- The card ------------------------------------------------------------ */

.bear {
  display: flex;
  flex-direction: column;
  padding: 0.75rem;
  margin: 0;
  min-inline-size: 0;
}

/* A fixed ratio is what keeps the grid even: the photos are not all the same
   shape, and without this one long portrait shot sets the height of its whole
   row. width and height are already on the element from slap_img(), so nothing
   here reflows once the file arrives. */
.bear__photo {
  inline-size: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: calc(var(--radius) - 0.75rem);
}

.bear__body {
  display: flex;
  flex-direction: column;
  gap: var(--stack-tight);
  padding: 0.9rem 0.35rem 0.25rem;
  flex: 1;
}

.bear__name {
  font-size: 1.25rem;
  line-height: 1.15;
}

.bear__blurb {
  color: var(--ink-soft);
  font-size: var(--size-small);
  max-inline-size: var(--measure);
}

.bear__source {
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* The gallery card's label is pushed to the foot of the card so that the
   labels line up across a row even when the blurbs run to different lengths. */
.bear--full .care-label {
  margin-block-start: auto;
}

.bear--brief .bear__body {
  gap: 0.3rem;
}

/* --- The care label ------------------------------------------------------ */
/*
 * A woven garment label, and the site's one structural device. Micro all-caps
 * captions, hairline rules between the rows, a stitched edge. It must not
 * decay into a generic caption block: the rules, the tracking and the foot
 * line are what make it read as something sewn into a seam.
 */

.care-label {
  position: relative;
  padding: 0.75rem 0.85rem;
  border: var(--edge) solid var(--thread);
  border-radius: var(--radius-sm);
  background: var(--linen);
  color: var(--ink);
}

.care-label__row {
  display: grid;
  gap: 0.1rem;
  padding-block: 0.4rem;
}

/* A hairline between rows and none above the first — the rule is a divider,
   not a border, and a border at the top would fight the stitched edge. */
.care-label__row + .care-label__row {
  border-block-start: 1px solid var(--tan);
}

.care-label__caption {
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--ink-soft);
  flex: none;
}

.care-label__value {
  margin: 0;
  font-size: var(--size-small);
  font-weight: 600;
  min-inline-size: 0;
}

.care-label__foot {
  margin-block-start: 0.5rem;
  padding-block-start: 0.45rem;
  border-block-start: 1px solid var(--tan);
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
}

/*
 * The hero variant. Below 60rem it simply sits under the photo — a label
 * covering the bear's face on a 360px screen would hide the one thing the
 * photograph is there to prove. From 60rem there is room for it to sit over
 * the lower corner, on a solid paper ground so the words stay readable. It is
 * a ground, not a shadow: nothing on this site floats.
 */
.care-label--on-photo {
  margin-block-start: 0.75rem;
}

/* Deliberately NOT overlaid on the photograph.
   Every position that fitted a label this size landed it on the bear's chest —
   directly over the sponsor badge that the label's own KEPT row names. A label
   that hides the thing it is pointing at is worse than no label. It sits below
   the photo instead, inside the same panel, which is also truer to the object:
   a care label is sewn into a seam, not stuck on the front. */

/* === form.css === */
/*
 * form.css — the enquiry form and the two notices it can come back as. The
 * numbered steps that sit beside it are a separate component in steps.css.
 *
 * Every state that matters is carried by something other than colour: an error
 * changes the thread AND prints a sentence, the summary at the top names each
 * problem as a link, and the two notices have different headings. A red edge on
 * its own tells a colour-blind visitor nothing and tells a screen-reader user
 * less than that.
 */

.form {
  display: grid;
  gap: var(--stack);
}

/* --- The error summary --------------------------------------------------- */

.form__summary {
  padding: var(--stack);
  border: var(--edge) solid var(--coral-deep);
  border-radius: var(--radius-sm);
  background: var(--paper);
}

.form__summary-title {
  font-size: 1.125rem;
  margin-block-end: 0.4rem;
}

.form__summary-list {
  display: grid;
  gap: 0.25rem;
  font-size: var(--size-small);
}

.form__summary-list a {
  color: var(--link);
}

/* --- Fields -------------------------------------------------------------- */

.field {
  display: grid;
  gap: 0.35rem;
}

.field__label {
  font-weight: 700;
  font-size: var(--size-small);
}

.field__optional {
  font-weight: 400;
  color: var(--ink-soft);
}

.field__hint {
  font-size: var(--size-small);
  color: var(--ink-soft);
  max-inline-size: var(--measure);
}

.field__input {
  inline-size: 100%;
  padding: 0.7rem 0.85rem;
  border: var(--edge) solid var(--ink-soft);
  border-radius: var(--radius-sm);
  background: var(--paper);
  color: var(--ink);
  font-size: var(--size-body);
  transition: border-color var(--speed) var(--ease);
}

.field__input::placeholder {
  color: var(--ink-soft);
}

.field__input:hover {
  border-color: var(--ink);
}

/* The invalid state: a coral edge, the whole field re-threaded coral, and the
   message below. Three signals, one of which is text. */
.field--error .field__input {
  border-color: var(--coral-deep);
}

.field--error {
  --thread: var(--coral-deep);
}

.field__error {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  font-size: var(--size-small);
  font-weight: 600;
  color: var(--coral-ink);
}

/* A drawn marker rather than a "!" glyph: a pseudo-element with no text cannot
   be read out as a stray character next to the message that follows it. */
.field__error::before {
  content: "";
  inline-size: 0.5em;
  block-size: 0.5em;
  border-radius: 1px;
  background: var(--coral-ink);
  flex: none;
  translate: 0 -0.1em;
}

/* --- Radio choices ------------------------------------------------------- */

.field--choice {
  display: grid;
  gap: 0.5rem;
}

.field__choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.choice {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  /* The whole pill is the label, so the whole pill is the target — and on a
     phone it has to be a thumb target, not a 35px one. */
  min-block-size: 2.75rem;
  padding: 0.55rem 0.9rem;
  border: var(--edge) solid var(--thread);
  border-radius: var(--radius-pill);
  background: var(--paper);
  cursor: pointer;
  transition: background-color var(--speed) var(--ease);
}

.choice:hover {
  background: var(--linen);
}

/* The native control, kept native: it is already accessible, already keyboard
   operable and already understood. accent-color is the whole restyle. */
.choice__input {
  accent-color: var(--grape-deep);
  inline-size: 1.1rem;
  block-size: 1.1rem;
  margin: 0;
  flex: none;
}

.choice__text {
  font-size: var(--size-small);
  font-weight: 600;
}

/* Checked is marked by the ground as well as by the radio itself, so it can be
   seen from across the form and not only by looking straight at the dot. */
.choice:has(.choice__input:checked) {
  background: var(--gold-light);
  border-color: var(--ink);
}

/* --- The honeypot -------------------------------------------------------- */
/*
 * Off-screen, not display:none and not hidden. A bot that skips hidden inputs
 * would sail past this one; a bot that fills everything it finds trips it. It
 * is aria-hidden and tabindex="-1" in the markup, so nobody using a keyboard or
 * a screen reader can ever reach it — which is the only reason it is safe to
 * treat a filled value as proof of a script.
 */
.form__trap {
  position: absolute;
  inset-inline-start: -9999px;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
}

/* --- Submit and aside ---------------------------------------------------- */

.form__send {
  justify-self: start;
  margin-block-start: var(--stack-tight);
}

.form__aside {
  font-size: var(--size-small);
  color: var(--ink-soft);
}

/* --- Notices ------------------------------------------------------------- */

.notice {
  display: grid;
  gap: var(--stack-tight);
}

.notice__title {
  font-size: clamp(1.375rem, 2.4vw, 1.75rem);
}

.notice--good {
  --thread: var(--sky-deep);
  background: var(--sky);
  color: var(--ink);
}

.notice--bad {
  --thread: var(--coral-deep);
  background: var(--paper-raised);
}

.notice__more {
  margin-block-start: var(--stack-tight);
}

/* === prose.css === */
/*
 * prose.css — long-form running text.
 *
 * The only place on the site with more than a paragraph at a time, so it is the
 * only place that needs rules for headings and lists inside flowing copy.
 * Everything else is a component with its own spacing, which is why these are
 * scoped under .prose rather than set on the bare elements: a bare `h2 + p`
 * margin would fight every card and band on every other page.
 *
 * The reading measure is capped on the text elements, NOT on .prose itself.
 * .prose sits on the band <section>, so a cap there shrank the whole band to
 * 60ch with no auto margin — the section jammed against the left edge while
 * every other band on the page stayed centred at the full .wrap width. Every
 * other --measure in the stylesheet (bear, form, panel, steps) is likewise on a
 * paragraph-level element, never on a container.
 *
 * Spacing is on the block-end of each element. That does mean the last
 * paragraph's margin collapses out of .wrap and adds to the band's own
 * padding-block, so this band ends slightly taller than its neighbours; it is
 * a few pixels at the very bottom of one page and not worth a rule to chase.
 */

.prose {
  color: var(--ink-soft);
}

.prose h2 {
  max-inline-size: var(--measure);
  margin-block: clamp(2rem, 4vw, 2.75rem) var(--stack-tight);
  font-size: clamp(1.375rem, 2.5vw, 1.75rem);
  line-height: 1.15;
  color: var(--ink);
}

/* The first heading sits directly under the page lead, which already carries
   the space above it. */
.prose h2:first-child {
  margin-block-start: 0;
}

.prose p {
  max-inline-size: var(--measure);
  margin-block: 0 var(--stack-tight);
  line-height: 1.7;
}

/* base.css clears list-style globally, because every other list on the site is
   a nav or a grid. Prose lists are the one place a real bullet belongs, so the
   marker has to be turned back ON here — restoring the indent alone left the
   items looking like stray indented lines. */
.prose ul {
  max-inline-size: var(--measure);
  list-style: disc;
  margin-block: 0 var(--stack);
  padding-inline-start: 1.25rem;
  line-height: 1.7;
}

.prose li {
  margin-block-end: 0.35rem;
}

/* The marker in the page's own thread colour rather than the browser's grey. */
.prose li::marker {
  color: var(--tan);
}

/* .prose sets --ink-soft on the whole block, so emphasis has to climb back to
   full-strength ink. Weight and link colour already come from base.css. */
.prose strong {
  color: var(--ink);
}

/* === steps.css === */
/*
 * steps.css — "What happens after you press send", the numbered list rendered
 * by partials/enquiry-steps.php.
 *
 * It sits BESIDE the enquiry form, not inside it: it is the only numbered
 * sequence on the site, it contains no controls, and it has no notion of a
 * value, an error or a submission. It lived in form.css, which meant the file
 * named after the form owned three unrelated components.
 */

.steps {
  display: grid;
  gap: var(--stack);
  margin-block-start: clamp(1.5rem, 3vw, 2.25rem);
}

.steps__step {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
}

/* A small stitched square — the same seam as every panel, at label size. */
.steps__number {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 2.25rem;
  block-size: 2.25rem;
  flex: none;
  border: var(--edge) solid var(--thread);
  border-radius: var(--radius-sm);
  background: var(--gold);
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1rem;
  line-height: 1;
}

.steps__body {
  display: grid;
  gap: 0.15rem;
  min-inline-size: 0;
}

.steps__title {
  font-weight: 700;
}

.steps__detail {
  color: var(--ink-soft);
  font-size: var(--size-small);
  max-inline-size: var(--measure);
}

/* === footer.css === */
/*
 * footer.css — the ink band that closes every page.
 *
 * The band modifier in layout.css already set the ground, the text colour, the
 * thread for the top seam and the focus ring. Nothing here repeats any of that;
 * this file only lays the columns out and sets the type inside them.
 */

/* body is a viewport-height column (base.css); this is the line that pushes the
   footer to the bottom of a page too short to fill the screen. */
.footer {
  margin-block-start: auto;
}

.footer__grid {
  display: grid;
  gap: var(--grid-gap);
}

.footer__about {
  min-inline-size: 0;
}

.footer__wordmark {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.375rem;
  letter-spacing: -0.02em;
  margin-block-end: 0.4rem;
}

.footer__blurb {
  color: var(--on-ink-soft);
  font-size: var(--size-small);
  max-inline-size: 40ch;
}

.footer__col {
  min-inline-size: 0;
}

.footer__col .label {
  margin-block-end: 0.6rem;
}

.footer__links {
  display: grid;
  gap: 0.4rem;
  font-size: var(--size-small);
}

/* The link colour token was chosen against paper and is unreadable on ink, so
   footer links take the band's own text colour and mark themselves with the
   seam instead — the same underline the menu uses. */
/* align-items: flex-end rather than centre: the extra height needed to reach a
   44px target is taken above the words, so the seam stays tight under them. */
.footer__links a {
  display: inline-flex;
  align-items: flex-end;
  min-block-size: 2.75rem;
  color: var(--on-ink);
  text-decoration: none;
  text-decoration: underline;
  text-underline-offset: 0.25em;
  text-decoration-thickness: 1px;
  padding-block-end: 0.15rem;
  transition: color var(--speed) var(--ease);
}

.footer__links a:hover {
  color: var(--gold);
}

/* The legal line also carries .label, so its colour and register are already
   set by type.css on the ink band. All it needs here is its own seam above it
   and the space to sit in. */
.footer__legal {
  margin-block-start: clamp(2rem, 4vw, 3rem);
  padding-block-start: var(--stack);
  /* A plain rule, not a seam. border-block-start also sidesteps the problem the
     background-image version had: .footer__legal is itself a .wrap, so a
     background ran out into the gutters and needed a negative offset to stay
     off the words. A border is drawn on the border box and just works. */
  border-block-start: 1px solid var(--on-ink-soft);
}

@media (min-width: 40rem) {
  .footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 60rem) {
  .footer__grid {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: clamp(2rem, 5vw, 4rem);
  }
}

