/* neo — the stylesheet
 *
 * One file, two consumers: the React components in this package (which exist so
 * Claude Design can compose real parts) and the Jinja templates the application
 * actually ships. Both emit the same markup and the same class names, so a
 * component here is a faithful description of what production renders.
 *
 * The provenance palette is load-bearing, not decorative. Three states must stay
 * visually distinct because they mean different things in law and in trust:
 *   verified  — checked against an external record
 *   confirmed — a previous employer corroborated it
 *   stated    — the person said it; nothing has checked it yet
 * A fourth, `ask`, marks an open question the system deliberately did NOT resolve.
 *
 * There is no score token and no class that renders one: the evidence is
 * structured, the judgement belongs to the user.
 *
 * LIGHT ONLY. A designed dark theme used to live here in two blocks, a
 * [data-theme="dark"] override and a prefers-color-scheme query. Both are
 * gone by decision, not by neglect: one ground to design against, and the
 * provenance hues only have to hold on one of them.
 */

:root {
  /* HARBOUR. Cool, and deliberately not descended from the incumbent.
     nannyjob.co.uk is an amber site, and so is almost everything else in UK
     childcare. The previous palette inherited that warmth and spent a lot of
     care keeping the brand clear of the amber this product already spends on
     "confirmed". This one steps out of the argument entirely.

     THE HUE WAS CHOSEN BY MEASUREMENT, not by taste. The three provenance
     verdicts occupy fixed hues -- `--c` (confirmed) at 73 degrees, `--v-fill`
     (verified) at 162, `--ask` at 294. That leaves three gaps, and the widest
     by far is the 132-degree arc between verified and ask. `--brand` sits at
     226, near its middle: 65 degrees from verified, 151 from confirmed, 67
     from ask. `tests/test_design_system.py` holds the floor at 12.

     WHAT A COOL GROUND COST. Two tints had to be re-derived rather than
     carried over. `--c-bg` and `--sun-soft` were both #FFF3D6, a warm cream
     that reads as a stain on cool paper rather than as a pale amber; `--ask-bg`
     had the same problem in violet. The verdict INKS are untouched -- those
     carry meaning and are not ours to retune for a background. */
  --bg: #F5F9FA;
  --card: #FFFFFF;
  --line: #DCE7EA;
  /* Shadows and scrims are the palette's ink seen through alpha, and they are
     tokens for one reason: a repaint that misses them leaves a warm halo on a
     cool page. That is exactly what happened when this palette turned — eight
     rgba(122, 82, 32, …) shadows and two rgba(42, 32, 24, …) scrims survived
     the change, because they lived in template <style> blocks rather than
     here. Anything casting a shadow uses these. */
  --shadow-rgb: 16, 54, 66;
  --shadow: 0 2px 10px rgba(var(--shadow-rgb), .10);
  --scrim: rgba(21, 39, 44, .46);

  --ink: #15272C;
  --mut: #5A6E75;
  --link: #0A5A73;

  --brand: #0B6480;
  --brand-ink: #FFFFFF;
  /* The brand as a pale fill behind brand-coloured text. 6.21:1 with
     --brand-text, so a pressed chip stays readable rather than merely tinted. */
  --brand-soft: #D6EAF1;
  /* The brand as INK rather than as a fill: an outline button, a kicker and an
     initials avatar are all text. --brand at 6.67:1 is fine behind white, but
     this darker step is what small type sits on -- 7.71:1 on card. */
  --brand-text: #0A5A73;

  /* THE SUNSHINE, and the only token in this file with a usage rule attached.
     It is two degrees of hue from --c. On a large surface -- a banner, a
     section band, an illustration -- that is warmth. On anything badge-sized
     beside a claim it is indistinguishable from "confirmed", so it must never
     paint a provenance pill. test_the_sunshine_is_never_worn_by_something_pill_sized
     holds both halves of that. */
  --sun: #F5A524;
  --sun-ink: #4A3000;
  --sun-soft: #FDF0D8;

  --v-fill: #2E7D5B;
  --v-on: #FFFFFF;
  /* Darkened one step from #8A5A00 so it clears 4.5:1 against the re-derived
     --c-bg on a cool ground. The hue is unmoved, which is what --sun's rule
     depends on. */
  --c: #7A5100;
  --c-bg: #FBF0D9;
  --ask: #6C4BB8;
  --ask-bg: #ECE7F9;

  --font-sans: system-ui, -apple-system, "Segoe UI", sans-serif;
  --t-display: clamp(1.75rem, 1.519rem + 0.946vw, 2.125rem);   /* 28 - 31.6 - 34 */
  --t-title:   clamp(1.25rem, 1.135rem + 0.473vw, 1.4375rem);  /* 20 - 21.8 - 23 */
  --t-lead:    clamp(1.0625rem, 0.986rem + 0.315vw, 1.1875rem);/* 17 - 18.2 - 19 */
  --t-card:    clamp(1.25rem, 1.173rem + 0.315vw, 1.375rem);   /* 20 - 21.2 - 22 */

  --r-card: 16px;
  --r-pill: 999px;
  --r-input: 12px;

  /* KEYBOARD FOCUS IS NOT A PROVENANCE VERDICT. Every focus ring in this file
     was painted with --ask, the violet that means "an open question nobody has
     resolved" -- a token that carries meaning beside a claim. Two problems:
     it overloads a semantic colour, and measured against a brand-filled button
     it is 1.06:1, which is to say invisible exactly where focus matters most.

     Ink, at the 2px offset every ring already uses, is drawn OUTSIDE the
     control on the surrounding surface: 15.5:1 on card, 14.6:1 on the page
     ground. The one place it is weak is a control sitting on the hero
     photograph, which is a smaller problem than an invisible ring on every
     primary button.

     `--focus` was already referenced once, by .fk-help > summary, and never
     declared -- so that single ring fell back to currentColor. */
  --focus: var(--ink);

  --danger: #B3261E;
  --danger-bg: #FCEBEA;

  --col: 1080px;
  --col-text: 54ch;
  --gutter: 20px;
}

/* One application after one press.  Kept narrow enough to read, while the
   actions wrap naturally rather than becoming a horizontal toolbar. */
.application-status { max-width: 44rem; margin-inline: auto; }
.application-status-card { padding: clamp(18px, 4vw, 24px); }
.application-status-actions { align-items: center; }
.application-status-actions form { margin: 0; }


html, body { margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
}

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

:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ---- surface ----------------------------------------------------------- */

.neo-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
  padding: 18px 20px;
}

/* ---- the language picker ----------------------------------------------- */

/* Collapsed by default and styled as a control rather than as help: it takes
   an answer, so it must not wear `.fk-help`'s "i" chrome, which on this
   product means "an explanation you may skip". */
.lang-pick > summary {
  font-size: 14.5px; font-weight: 700; cursor: pointer;
  padding: 10px 2px; min-height: 44px; display: flex; align-items: center; gap: 8px;
}
/* The count beside the summary, so she can see whether she has answered
   without opening forty-one rows. */
.lang-count { font-weight: 400; color: var(--mut); }
.lang-list { list-style: none; margin: 6px 0 0; padding: 0; display: grid; gap: 4px; }
.lang-list li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px; align-items: center;
  /* 44px, so a thumb on a phone lands on the row it aimed at. */
  min-height: 44px; padding: 0 2px;
}
.lang-row { display: flex; align-items: center; gap: 10px; font-weight: 400; }
.lang-level select { font-size: 15px; padding: 6px 8px; }
@media (max-width: 719px) {
  /* The level under the name rather than beside it: two controls and a long
     language name do not fit 390px side by side. */
  .lang-list li { grid-template-columns: 1fr; gap: 2px; padding: 6px 2px 10px; }
}

/* ---- money input ------------------------------------------------------- */

/* ONE IMPLEMENTATION, BECAUSE THERE WERE THREE. `.money-input` was defined in
   _formkit.html, again in adverts/form.html and a third time, quite
   differently, in intake/_rolefacts.html -- and the advert form includes the
   form kit, so two ::before rules painted one pseudo-element. That is what put
   the pound sign on top of the first digit of the pay figure.

   The prefix comes from `data-prefix` rather than a hardcoded glyph, so a
   brand in another currency needs markup rather than a new rule.

   IT IS A FLEX ITEM, NOT AN OVERLAY, and that is the whole fix. Every previous
   implementation drew the glyph absolutely and then reserved room for it with
   `padding-left` on the input -- which only works while nothing else sets that
   input's padding. The form kit does, at the same specificity and later in
   source order, so the padding was silently dropped and the pound sign landed
   on the first digit. A flex row cannot be undone that way: the prefix
   occupies real space, so nothing has to be reserved for it. */
.money-input { display: flex; align-items: center; gap: 6px; max-width: 12rem; }
.money-input::before {
  content: attr(data-prefix);
  font-weight: 800; color: var(--mut); flex: none;
}
.money-input input { flex: 1 1 auto; min-width: 0; }

/* ---- provenance -------------------------------------------------------- */

.prov {
  font-size: 11px;
  font-weight: 700;
  border-radius: var(--r-pill);
  padding: 3px 10px;
  white-space: nowrap;
}
.prov-verified  { background: var(--v-fill); color: var(--v-on); }
.prov-confirmed { border: 1.5px solid var(--c); color: var(--c); background: var(--c-bg); }
.prov-stated    { text-transform: uppercase; letter-spacing: .06em; color: var(--mut); }
.prov-ask       { color: var(--ask); }

/* ---- claim line -------------------------------------------------------- */

/* THE PILL BELONGS TO THE CLAIM, and the row has one shape or it has none.

   The bare rules here wrapped: a claim whose words ran long pushed its
   provenance onto a second line and left the dotted leader stretched off the
   end of the label with nothing on the other side of it, which reads as a
   rendering fault. Measured at 390 on /nannies/{id}/checklist/checks, four of
   five rows did it and one did not; on the review sheet the rows came out
   25px, 57px and 81px tall in no pattern a reader could learn. Ragged rather
   than broken — and this is the product's signature element, so ragged is
   worse than it sounds.

   The fix was already written TWICE, page-locally, in fitview/candidate.html
   and providers/profile.html, with the argument spelled out in both. It
   belongs to the component: every other page that draws a claim row — the
   checklist, the review sheet, the message thread, a step page — took the
   defaults and got the fault.

   Above 680px the row is a ROW: it does not wrap, the label gives ground
   first (min-width: 0 is what allows that; auto is the default and means
   "never narrower than your longest word"), and the leader runs out of dots
   before anything else moves.

   Below it the row is a STACK, because a claim, a leader and a pill will not
   share 350px: the pill would win the fight and squeeze the words to one per
   line, and a nowrap pill as long as "Verified, Home Office share code, on the
   update service" would push the document wider than the screen. Every row the
   same two lines, and no leader — a leader with no room to run is a fleck of
   dots, not a line.

   A WIDTH QUERY, and only a width query: this is layout, not a target. What a
   thumb has to hit keys on (pointer: coarse) at the foot of this file and
   never on width. */
.claim-row { padding: 9px 0; }
.claim { display: flex; align-items: baseline; gap: 10px; flex-wrap: nowrap; }
.claim-text { font-size: 15.5px; font-weight: 600; line-height: 1.45; min-width: 0; }
.claim-text-muted { color: var(--mut); }
.claim-leader {
  flex: 1; min-width: 0;
  border-bottom: 2px dotted var(--line);
  position: relative; top: -4px;
}
@media (max-width: 680px) {
  .claim { flex-wrap: wrap; gap: 7px 10px; }
  .claim-text { flex-basis: 100%; }
  .claim-leader { display: none; }
  .claim .prov { white-space: normal; }
}
.claim-note {
  margin: 5px 0 0;
  font-size: 13.5px;
  color: var(--mut);
  max-width: 60ch;
}

/* ---- pay --------------------------------------------------------------- */

/* Pay is shown exactly as the family gave it. When they didn't say, that
   absence is displayed honestly rather than hidden, guessed or invented. */
.pay        { font-size: 17px; font-weight: 800; color: var(--ink); }
.pay-unsaid { font-size: 15px; font-style: italic; font-weight: 500; color: var(--mut); }
.pay-note   { font-size: 12.5px; font-style: italic; color: var(--c); }

/* ---- avatar ------------------------------------------------------------ */

/* The FALLBACK on a carer's own profile, where she may publish a photograph of
   herself, and the ONLY identity everywhere else: an index row, a candidate, an
   applicant, a cover offer, a message thread and the header all take initials,
   because a face beside a row that is being compared is how a hiring surface
   launders a preference into a decision - migration 0061 argues that at length.
   So layouts must still read well with no face in them rather than treating the
   absence as a gap to fill. On most surfaces there will never be one, and on
   the one surface where there may be, a photograph is never required and most
   profiles will not carry it. */
.avatar {
  width: 56px; height: 56px;
  border-radius: var(--r-pill);
  background: var(--brand-soft);
  color: var(--brand-text);
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; font-weight: 800;
  flex-shrink: 0;
}
.avatar-sm { width: 36px; height: 36px; font-size: 13px; }

/* ---- buttons ----------------------------------------------------------- */

/* A button and a link that acts as one must be indistinguishable: half the
   product's primary actions are <a href> because they are navigations, and an
   underlined stretched link where a button belongs is how the surface read
   before this rule existed. */
.btn {
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  border-radius: var(--r-pill);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  text-align: center;
  text-decoration: none;
  line-height: 1.2;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}
.btn-primary { padding: 10px 22px; border: none; background: var(--brand); color: var(--brand-ink); }
.btn-ghost   { padding: 10px 20px; border: 1.5px solid var(--brand-text); background: transparent; color: var(--brand-text); }
.btn-quiet   { padding: 10px 18px; border: 1.5px solid var(--line); background: transparent; color: var(--ink); }
.btn-quiet[aria-pressed="true"] {
  border-color: var(--brand-text);
  background: var(--brand-soft);
  color: var(--brand-text);
}
.btn-block { width: 100%; }
.btn-sm { font-size: 13px; }
.btn-sm.btn-primary, .btn-sm.btn-ghost, .btn-sm.btn-quiet { padding: 7px 14px; }
.btn-lg { font-size: 15.5px; }
.btn-lg.btn-primary, .btn-lg.btn-ghost { padding: 13px 26px; }

/* Hover states are written for the anchor as well as the button, because the
   global `a:hover { color: var(--ink) }` would otherwise paint dark ink on the
   brand fill and make the primary action unreadable exactly when it is being
   pointed at. */
.btn-primary:hover, a.btn-primary:hover { background: var(--link); color: var(--brand-ink); }
.btn-ghost:hover, a.btn-ghost:hover { background: var(--brand-soft); color: var(--brand-text); }
.btn-quiet:hover, a.btn-quiet:hover { border-color: var(--mut); color: var(--ink); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

/* ---- filter chip ------------------------------------------------------- */

.chip {
  font: inherit;
  font-size: 13.5px;
  font-weight: 700;
  padding: 9px 16px;
  border-radius: var(--r-pill);
  border: 1.5px solid var(--line);
  background: var(--card);
  color: var(--ink);
  box-shadow: var(--shadow);
  cursor: pointer;
  /* Both index pages re-declared this to make an <a class="chip"> line up
     with a <button class="chip">. It belongs to the chip. It is also what
     lets the 719px block below put a min-height on one. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  text-decoration: none;
  white-space: nowrap;
}
.chip[aria-pressed="true"] { border-color: var(--ink); background: var(--ink); color: var(--bg); }

/* ---- role card --------------------------------------------------------- */

.role-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: 18px;
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.role-top { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
.role-kicker { font-size: 13px; font-weight: 700; color: var(--brand-text); }
.role-posted { font-size: 12px; color: var(--mut); white-space: nowrap; }
/* The children lead, because they are the work. */
.role-title { margin: 0; font-size: var(--t-card); font-weight: 800; letter-spacing: -.01em; line-height: 1.25; }
.role-tags { display: flex; gap: 6px; flex-wrap: wrap; }
.tag { font-size: 12.5px; font-weight: 600; border-radius: var(--r-pill); padding: 4px 11px; }
.tag-week { background: var(--brand-soft); color: var(--ink); }
.tag-home { background: var(--sun-soft); color: var(--ink); }
.role-money { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.role-actions { display: flex; gap: 8px; margin-top: auto; padding-top: 4px; }
.role-actions .btn-primary { flex: 1; padding: 10px 0; }

/* ---- evidence panel ---------------------------------------------------- */

/* Two people describing the same job can both be honest and still disagree.
   Both accounts are shown; the product never adjudicates between them. */
.evidence { background: var(--ask-bg); border-radius: 12px; padding: 16px; }
.evidence-title {
  font-size: 12px; font-weight: 800;
  text-transform: uppercase; letter-spacing: .08em;
  color: var(--ask);
}
.evidence-duo { display: grid; gap: 12px; margin-top: 12px; }
@media (min-width: 640px) { .evidence-duo { grid-template-columns: 1fr 1fr; } }
.evidence-src { background: var(--card); border-radius: 10px; padding: 12px 14px; }
.evidence-who { font-size: 11.5px; font-weight: 700; color: var(--mut); }
.evidence-said { margin: 4px 0 0; font-size: 14px; line-height: 1.55; }
.evidence-q { margin: 12px 0 0; font-size: 13.5px; line-height: 1.55; }
.evidence-q strong { color: var(--ask); }

/* ---- question list ----------------------------------------------------- */

.questions { background: var(--ask-bg); border-radius: var(--r-card); padding: 18px 20px; }
.questions-title { margin: 0 0 8px; font-size: 16px; font-weight: 800; color: var(--ask); }
/* --mut on --ask-bg is 4.43:1, the same shortfall as .ai-disclosure above --
   --ink clears 12.78:1 (tests/test_a_colour_is_read_against_its_own_ground.py). */
.questions-intro { margin: 0 0 12px; font-size: 13px; color: var(--ink); line-height: 1.55; }
.questions-list {
  margin: 0; padding-left: 18px;
  font-size: 14.5px; line-height: 1.5;
  display: flex; flex-direction: column; gap: 10px;
  font-weight: 600;
}
.questions .btn { margin-top: 14px; padding: 10px 0; border: none; background: var(--ask); color: var(--card); }

/* ==================================================================   THE PAGE FRAME
   ==================================================================   Everything above this line describes a component. Everything below it
   describes the page those components sit on: the header, the column, the
   forms and the footer that every one of the application's surfaces inherits
   from base.html. It is written as element rules wherever it can be, because
   forty templates already exist and none of them were going to be revisited
   to add a class to every <input>. */

/* ---- rhythm ------------------------------------------------------------ */

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

body {
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* A column layout with a growing <main> is what keeps the footer at the
     bottom of a short page — /signin is two fields, and a footer floating
     mid-screen reads as a page that failed to load. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* LIGHT, BECAUSE THIS STYLESHEET IS. The header of this file says so — the
   dark theme's two blocks were deleted by decision — and every one of the
   ~40 tokens at :root above is an unconditional light value.

   This line used to read `light dark`, with a comment about controls
   following the theme "rather than staying stubbornly light on a dark page".
   There is no dark page for them to follow. What it actually did was invite
   the browser to paint, in dark, every part the author did not: a dark
   scrollbar track running down the white interview sheet, and unchecked
   checkboxes and radios rendered dark-on-dark against `accent-color` below.
   Declaring one theme and opting into two is the mismatch, not the fix. If a
   dark theme is wanted, it is those two blocks coming back — not this word. */
:root { color-scheme: light; }

h1, h2, h3, h4 { line-height: 1.2; letter-spacing: -.015em; margin: 0 0 12px; }
h1 { font-size: var(--t-display); font-weight: 800; }
h2 { font-size: var(--t-title); font-weight: 800; }
h3 { font-size: 17px; font-weight: 700; }
h4 { font-size: 15px; font-weight: 700; }
main > h1, main > h2 { margin-top: 0; }
main > * + h2, main > * + h3 { margin-top: 32px; }
p { margin: 0 0 12px; max-width: var(--col-text); }
main > p, main > ul, main > ol, main > dl { margin-bottom: 16px; }
hr, .rule { border: 0; border-top: 1px solid var(--line); margin: 28px 0; }
small { font-size: 13px; color: var(--mut); }
strong { font-weight: 700; }

/* ---- header ------------------------------------------------------------ */

.site {
  background: var(--card);
  border-bottom: 1px solid var(--line);
}
.site-inner {
  max-width: var(--col);
  margin: 0 auto;
  padding: 12px var(--gutter);
  display: flex;
  align-items: center;
  gap: 10px 24px;
  /* WRAPPING IS THE RELIEF VALVE, AT EVERY WIDTH. It used to start at 900px,
     and between 900 and 1440 the row could not wrap, so the only thing that
     could give was the nav — which has `flex: 1 1 auto` and was therefore the
     one item that shrank. Measured on the running site: the person who is both
     sides of this market and has not yet said which carries a session block
     628px wide (her name, the question, its two answers, and Sign out), which
     left the navigation 164px at 1024 and stacked it five deep. The rule below
     the 900px breakpoint already says three things cannot share this row when
     one of them ends up too narrow to read; this makes that true by content
     rather than only by viewport. */
  flex-wrap: wrap;
}

/* The wordmark is the brand row's name plus a mark drawn from its first
   letter — no image file, so a second brand is still a configuration change
   and not an asset pipeline. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--ink);
  font-weight: 800;
  font-size: 18px;
  letter-spacing: -.02em;
  white-space: nowrap;
  /* Top-aligned for the same reason the session block is: the nav between
     them may be one line or two, and the wordmark should not float. */
  align-self: flex-start;
  padding-top: 1px;
}
.wordmark:hover { color: var(--brand-text); }
.wordmark-mark {
  width: 30px; height: 30px;
  border-radius: 9px;
  background: var(--brand);
  color: var(--brand-ink);
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 800;
  text-transform: uppercase;
}

/* The surfaces are the flexible part of the header, and they are now the SHORT
   part of it: a visitor has two, a carer three, and the person with the most of
   this product — both sides of the market, question still open — has four and a
   disclosure. It used to be eight and eleven, one flat row, which is the row
   this block was written to stop clipping. They still wrap onto a second line
   rather than clipping — a nav link truncated to "No…" with no visible
   scrollbar is indistinguishable from a broken page — but on a phone there is
   now rarely a second line to wrap onto.

   TASK-142 MOVED THE DISCLOSURE OUT OF THIS ROW, into `.session` beside the
   name it now hangs off (see below) — so this no longer needs to be the
   panel's anchor, and is not positioned any more. */
.surfaces {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: 1 1 auto;
  /* A FLOOR, not zero. `min-width: 0` is what let the nav be squeezed to a
     column of one-word lines rather than pushing the session block onto a row
     of its own: a flex item that may shrink to nothing always will. 16rem is
     three pills, which is the narrowest this is still a row. Below 900px the
     rule at the end of this block gives it the whole width anyway, so the
     floor is never the thing that decides a phone — and `min()` caps it at the
     container so a 280px screen cannot be given a 256px floor and a scrollbar
     with it. */
  min-width: min(16rem, 100%);
  flex-wrap: wrap;
}
.surfaces a {
  display: inline-block;
  padding: 7px 11px;
  border-radius: var(--r-pill);
  font-size: 14px;
  font-weight: 600;
  color: var(--mut);
  text-decoration: none;
  white-space: nowrap;
}
.surfaces a:hover { background: var(--brand-soft); color: var(--ink); }
/* Where you are is part of navigation, not decoration: the header is the only
   thing on most of these pages that says which surface you are on. */
.surfaces a[aria-current="page"] { background: var(--brand-soft); color: var(--brand-text); }

/* A thing you DO, told apart from the places you go. The row had "Post a job"
   sitting between "Nannies" and "Messages" as though writing an advert were
   somewhere you browse to. Soft and not solid: a filled brand button in the
   corner of all fifty pages reads as the site advertising itself, and this
   header is not where anything is sold.

   TASK-273: this used to paint the SAME --brand-soft fill as [aria-current]
   above, so a page with a current item AND an action showed two identical
   pills -- "where you are" and "a thing you do" reading as one meaning
   instead of two. --brand-soft is now spoken for by "where you are" alone.
   The action is told apart by a rule and a weight rather than a second
   fill: still not a filled brand button (the argument above still holds),
   still not the unfilled --mut of a plain destination either. Border width
   is subtracted from the padding so the pill's footprint doesn't grow
   against its neighbours. --brand-text on the header's --card is 7.71:1
   (tests/test_a_colour_is_read_against_its_own_ground.py). */
.surfaces .act {
  border: 1.5px solid var(--brand-text);
  padding: 5.5px 9.5px;
  color: var(--brand-text);
  font-weight: 700;
}
.surfaces .act:hover { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); }

/* EVERYTHING ELSE OF HERS, one disclosure away. A <details>, so it opens with
   no script on the page — this is a server-rendered site and its header must
   not need a runtime. What the rules below do is stop it looking like a
   browser default: a triangle in the text flow and a block of links shoving
   the page down when it opens. */
.menu > summary {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 11px;
  border-radius: var(--r-pill);
  font-size: 14px;
  font-weight: 600;
  color: var(--mut);
  white-space: nowrap;
  cursor: pointer;
  /* Both, because the two engines hide the marker differently and a summary
     that keeps its default triangle is a control that looks like a bullet. */
  list-style: none;
}
.menu > summary::-webkit-details-marker { display: none; }
/* Drawn, not typed. A "▾" is a character: it inherits the font stack, and it
   lands on a different baseline on every platform that has to substitute for
   it. */
.menu > summary::after {
  content: "";
  width: 0; height: 0;
  border: 4px solid transparent;
  border-top-color: currentColor;
  margin-top: 3px;
}
.menu > summary:hover,
.menu[open] > summary { background: var(--brand-soft); color: var(--ink); }
/* You are standing on a page that lives inside this menu. The header is the
   only thing on most of these pages that says which surface you are looking
   at, and that has to go on being true for a destination that moved behind a
   disclosure. */
.menu > summary.menu-here { background: var(--brand-soft); color: var(--brand-text); }
/* TASK-142: THE SAME DISCLOSURE, NOW SUMMARISED BY THE AVATAR AND NAME
   rather than the word "Yours" — `.who`'s own weight and colour still read
   as an identity rather than a nav item, and `.menu > summary` alone would
   have overridden both (a later, more specific selector on the same
   element). This is the one place they combine, so it is stated once here
   rather than left to whichever rule happens to come last. */
.menu > summary.who { color: var(--ink); font-weight: 700; }

/* Anchored to the NAV rather than to its own <details> — see .session below.
   The <details> stays unpositioned on purpose: it is a few pixels wide and a
   panel measured against it would be measured against nothing.

   RIGHT, NOT LEFT (TASK-142). This used to hang off `.surfaces`, the wide
   flexible nav on the LEFT, so its own left edge was a sane anchor. It now
   hangs off `.session`, which sits flush against the right edge of the
   header (`margin-left: auto`) — anchoring the panel's LEFT edge there would
   let a wide panel run off the right side of the viewport, which is exactly
   the "measured against nothing inside the page" fault the note above
   already refuses once. */
.menu-panel {
  position: absolute;
  z-index: 20;
  top: calc(100% + 6px);
  right: 0;
  min-width: 15rem;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  padding: 8px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow);
}
/* The heading is the whole point of the panel. Seven destinations in a column
   is the same list that was in the row; three of them under "Your hiring" is
   something a person can skip in one glance. */
.menu-head {
  margin: 10px 8px 3px;
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--mut);
}
.menu-head:first-child { margin-top: 2px; }
/* TASK-142 RE-PAIRS THIS, following the pattern `.fk-drafted .fk-block-head p`
   already set for `--mut` on `--card` vs `--brand-soft` (tests/test_a_colour_is_read_against_its_own_ground.py).
   Moving the disclosure into `.session` put these links where
   `.session > a:not(.btn) { color: var(--mut) }` — written for the plain
   "Sign in" and fallback `.who` links that ARE its direct children — now
   also resolves against, at (0,2,1) versus `.menu-panel a`'s own (0,1,1):
   `--mut` on `--brand-soft` (this row's hover ground) measures 4.31:1,
   0.19 short of the 4.5:1 floor that register holds every pair to. Named
   through the whole ancestor chain so the specificity is unambiguously
   higher rather than tied on source order. */
.session .menu .menu-panel a { color: var(--ink); }
.menu-panel a {
  padding: 9px 8px;
  border-radius: 9px;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.menu-panel a:hover { background: var(--brand-soft); }
.menu-panel a[aria-current="page"] { background: var(--brand-soft); color: var(--brand-text); }

.session {
  /* TASK-142: anchors `.menu-panel` now — see the note above it. */
  position: relative;
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
  flex-wrap: nowrap;
  /* Pinned to the top of the row so a nav that has wrapped onto two lines
     does not drag "Sign out" down the page with it. */
  align-self: flex-start;
  padding-top: 1px;
}
.who {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  min-width: 0;
  white-space: nowrap;
}
.who-name { overflow: hidden; text-overflow: ellipsis; max-width: 22ch; }
.who .avatar { width: 28px; height: 28px; font-size: 11px; }
.signout { margin: 0; }

/* Which side of the market you are being — see app/side.py. It renders for one
   person only: somebody who holds both a carer profile and a household, which
   is the edge case and not the norm. Everyone else's header is untouched, which
   is the point.

   Styled as part of the session block rather than as a surface, because it is
   not a destination: it is a statement about the account, in the place where
   the account already speaks. */
.viewing { margin: 0; display: inline-flex; align-items: center; gap: 6px; }
.viewing-ask {
  font-size: 13px;
  font-weight: 600;
  color: var(--mut);
  white-space: nowrap;
}
@media (max-width: 719px) {
  /* 719, not 720: jobs/list.html switches its chip rows at 719 and this file
     switched the header question at 720, so there was one pixel of viewport
     where the two disagreed about whether it was a phone. One boundary now.

     The question is the first thing to go: the two buttons under it still say
     what is being asked, and a header that wraps to three lines on a phone is
     worse than a question phrased by its own answers. */
  .viewing-ask { display: none; }
}
.session > a { font-size: 14.5px; font-weight: 700; text-decoration: none; }
.session > a:not(.btn) { padding: 8px 4px; color: var(--mut); }
.session > a:not(.btn):hover { color: var(--ink); }

@media (max-width: 900px) {
  .site-inner { flex-wrap: wrap; row-gap: 8px; }
  /* Below this width the surfaces take a line of their own: sharing one with
     the wordmark and the session leaves each of the three too little to be
     read. */
  .surfaces { order: 3; width: 100%; flex-basis: 100%; padding-bottom: 2px; }
}
@media (max-width: 560px) {
  /* On a phone the name and the sign-out control cannot both fit beside the
     wordmark. The initials stay — they are the identity everywhere else in
     this product, so they are the half that carries meaning. */
  .who-name { display: none; }
}

/* ---- the operator's strip ---------------------------------------------- */

/* A ROW OF ITS OWN, AND THAT IS THE WHOLE ARGUMENT. "Admin" used to sit in the
   surfaces between "Bookings" and "Notifications", which said that moderating
   is somewhere a parent might wander on the way to reading her messages. It is
   not: it is a different job, done by a different person wearing a different
   hat, with its own vocabulary, its own tables and its own stylesheet
   (operate.css). The strip says which hat is on.

   It offers and does not permit, like everything else in this header: /admin
   asks the store for an operator membership and 403s without one. And it
   survives both sides of the market, because moderating is neither hiring nor
   looking for work.

   Dark, so it is unmistakably not part of the product underneath it. The one
   dark surface in a light-only stylesheet is a statement, not a theme. */
/* THE QUESTION THIS ACCOUNT HAS NOT BEEN ASKED (app/side.py, migration 0101).

   A band under the header, on every page, for the one state where this product
   genuinely cannot tell which half of itself to show somebody: an account that
   holds both sides of the market, or neither, and has never answered. It is a
   band rather than a redirect because a redirect would interrupt whatever she
   came to do and lose what she had typed; the argument is written out in
   base.html.

   NOT DRESSED AS A WARNING. Nothing has gone wrong and she has done nothing:
   the question is ours to have failed to ask. So it wears the same quiet paper
   as the header above it with one hairline to separate them, and not the
   colour this stylesheet keeps for a refusal.

   Wraps at 390px: the question, then the two answers, then the link. The row
   is allowed to become four lines on a narrow phone rather than shrink the
   two controls below a thumb. */
.ask-strip {
  background: var(--bg);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.ask-strip-inner {
  max-width: var(--col);
  margin: 0 auto;
  padding: 8px var(--gutter);
  display: flex;
  align-items: center;
  gap: 8px 12px;
  flex-wrap: wrap;
}
.ask-strip .viewing-ask { font-size: 13.5px; font-weight: 700; }
.ask-strip a {
  font-size: 13px;
  color: var(--mut);
}

.operate-strip {
  background: var(--ink);
  color: var(--card);
}
.operate-strip-inner {
  max-width: var(--col);
  margin: 0 auto;
  padding: 5px var(--gutter);
  display: flex;
  align-items: center;
  gap: 4px 14px;
  flex-wrap: wrap;
}
.operate-tag {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  /* Not var(--mut): that is a colour for ink on paper and this is paper on
     ink. The label is a caption for the links beside it, so it recedes by
     being thinner rather than by being grey. */
  opacity: .68;
}
.operate-links { display: flex; flex-wrap: wrap; gap: 2px 4px; }
.operate-links a {
  display: inline-block;
  padding: 5px 10px;
  border-radius: var(--r-pill);
  font-size: 13.5px;
  font-weight: 700;
  color: inherit;
  text-decoration: none;
  white-space: nowrap;
}
.operate-links a:hover { background: rgba(255, 255, 255, .14); }
.operate-links a[aria-current="page"] { background: rgba(255, 255, 255, .20); }

/* ---- the column -------------------------------------------------------- */

main {
  width: 100%;
  max-width: var(--col);
  margin: 0 auto;
  padding: 32px var(--gutter) 56px;
  flex: 1 0 auto;
}
/* Full-bleed pages (the landing hero) opt out of the column's padding while
   keeping its width. */
main.flush { max-width: none; padding: 0; }

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

/* The AI disclosure keeps its own footer element — a page's disclosure belongs
   with the page, not with the site's colophon — but it needs the column too,
   because base.html renders it outside <main>. */
.disclosure {
  max-width: var(--col);
  margin: 0 auto;
  padding: 0 var(--gutter) 24px;
}
/* --mut on this box's own --ask-bg is 4.43:1 -- fails AA by 0.07
   (tests/test_a_colour_is_read_against_its_own_ground.py), on a footer that renders on most of the product.
   --ink clears 12.78:1 here and is what `.fk-drafted .fk-block-head p` swaps
   to for the same reason. */
.ai-disclosure {
  margin: 0;
  font-size: 13px;
  color: var(--ink);
  background: var(--ask-bg);
  border-radius: 12px;
  padding: 10px 14px;
  max-width: var(--col-text);
}

.site-footer {
  background: var(--card);
  border-top: 1px solid var(--line);
  margin-top: auto;
}
.site-footer-inner {
  max-width: var(--col);
  margin: 0 auto;
  padding: 26px var(--gutter) 34px;
  display: flex;
  flex-wrap: wrap;
  gap: 14px 40px;
  align-items: flex-start;
}
.site-footer .wordmark { font-size: 15px; }
.site-footer .wordmark-mark { width: 24px; height: 24px; font-size: 12px; border-radius: 7px; }
.footer-links { display: flex; flex-wrap: wrap; gap: 4px 18px; }
.footer-links a { font-size: 14px; font-weight: 600; text-decoration: none; }
.footer-links a:hover { text-decoration: underline; }
.footer-note {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--mut);
  max-width: 46ch;
  margin-left: auto;
}

/* ==================================================================   FORMS AND CONTROLS
   ========================================================================= */

/* Element selectors on purpose. Every form in this application is plain HTML
   written before there was a stylesheet — `<label>Email <input></label>` — and
   it has to come out looking deliberate without anybody editing it. The
   classes below (.field, .form-actions, .input) exist for templates that want
   to say it explicitly; both routes produce the same control. */

form { margin: 0 0 20px; }

label, .label {
  display: block;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--mut);
  margin-bottom: 14px;
}
.field { margin-bottom: 14px; }

input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
select,
textarea,
.input {
  display: block;
  width: 100%;
  max-width: 26rem;
  margin-top: 6px;
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
  background: var(--card);
  border: 1.5px solid var(--line);
  border-radius: var(--r-input);
  padding: 10px 13px;
  transition: border-color .12s ease, box-shadow .12s ease;
}
textarea { min-height: 8em; line-height: 1.5; resize: vertical; }
select { max-width: 20rem; cursor: pointer; }

input:hover:not([type="hidden"]):not([type="submit"]):not([type="button"]),
select:hover, textarea:hover { border-color: var(--mut); }
input:focus, select:focus, textarea:focus, .input:focus {
  border-color: var(--brand);
  outline: none;
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}
::placeholder { color: var(--mut); opacity: .75; }
input:disabled, select:disabled, textarea:disabled {
  background: var(--bg);
  color: var(--mut);
  cursor: not-allowed;
}
input[type="checkbox"], input[type="radio"] {
  width: 17px; height: 17px;
  margin: 0 8px 0 0;
  accent-color: var(--brand);
  vertical-align: -2px;
  cursor: pointer;
}
/* A checkbox's label sits beside it, not above it. */
label:has(> input[type="checkbox"]), label:has(> input[type="radio"]) {
  display: flex;
  align-items: flex-start;
  gap: 2px;
  font-weight: 600;
  color: var(--ink);
}

/* An opt-out with its reason attached: the tick, the sentence it makes, and
   the paragraph saying what it does to what you are shown. The rule above
   already lays the tick beside the text; this lets that text be two lines of
   different weight without the hint inheriting the label's own. */
.tickbox { margin: 12px 0 0; gap: 8px; }
.tickbox > span { display: block; font-weight: 600; }
.tickbox .form-hint, .tickbox .fk-hint {
  display: block; margin: 4px 0 0; font-weight: 400;
}
/* WHAT A SUGGESTION WAS READ OUT OF, under the tick it belongs to. A sibling
   of the label rather than a child of it, because it is the family's own
   sentence quoted back and clicking it must not toggle the box. Indented past
   the checkbox so the quotation reads as belonging to the line above it. */
.fk-source { margin: 2px 0 12px 26px; font-weight: 400; }

fieldset {
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: 16px 18px;
  margin: 0 0 18px;
}
legend { font-size: 13px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--mut); padding: 0 6px; }

/* An unclassed <button> is the submit button of a plain form, so it gets the
   primary shape by default. Anything wearing .btn-* or .chip outranks this and
   keeps its own. */
button, input[type="submit"] {
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  border: none;
  border-radius: var(--r-pill);
  background: var(--brand);
  color: var(--brand-ink);
  padding: 10px 22px;
  cursor: pointer;
  line-height: 1.2;
}
button:hover, input[type="submit"]:hover { background: var(--link); }
button:disabled, input[type="submit"]:disabled { opacity: .5; cursor: not-allowed; }

.form-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 4px; }
.form-row { display: flex; flex-wrap: wrap; gap: 12px 16px; align-items: flex-end; }
.form-row label { margin-bottom: 0; }
.form-hint { font-size: 13px; color: var(--mut); margin: 6px 0 0; max-width: 52ch; font-weight: 500; }

/* A refusal is part of the product. It is a panel, not a red word floating
   above a field, because the person reading it has just been stopped. */
.form-error {
  margin: 0 0 16px;
  padding: 12px 14px;
  border-radius: 12px;
  border-left: 4px solid var(--danger);
  background: var(--danger-bg);
  color: var(--danger);
  font-size: 14.5px;
  font-weight: 600;
  max-width: 52ch;
}

/* A search form is a row, not a stack: /jobs puts a query box, a journey
   filter and a mode select on one line. */
form[role="search"] {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px 12px;
}
form[role="search"] input[type="search"] { max-width: 22rem; margin-top: 0; }
form[role="search"] label { margin-bottom: 0; }
form[role="search"] select { margin-top: 0; }
/* A label that wraps its own control ("Within [5] min" on /jobs) stays inline;
   a label that only names the field below it takes the whole row, or it reads
   as a third control on the line. */
form[role="search"] > label:not(:has(input)):not(:has(select)) { flex-basis: 100%; }

/* ==================================================================   SMALL UTILITIES
   ========================================================================= */

.stack { display: grid; gap: 16px; }
.stack-sm { display: grid; gap: 10px; }
.cluster { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.actions { display: flex; flex-wrap: wrap; gap: 10px; margin: 16px 0 0; }
.page-head { margin-bottom: 24px; }
.kicker {
  display: block;
  font-size: 12.5px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--brand-text);
  margin-bottom: 8px;
}
.lede { font-size: var(--t-lead); line-height: 1.55; color: var(--mut); max-width: 58ch; }
.bare { list-style: none; padding: 0; margin: 0; }
.ticks { list-style: none; padding: 0; margin: 0; display: grid; gap: 8px; }
.ticks li {
  position: relative;
  padding-left: 26px;
  font-size: 14.5px;
  line-height: 1.5;
}
/* A drawn tick, not an emoji: it inherits the theme's green and a screen
   reader is never handed a decorative character. */
.ticks li::before {
  content: "";
  position: absolute;
  left: 4px; top: 6px;
  width: 6px; height: 11px;
  border: solid var(--v-fill);
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(45deg);
}

/* ==================================================================   THE LANDING PAGE
   ========================================================================= */

/* The landing page uses the same Harbour palette as the application. Text
   sits on solid surfaces; the photograph has its own space and caption. */
.hero { background: var(--brand-soft); border-bottom: 1px solid var(--line); }
.hero-inner {
  max-width: var(--col); margin: 0 auto; padding: 64px var(--gutter);
  display: grid; grid-template-columns: 1.15fr .85fr; gap: 44px; align-items: center;
}
.hero-copy { min-width: 0; }
.hero h1 {
  font-size: clamp(36px, 3.5vw, 48px); line-height: 1.08;
  font-weight: 750; letter-spacing: -.045em; max-width: none;
  margin: 18px 0 24px; color: var(--ink); text-wrap: balance;
}
.hero h1 span { color: var(--brand-text); }
.hero .lede { font-size: 18px; line-height: 1.65; color: var(--ink); max-width: 43ch; }
.hero-doors { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 28px; }
.door {
  position: relative; min-width: 0; flex-direction: column; align-items: flex-start;
  justify-content: center; gap: 5px; padding: 18px 30px 18px 18px;
  border-radius: 14px; border: 1px solid var(--brand);
  background: var(--card); color: var(--ink); text-align: left;
}
.door::after { content: "↗"; position: absolute; right: 12px; top: 16px; color: var(--brand-text); }
.door:hover, a.door:hover { background: var(--bg); color: var(--ink); box-shadow: var(--shadow); }
.door-for { font-size: 10.5px; font-weight: 750; letter-spacing: .055em; text-transform: uppercase; color: var(--brand-text); }
.door-do { font-size: 16px; font-weight: 750; letter-spacing: -.015em; }
.hero-note { margin: 18px 0 0; font-size: 13px; color: var(--ink); }
.hero-picture { margin: 0; align-self: stretch; min-height: 400px; display: flex; flex-direction: column; }
.hero-picture img { width: 100%; height: 100%; min-height: 0; flex: 1; object-fit: cover; object-position: 57% center; border-radius: 120px 24px 24px 24px; }
.hero-picture figcaption { padding: 14px 0 0; font-size: 13px; color: var(--brand-text); text-align: right; }
.home-welcome { margin-top: 16px; max-width: 32rem; }
.home-welcome summary { cursor: pointer; color: var(--brand-text); font-size: 13px; width: fit-content; padding: 6px 0; }
.hero .hear-said { color: var(--ink); }
.hero audio { max-width: 100%; }
.home { max-width: var(--col); margin: 0 auto; padding: 76px var(--gutter) 0; }
.home:last-of-type { padding-bottom: 76px; }
.home-head { margin-bottom: 30px; }
.home-head h2 { font-size: clamp(27px, 3vw, 36px); line-height: 1.18; letter-spacing: -.035em; max-width: 28ch; margin: 10px 0 14px; text-wrap: balance; }
.home-head p { color: var(--mut); max-width: 55ch; line-height: 1.65; }
.home-page .kicker { color: var(--brand-text); font-size: 11px; letter-spacing: .1em; font-weight: 750; text-transform: uppercase; }
.sides { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.side { display: flex; flex-direction: column; gap: 16px; padding: 28px; overflow: hidden; box-shadow: none; }
.side h2 { margin: 0; font-size: 29px; letter-spacing: -.03em; }
.side > p { margin: 0; font-size: 16px; line-height: 1.65; color: var(--mut); }
.side .ticks { margin: 0 0 6px; font-size: 14px; line-height: 1.65; }
.side .actions { margin-top: auto; padding-top: 10px; }
.side-pic { display: block; width: calc(100% + 56px); max-width: none; margin: -28px -28px 10px; aspect-ratio: 2.65 / 1; height: auto; object-fit: cover; background: var(--brand-soft); }
.home-search { display: flex; align-items: center; gap: 24px; margin: 24px 0 0; padding: 24px 28px; background: var(--brand-soft); border-radius: var(--r-card); }
.home-search label { flex: 1; margin: 0; font-size: 16px; color: var(--ink); }
.home-search-controls { display: flex; flex: 1.5; gap: 10px; min-width: 0; }
.home-search input[type="search"] { min-width: 0; width: 100%; max-width: none; flex: 1; background: var(--card); }
.steps { counter-reset: step; display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; list-style: none; padding: 0; margin: 0; }
.steps li { counter-increment: step; position: relative; padding: 68px 0 0; border: 0; border-top: 1px solid var(--line); border-radius: 0; background: transparent; box-shadow: none; }
.steps li::before { content: "0" counter(step); position: absolute; top: 20px; left: 0; color: var(--brand-text); font-size: 22px; font-weight: 650; }
.steps h3 { margin: 0 0 10px; font-size: 20px; letter-spacing: -.02em; }
.steps p { margin: 0; font-size: 15px; line-height: 1.7; color: var(--mut); }
.home-trust { display: grid; grid-template-columns: .85fr 1.15fr; gap: 60px; align-items: center; }
.home-trust .home-head { margin: 0; }
.home-trust .home-head > p + p { margin-top: 16px; }
.sample { padding: 24px 28px 18px; box-shadow: none; }
.sample-caption { font-size: 12px; font-weight: 750; color: var(--mut); text-transform: uppercase; letter-spacing: .08em; margin: 0 0 12px; }
.sample .claim-row + .claim-row { border-top: 1px solid var(--line); }
.sample .claim-text { font-size: 14px; }
.sample .claim-note { font-size: 13px; margin-bottom: 2px; }
.closing-line { display: flex; justify-content: space-between; align-items: center; gap: 32px; padding: 40px; border-radius: 24px; background: var(--brand-soft); }
.closing-line h2 { font-size: clamp(26px, 3vw, 32px); letter-spacing: -.03em; margin: 10px 0 14px; }
.closing-line p { color: var(--ink); font-size: 15px; margin: 0; }
.closing-actions { flex-shrink: 0; text-align: center; }
.closing-actions p { font-size: 13px; margin-top: 12px; }
@media (max-width: 959px) {
  .hero-inner { gap: 28px; grid-template-columns: 1.2fr .8fr; padding-top: 44px; padding-bottom: 44px; }
  .hero-doors { grid-template-columns: 1fr; }
  .hero-picture { min-height: 360px; }
  .home-trust { gap: 28px; }
  .home-search { flex-direction: column; align-items: stretch; gap: 14px; }
  .closing-line { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 719px) {
  .hero-inner { grid-template-columns: 1fr; padding-top: 32px; padding-bottom: 28px; gap: 28px; }
  .hero h1 { font-size: clamp(34px, 8vw, 48px); max-width: none; margin: 14px 0 18px; }
  .hero .lede { font-size: 16px; }
  .hero-doors { grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 22px; }
  .door { padding: 15px 22px 15px 12px; }
  .door-for { font-size: 9px; letter-spacing: .025em; }
  .door-do { font-size: 14px; }
  .door::after { right: 8px; top: 11px; font-size: 14px; }
  .hero-picture { min-height: 0; height: 220px; }
  .hero-picture img { border-radius: 48px 16px 16px 16px; }
  .hero-picture figcaption { font-size: 12px; padding-top: 10px; }
  .home { padding-top: 48px; }
  .home:last-of-type { padding-bottom: 48px; }
  .home-head { margin-bottom: 24px; }
  .sides, .steps, .home-trust { grid-template-columns: 1fr; }
  .side { padding: 24px; }
  .side-pic { width: calc(100% + 48px); margin: -24px -24px 6px; }
  .home-search { padding: 22px; }
  .home-search-controls { flex-direction: column; }
  .steps { gap: 24px; }
  .steps li { padding-top: 62px; }
  .home-trust { gap: 24px; }
  .sample { padding: 20px; }
  .closing-line { padding: 28px 24px; gap: 24px; }
  .closing-actions { text-align: left; }
}
@media (max-width: 359px) {
  .hero-doors { grid-template-columns: 1fr; }
  .door-for { font-size: 10px; }
  .door-do { font-size: 16px; }
}

/* ---- what a job actually pays ------------------------------------------ */

/* Deliberately quieter than the advert it sits under: this is an estimate
   beside a stated fact, and it must not out-shout the family's own words. */
.takehome {
  margin: 18px 0 0;
  padding: 18px 20px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
}
.takehome h2 { margin: 0 0 4px; font-size: 17px; }
.takehome h3 { margin: 14px 0 4px; font-size: 14px; }
.takehome p { margin: 6px 0 0; font-size: 14px; line-height: 1.55; color: var(--mut); }
.takehome-lede { color: var(--ink) !important; }

.takehome-rows { margin: 14px 0 0; display: grid; gap: 2px; }
.takehome-rows > div {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--line);
}
.takehome-rows dt { font-size: 14px; color: var(--mut); }
/* tabular-nums so the column of money lines up on the decimal rather than
   wandering with the digits. */
.takehome-rows dd {
  margin: 0; font-size: 15px; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.takehome-out dd, dd.takehome-out { color: var(--mut); font-weight: 600; }
.takehome-total { border-bottom: none !important; padding-top: 10px !important; }
.takehome-total dt { font-weight: 700; color: var(--ink) !important; font-size: 15px !important; }
.takehome-total dd { font-size: 19px; }
.takehome-per { display: block; font-size: 12.5px; font-weight: 500; color: var(--mut); }

.takehome-pension { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.takehome-cost {
  margin-top: 12px !important; padding: 10px 14px;
  background: var(--bg); border-radius: var(--r-input);
}

.takehome-controls {
  /* flex-start, not flex-end: one of these labels carries a hint underneath
     it, and aligning on the bottom edge then staggers every other control. */
  display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line);
}
.takehome-controls label { font-size: 12.5px; font-weight: 700; color: var(--mut); }
.takehome-controls input[type="number"], .takehome-controls input[name="tax_code"],
.takehome-controls select {
  display: block; margin-top: 4px; padding: 7px 10px; font: inherit; font-size: 14px;
  border: 1.5px solid var(--line); border-radius: var(--r-input); background: var(--card);
  color: var(--ink);
}
.takehome-check { flex-direction: row !important; align-items: center; gap: 6px;
                  font-weight: 600; padding-top: 22px; }
.takehome-controls button { margin-top: 20px; }
.takehome-check input { margin: 0; }

.takehome-caveat {
  margin-top: 12px !important; font-size: 12.5px !important; line-height: 1.5 !important;
}

.takehome-controls label { display: flex; flex-direction: column; }
.takehome-controls input[name="tax_code"] { width: 7rem; }
.takehome-controls input[type="number"] { width: 5rem; }
.takehome-hint {
  margin-top: 4px; font-size: 11.5px; font-weight: 500; color: var(--mut);
  max-width: 22ch; line-height: 1.35;
}

/* The agreed rate, beside the time on a booking row. A middot separator rather
   than a chip: it is one more fact about the same arrangement, not a state. */
.record-rate { color: var(--ink); font-weight: 700; }
.record-rate::before { content: "\00b7"; color: var(--mut); font-weight: 400; margin: 0 6px; }

/* A note about units, on an applicant row. Quiet: it is information for a
   conversation, not a warning about a person, and it must not read as a mark
   against her. */
.record-flag {
  margin: 6px 0 0;
  padding: 8px 12px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--sun-soft);
  border-radius: var(--r-input);
  max-width: 60ch;
}

/* Day / month / year as three boxes. Sized to their content so the shape of
   the field says what belongs in it before the label is read.

   THE WIDTHS ARE REPEATED THROUGH THE FULL :not() CHAIN, and that is not
   belt-and-braces. `.date-parts input` is specificity (0,1,1); the shared
   control rule is `input` plus FIVE attribute :not()s, which is (0,5,1), and
   it wins on every property the two share however late this file says
   otherwise. (the form-kit section below calls it "the six-:not() chain"; there are five
   of them, and the sixth term in (0,5,1) is the `input` itself.) So `width: 4rem` here never applied: the boxes have been taking
   the shared `width: 100%` and then shrinking to whatever the `size`
   attribute happened to make them - 78px, 78px and 94px, not 64/64/96. Same
   for the padding and the margin-top below. The form-kit section already pays this
   cost knowingly ("a chain like that beats any class"); this is the same
   toll on the same road. */
.date-parts { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.date-parts label { display: flex; flex-direction: column; }
.date-parts input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]) {
  width: 4rem;
  max-width: none;
  margin-top: 4px;
  padding: 8px 10px;
}
.date-parts label:last-child input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]) {
  width: 6rem;
}

/* She is above what this advert can reach. A note, not a refusal: the page is
   still hers to read and the application is still hers to make. */
.over-budget {
  margin: 14px 0 0;
  padding: 10px 14px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink);
  background: var(--sun-soft);
  border-radius: var(--r-input);
  max-width: 62ch;
}

/* What decides employment status, at the foot of a family's bookings. Quiet:
   it is the ordinary truth about casual work rather than a warning. */
.status-note {
  max-width: var(--col-text);
  margin: 22px auto 0;
  padding: 12px 16px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--mut);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
}

/* A date as three boxes, self-contained so the macro works on any page. */
.datebox { border: none; margin: 0 0 4px; padding: 0; min-width: 0; }
 /* `legend`'s small caps are right for a caption ("PAY") and wrong for a
    question. This one asks "The date you are free from", and it has been
    shouting it: the base rule's text-transform and letter-spacing survive a
    child rule that only restates the size and the weight. The form kit's
    .fk-set legend already resets all three; this brings the datebox into
    line. providers/form.html's `.ticklist legend` has the same bug and needs
    the same two declarations, in its own block. */
.datebox > legend {
  padding: 0; font-size: 13px; font-weight: 700; color: var(--ink);
  text-transform: none; letter-spacing: normal;
}
/* Two words in one shape: a box that need not be filled in, and — where a
   page has promised the difference is marked — one that must be. */
.datebox-opt, .datebox-req {
  margin-left: 6px; font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--mut);
}
.datebox-hint {
  display: block; margin: 4px 0 0; font-size: 12.5px; font-weight: 400;
  line-height: 1.45; color: var(--mut); max-width: 52ch;
}
.date-parts label { font-size: 12.5px; font-weight: 700; color: var(--mut); }
.date-parts input {
  display: block; margin-top: 4px; padding: 8px 10px; font: inherit; font-size: 15px;
  border: 1.5px solid var(--line); border-radius: var(--r-input);
  background: var(--card); color: var(--ink); font-variant-numeric: tabular-nums;
}


/* ==================================================================   THE THUMB
   ==================================================================   Everything in here is a FLOOR rather than a point on a curve, which is why
   it steps instead of interpolating: 16px is the size under which Mobile
   Safari zooms a focused control, and 44px is the smallest target a person
   hits reliably holding a handrail. Neither is a proportion, so neither
   belongs in a clamp.

   GATED ON THE POINTER AND NOT ONLY ON THE WIDTH, and that is the whole
   point of the block. Both facts above are about a THUMB, and this was
   written as `max-width: 719px` alone — so an iPad, which is wide and has
   nothing but thumbs, got 31px buttons, 41px chips and 15px inputs. Measured
   on the running site at 768px before this line changed. The 15px is not a
   near miss either: iPad Safari zooms a sub-16px control on focus exactly as
   the phone does, so every tap into a form on an iPad threw the page.

   `pointer: coarse` is the primary query and the width is kept beside it for
   the narrow-window-with-a-mouse case. A desktop with a touchscreen gets the
   larger targets, which is the safer way to be wrong.

   The control rule repeats the :not() chain verbatim. Same specificity as
   the original, later in the file, so it wins on source order - and it stays
   under .fk-panel's, which only sets max-width and is not in this fight. */

@media (max-width: 719px), (pointer: coarse) {

  /* ---- the zoom threshold --------------------------------------------- */

  input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
  select,
  textarea,
  .input {
    font-size: 16px;
  }

  /* textarea is deliberately not here: it has its own 8em minimum, and a
     min-height of 44px would beat it and collapse six rows of somebody
     describing herself into one. */
  input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
  select,
  .input {
    min-height: 44px;
    padding: 11px 13px;
  }

  /* ---- a tick you can actually hit ------------------------------------- */

  input[type="checkbox"], input[type="radio"] {
    width: 24px; height: 24px;
    vertical-align: -6px;
  }
  /* The label is the target; the box is only the mark on it. This reaches
     .tick, .week-box and .tickbox without any of them being named, because
     all three are a label wrapping its own control. */
  label:has(> input[type="checkbox"]), label:has(> input[type="radio"]) {
    min-height: 44px;
  }

  /* ---- buttons, chips, links that act as buttons ----------------------- */

  .btn, button, input[type="submit"] { min-height: 44px; }
  /* .btn-sm is the one that matters: it is "Sign out" in the header of every
     page, "Clear filters" on /jobs and both sides of the viewing switch, and
     it renders 31.6px. It is not made bigger by growing the type - the type
     is small on purpose - it is made bigger by giving it a floor. */
  .btn-sm { font-size: 14px; }
  .btn-sm.btn-primary, .btn-sm.btn-ghost, .btn-sm.btn-quiet { padding: 8px 16px; }

  .chip { font-size: 14px; padding: 10px 16px; min-height: 44px; }

  /* ---- the header ------------------------------------------------------ */

  /* Eight destinations at 35.7px tall and 2px apart is a row of targets that
     overlap in the thumb even though they do not overlap on the screen. */
  .surfaces { gap: 6px 4px; }
  .surfaces a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 12px;
  }
  /* "Sign in" is an anchor and not a .btn, so the rule above does not reach
     it - and it is the first control a signed-out visitor is offered. */
  .session > a:not(.btn) {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  /* The disclosure and what is inside it. The summary is a control and the
     rule above reaches only .btn and <button>; the panel's links carry a
     class, so `.surfaces a` loses to them on specificity however late it
     appears. Both need saying again rather than relying on either. */
  .menu > summary { min-height: 44px; padding: 0 12px; }
  .menu-panel a {
    display: flex;
    align-items: center;
    min-height: 44px;
  }
  /* A column of targets 44px tall wants breathing room between them or the
     thumb lands on the neighbour; 2px of it, so the panel does not grow a
     scroll of its own on a short phone. */
  .menu-panel { gap: 2px; }
  /* The assistant's own disclosure, for the same reason as the menu's: a
     <summary> is a control, and tests/ui/test_hiring_workflow_mobile.py
     measured this one at 39.7px on a phone. It renders on every signed-in
     page, so it is the most-drawn control in the product. */
  .ask-here > summary { min-height: 44px; padding: 0 12px; }
  .operate-links a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  /* ---- prose ----------------------------------------------------------- */

  /* The line is 45 characters here. That is under the measure, not over it,
     so nothing is capped - but a short measure is where a ragged last line
     shows most, and this is the one width where it is worth the reflow. */
  p, .lede, .form-hint, .fk-hint, .claim-note { text-wrap: pretty; }
}


/* ======================================================================== *
 * THE FORM KIT
 *
 * These rules lived in app/templates/_formkit.html as a 20 KB <style> block
 * included by THIRTY-THREE pages -- so every one of those pages carried the
 * same 20 KB inline, uncached, on every request. They are appended here
 * rather than merged into the sections above so that cascade order is
 * unchanged: the partial was included from {% block head %}, which base.html
 * emits after this stylesheet is linked, so "after everything else" is
 * exactly where these rules already were.
 *
 * The partial's own note, kept because it explains why the kit exists:
 *  The form kit — the shared look of the pages where somebody joins, posts or
 *     is interviewed.
 *
 *     It lives in ONE partial rather than in eight <style> blocks because these
 *     eight surfaces are one flow: sign up, create the household, answer the
 *     interview, read the draft, approve it. A family walks the whole thing in a
 *     single sitting and a visual seam between two of those steps reads as two
 *     different products.
 *
 *     Everything here is a LAYOUT on top of app/static/neo.css, never a second
 *     visual language: the colours, radii, shadows, buttons and provenance pills
 *     all come from the stylesheet's tokens. The rules that follow only do the
 *     things a stylesheet written for cards and pills could not know about a
 *     form — the measure of a column, the width of a box that holds one digit,
 *     and the difference between what a family said and what was drafted for
 *     them.
 *
 *     Included from {% block head %}, so it is in the document head where a
 *     stylesheet belongs.
 * ======================================================================== */
/* ---- the page ---------------------------------------------------------- */

/* A form column and, beside it, what the page owes the reader: what happens
   next, what is optional, what is never published. On a phone the aside
   follows the form, which is also the order they matter in. */
.fk-page { display: grid; gap: 26px 40px; align-items: start; }
@media (min-width: 960px) { .fk-page { grid-template-columns: minmax(0, 1fr) 19rem; } }
/* One column, held to a readable measure. A 1080px-wide login box is not a
   calm surface; it is a form that has been left where it fell. */
.fk-solo { max-width: 34rem; }
.fk-centre { max-width: 27rem; margin-inline: auto; }
.fk-centre .fk-head { text-align: center; }

/* A refusal panel is about the form it sits above, so it takes the width of
   the form rather than the stylesheet's default reading measure. */
.fk-page .form-error, .fk-solo .form-error, .fk-centre .form-error { max-width: none; }

.fk-head { margin-bottom: 22px; }
.fk-head h1 { margin-bottom: 10px; }
/* No font-size here. This used to hold the lede at a flat 16.5px, which was
   half a pixel under the stylesheet's own `.lede` and therefore a whole
   separate size to maintain — and once the ramp arrived it was worse than
   redundant: it pinned the form pages to 16.5px while every other page's lede
   grew from 17px on a phone to 19px on a desktop. The kit lays these pages
   out; it does not own how big a lede is. */
.fk-head > :last-child { margin-bottom: 0; }

/* ---- the panel --------------------------------------------------------- */

/* Fields sit on the card, not on the page: it gives the form one edge to
   start from and the actions a floor to stand on. */
.fk-panel { display: grid; gap: 18px; padding: 24px 26px; }
.fk-panel > form { margin: 0; display: grid; gap: 18px; }
.fk-panel > form > fieldset { margin: 0; }
/* The label IS the question on these pages, so it is ink rather than the
   stylesheet's muted grey, and the hint under it carries the quiet half. */
.fk-panel label { margin-bottom: 0; color: var(--ink); font-size: 14.5px; }
/* The stylesheet holds a bare input to a 26rem measure, which is right on a
   page and wrong inside a panel that already has one. The :not() chain is
   repeated here rather than shortened because a chain like that beats any
   class: this is what saying "wider than the default" costs without reaching
   for !important. FIVE :not()s, not six — this comment said six for as long
   as it existed. The shared control rule is `input` plus five attribute
   :not()s, which is (0,5,1): five in the class column, and the one term in
   the element column is the `input` itself. Anything here that means to beat
   it has to carry the same five and add a class of its own.

   And `none` rather than a percentage, because the three interview pages are
   scanned for "<digits>%" by the guard that keeps a percentage off a person
   — and a style block is part of the page it is served in. */
.fk-panel input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
.fk-block input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]) { max-width: none; }
.fk-panel textarea, .fk-block textarea { max-width: none; }
/* Except where the content has a size of its own: four options do not need
   the width of a paragraph. The date rule that used to sit here styled
   `input[type="date"]`, and there are none left — dates are three boxes now
   (app/templates/_datebox.html), sized by `.date-parts`. */
.fk-panel select, .fk-block select { max-width: 22rem; }
.fk-hint {
  display: block;
  margin-top: 3px;
  font-size: 13px;
  font-weight: 500;
  color: var(--mut);
  line-height: 1.5;
  max-width: 52ch;
}
.fk-set { border: 1px solid var(--line); border-radius: var(--r-card); padding: 16px 18px; display: grid; gap: 14px;
  /* A FIELDSET DOES NOT SHRINK. Its UA default is `min-width: min-content`,
     so a wide child sets a floor the element will not go below however narrow
     the viewport gets -- measured here at a constant 395px at every width from
     320 to 390. Every other block element would have shrunk. */
  min-width: 0;
}
/* A group's legend is a question here, not a caption: it is asked in the same
   voice and at the same size as the labels inside it, rather than in the
   stylesheet's small caps. */
.fk-set > legend {
  padding: 0 6px;
  font-size: 14.5px; font-weight: 800;
  text-transform: none; letter-spacing: 0; color: var(--ink);
}
.fk-set > legend .fk-req {
  font-size: 12px;
  font-weight: 700;
  color: var(--ink);
}
/* "Optional" said as a state rather than as an apology in brackets. */
.fk-opt { margin-left: 8px; }
/* "Optional" said as a state rather than as an apology in brackets. */
.fk-opt {
  display: inline-block;
  font-size: 10.5px; font-weight: 800;
  letter-spacing: .07em; text-transform: uppercase;
  color: var(--brand-text); background: var(--brand-soft);
  border-radius: var(--r-pill); padding: 3px 9px;
  vertical-align: 1px;
}

/* The actions get a floor: a rule, the primary action, and the sentence that
   says what pressing it does. Never a full-bleed button — a button as wide as
   a paragraph reads as a banner, not as a thing to press. */
.fk-foot {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 12px 16px; padding-top: 18px; border-top: 1px solid var(--line);
}
.fk-foot-note { margin: 0; font-size: 13px; color: var(--mut); flex: 1 1 13rem; max-width: 40ch; }
/* The same row without the rule, for a card that is nothing but the action. */
.fk-foot-bare { border-top: 0; padding-top: 0; }
.fk-approve { padding: 20px 24px; }

/* ---- the aside --------------------------------------------------------- */

.fk-aside { display: grid; gap: 14px; }
/* Between a phone and the two-column layout the aside sits under the form,
   where one card per line would be a very wide line for three short ones. */
@media (min-width: 620px) and (max-width: 959px) {
  .fk-aside { grid-template-columns: 1fr 1fr; align-items: start; }
}
.fk-side { padding: 18px 20px; border-radius: var(--r-card); background: var(--card); border: 1px solid var(--line); }
.fk-side-soft { background: var(--brand-soft); border-color: transparent; }
.fk-side h2 { font-size: 14px; font-weight: 800; margin-bottom: 10px; letter-spacing: 0; }
.fk-side p { font-size: 13.5px; color: var(--mut); line-height: 1.55; margin: 0 0 10px; }
.fk-side > :last-child { margin-bottom: 0; }
.fk-side .ticks li { font-size: 13.5px; color: var(--mut); }
/* --mut on --brand-soft is 4.31:1 -- fails AA by 0.19 (tests/test_a_colour_is_read_against_its_own_ground.py).
   --mut is fine on --card, which is every OTHER ground it sits on, so the fix
   is the pairing rather than the token: the same swap `.fk-drafted
   .fk-block-head p` already makes for the identical reason a few hundred
   lines down. --ink clears 12.44:1 here. */
.fk-side-soft p, .fk-side-soft .ticks li { color: var(--ink); }

/* Where the family is in the flow. Numbered because the interview genuinely
   has three stages, and marked with aria-current so it is a position and not
   a decoration. */
.fk-flow { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; counter-reset: fkstep; }
.fk-flow li {
  counter-increment: fkstep;
  display: grid; grid-template-columns: 26px 1fr; gap: 10px; align-items: start;
  font-size: 13.5px; line-height: 1.45; color: var(--mut);
}
.fk-flow li::before {
  content: counter(fkstep);
  width: 26px; height: 26px; border-radius: var(--r-pill);
  background: var(--bg); border: 1px solid var(--line); color: var(--mut);
  display: flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 800;
}
.fk-flow li[aria-current="step"] { color: var(--ink); font-weight: 700; }
.fk-flow li[aria-current="step"]::before { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); }

/* ---- counting children ------------------------------------------------- */

/* Five age bands, each holding at most two digits. The stylesheet's 26rem
   text box is right for a sentence and absurd for the number 2, so the band
   is a row: the question on the left, the box that answers it on the right. */

/* ---- the honest blank -------------------------------------------------- */

/* Unstated pay is information, not a gap. A dashed edge says "this may stay
   empty" in the one place a family is most likely to invent a number. */
.fk-blank {
  background: var(--bg); border: 1px dashed var(--line); border-radius: var(--r-input);
  padding: 12px 14px; font-size: 13.5px; line-height: 1.55; color: var(--mut);
}
.fk-blank strong { color: var(--ink); }

/* ---- what is already held, and what nobody asked ----------------------- */

/* §8. The interview comes back to a question whose own answer could not be
   read, and this is what we hold said back before the box — her sentence in
   quotes, on the brand's own soft ground, so it reads as ours repeating hers
   rather than as a warning about it. It is not a refusal and carries none of
   the refusal palette. */
.fk-held {
  margin: 0; padding: 12px 14px; border-radius: var(--r-input);
  background: var(--brand-soft); color: var(--ink);
  font-size: 14px; line-height: 1.55;
}
/* §9. The loop before publishing: the lines nobody has put a question for,
   NAMED and never counted. Quiet by construction — no tint, no rule down the
   side, nothing that reads as a warning — because absence here is a fact
   about the platform and not about the family, and the approve control three
   sections below it stays exactly as prominent as it was. */
.fk-notasked { display: grid; gap: 12px; }
.fk-notasked-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.fk-notasked-item {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 12px;
  padding: 12px 14px; border: 1px solid var(--line);
  border-radius: var(--r-input); background: var(--bg);
}
.fk-notasked-label { font-size: 15px; font-weight: 600; color: var(--ink); }
.fk-notasked-why { margin: 0; flex: 1 1 16rem; font-size: 13px; line-height: 1.5; color: var(--mut); }
.fk-notasked form { margin: 0; }
.fk-notasked-item .btn { min-height: 44px; }
@media (max-width: 719px) {
  .fk-notasked-item { flex-direction: column; align-items: stretch; }
  .fk-notasked-item .btn { width: 100%; }
}
/* Two money fields side by side. Their hints are different lengths, so the
   hint is the part that stretches and the boxes still line up. */
.fk-pair { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); }
.fk-pair label { display: flex; flex-direction: column; }
.fk-pair .fk-hint { flex: 1 1 auto; }
.fk-pair select { max-width: none; }
/* ---- said vs drafted --------------------------------------------------- */

/* The review page's whole argument. The family's own words sit on the white
   card the rest of the product uses for facts; the drafted advert sits on the
   brand tint behind a rule, so the two are told apart from across the room
   and before a single word is read. The provenance HUES are not borrowed for
   this: green, amber and purple mean verified, confirmed and unresolved, and
   a fourth meaning smuggled into that palette would cost more than it buys. */
.fk-block { border-radius: var(--r-card); padding: 22px 24px; display: grid; gap: 16px; }
.fk-said { background: var(--card); border: 1px solid var(--line); box-shadow: var(--shadow); }
.fk-drafted { background: var(--brand-soft); border: 1px solid transparent; border-left: 5px solid var(--brand-text); }
.fk-block-head { display: grid; gap: 4px; }
/* The family's own words are the "stated" end of the provenance vocabulary,
   so their kicker is the quiet grey that vocabulary uses; the draft's is the
   brand, because a machine — or this product's own arrangement of their
   sentences — is the thing being pointed at. */
.fk-said .kicker { color: var(--mut); }
/* The size a card's own title is, from the ramp, rather than a flat 20px
   that happened to match it at 390px and nowhere else. `--t-card` starts at
   the same 20px and reaches 22px on a desktop, which is what every other
   card title on the product does. */
.fk-block-head h2 { margin: 0; font-size: var(--t-card); }
.fk-block-head p { margin: 0; font-size: 13.5px; color: var(--mut); max-width: 56ch; }
.fk-drafted .fk-block-head p { color: var(--ink); }
.fk-block > form,
.fk-block .fk-fields { display: grid; gap: 16px; margin: 0; }
.fk-block label { color: var(--ink); font-size: 14.5px; margin-bottom: 0; }
.fk-block input:not([type="hidden"]), .fk-block select, .fk-block textarea { max-width: none; }
.fk-drafted input, .fk-drafted textarea { background: var(--card); }

/* The interview, played back. Each answer is the family's sentence, kept
   verbatim and marked as theirs by the quote rule down its left side. */
.fk-qa { display: grid; gap: 14px; margin: 0; }
.fk-qa > div { border-left: 3px solid var(--line); padding-left: 14px; }
.fk-q { margin: 0 0 4px; font-size: 13px; font-weight: 700; color: var(--mut); }
.fk-a { margin: 0; font-size: 15px; line-height: 1.55; color: var(--ink); }

/* ---- people ------------------------------------------------------------ */

/* Initials, never a face — here. Not a rule about the whole product any
   more: a carer may present themselves on their own profile page, and what they
   put there belongs to them. A list of parents is not that page. It is the plumbing
   of a household, saying who holds what, and a face on each of its rows would
   be decoration taken for granted rather than anything a reader came for. */
.fk-people { list-style: none; display: flex; flex-wrap: wrap; gap: 10px 18px; margin: 0; padding: 0; }
.fk-person { display: inline-flex; align-items: center; gap: 9px; font-size: 14.5px; font-weight: 600; }
.fk-member-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
/* A row, not a stack — and typed as `form.fk-inline` so it beats the
   panel's own `> form { display: grid }`. */
form.fk-inline { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; margin: 0; }
.fk-inline label { flex: 1 1 16rem; margin-bottom: 0; }
.fk-inline input { margin-top: 6px; }

/* ---- the second way in ------------------------------------------------- */

/* A hierarchy, not a split. The sign-in page has one promoted way in; the
   password is kept for the accounts that already have one and sits below it
   behind a sentence, so a reader is never asked to choose between two forms
   that look equally important. <details> does that with no script and no
   library, and a summary is focusable and announced as a disclosure without
   any help from us.

   Written without the obvious word for "put one thing under another": every
   page carrying this partial is scanned for the vocabulary that turns a
   person into a number, and a style block is part of the page it is served
   in. The rule at the top of this file says so; it is easy to forget twice. */
.fk-more { margin-top: 18px; }
.fk-more > summary {
  cursor: pointer;
  /* A <summary> is a control, and it is the ONLY control in this kit the
     stylesheet's thumb block cannot reach: that block floors inputs, selects,
     buttons and chips, and a summary is none of them. It rendered 38.5px on
     a phone, an iPad and a desktop alike — measured — which is under the 44px
     floor everything beside it gets. The floor is written here unconditionally
     rather than behind a second copy of the pointer query, because a 44px
     disclosure row is right with a mouse too and a duplicated media query is
     how two floors drift apart. */
  min-height: 44px;
  /* Both halves of removing the browser's own triangle: `list-style` is what
     Firefox and current Chrome read, the pseudo-element is what Safari does.
     One without the other leaves a marker on some of the market. */
  list-style: none;
  display: inline-flex; align-items: center; gap: 9px;
  padding: 8px 2px;
  font-size: 14.5px; font-weight: 700; color: var(--brand-text);
}
.fk-more > summary::-webkit-details-marker { display: none; }
/* A drawn chevron, turning as it opens: the affordance has to survive losing
   the default marker, and an image file for two triangles is not a design
   system, it is an asset pipeline. */
.fk-more > summary::before {
  content: ""; width: 7px; height: 7px; flex: 0 0 auto;
  border: solid currentColor; border-width: 0 2px 2px 0;
  transform: translateY(-2px) rotate(-45deg);
  transition: transform .15s ease;
}
.fk-more[open] > summary::before { transform: translateY(-3px) rotate(45deg); }
.fk-more > summary:hover { color: var(--link); }
.fk-more-body { margin-top: 10px; }

/* ---- help beside an unfamiliar choice --------------------------------- */

/* This is deliberately a native disclosure rather than a button plus a
   hidden panel. The browser owns its expanded state, keyboard behaviour and
   relationship to the content, including when scripts do not run. */
.fk-help { margin: 4px 0 8px; color: var(--ink); }
.fk-help > summary {
  min-height: 44px;
  width: fit-content;
  max-width: calc(100vw - 32px);
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 2px;
  cursor: pointer;
  color: var(--brand-text);
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.35;
}
.fk-help > summary::-webkit-details-marker { display: none; }
.fk-help > summary:hover { color: var(--link); }
.fk-help > summary:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
  border-radius: var(--r-pill);
}
.fk-help-mark {
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  border: 2px solid currentColor;
  border-radius: var(--r-pill);
  font-family: Georgia, serif;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
}
.fk-help-body {
  max-width: 38rem;
  margin: 2px 0 10px 30px;
  padding: 10px 12px;
  border-left: 3px solid var(--line);
  color: var(--mut);
  font-size: 13.5px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.fk-help-body p { margin: 0; }
.fk-help-body p + p { margin-top: 7px; }
.fk-help-example strong { color: var(--ink); }
@media (max-width: 719px) {
  .fk-help-body { margin-left: 0; }
  .fk-people { display: grid; }
  .fk-person { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; }
  .fk-member-actions { grid-column: 1 / -1; display: grid; }
  .fk-member-actions form.fk-inline { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: stretch; }
  .fk-member-actions select, .fk-member-actions button,
  .fk-foot form.fk-inline button { min-height: 44px; }
}

/* ---- the passkey offer ------------------------------------------------- */

/* Below the form and inside the same card: it is another way through the same
   door, not another door. Ghost rather than primary, because the promoted
   action is the one that works for everybody on every device — and two
   primary buttons is the question this page was rebuilt to stop asking. */
.fk-passkey { display: grid; gap: 12px; margin-top: 4px; padding-top: 18px; border-top: 1px solid var(--line); }
.fk-passkey > p { margin: 0; }
.fk-or {
  font-size: 11px; font-weight: 800;
  letter-spacing: .09em; text-transform: uppercase; color: var(--mut);
}

/* `hidden` has to actually hide. The attribute is nothing more than a
   `display: none` in the browser's own stylesheet, and ANY author rule that
   sets display beats it however low its specificity — `.fk-foot { display:
   flex }` is enough. So a control marked hidden, waiting for passkey.js to
   feature-detect and reveal it, was rendering anyway: the dead button the
   whole arrangement exists to avoid. This is the one place !important is the
   correct tool, because the point of the declaration is precisely to beat
   whatever layout the element is otherwise given. */
[hidden] { display: none !important; }

/* ---- small parts ------------------------------------------------------- */

.fk-empty { display: grid; gap: 12px; justify-items: center; text-align: center; padding: 38px 24px; }
.fk-empty p { max-width: 44ch; color: var(--mut); margin: 0; }
/* A drawn tick on the verified green, so a confirmation says "done" without
   an emoji and without an image file. */
.fk-done { display: flex; align-items: center; gap: 14px; margin-bottom: 8px; }
.fk-done-mark {
  width: 40px; height: 40px; border-radius: var(--r-pill);
  background: var(--v-fill); flex-shrink: 0; position: relative;
}
.fk-done-mark::after {
  content: ""; position: absolute; left: 15px; top: 10px;
  width: 8px; height: 15px; border: solid var(--v-on); border-width: 0 3px 3px 0;
  transform: rotate(45deg);
}
.fk-done h1 { margin: 0; }
/* A term and its value belong together, so the space goes BETWEEN pairs and
   not inside them. */
.fk-summary { display: grid; gap: 0; }
.fk-summary dt { font-size: 12.5px; font-weight: 700; color: var(--mut); }
.fk-summary dt + dd { margin: 2px 0 0; font-size: 15px; }
.fk-summary dd + dt { margin-top: 14px; }
.fk-alt { margin: 16px 0 0; text-align: center; font-size: 14.5px; color: var(--mut); }
.fk-title { margin: 0 0 10px; }
/* A heading with one action beside it. The action sits on the baseline
   of the title rather than above or below it, so the card still reads as
   one thing; it wraps rather than squeezing the name on a narrow screen. */
.fk-title-row { display: flex; justify-content: space-between; gap: 10px;
                align-items: baseline; flex-wrap: wrap; }
.fk-title-row .fk-title { margin-bottom: 0; }
.fk-flush { margin: 0; }
.fk-gap-top { margin-top: 16px; }


/* ======================================================================== *
 * THE SHARED KIT
 *
 * A breadcrumb, a task row, and the offer that opens into a sheet. All three
 * lived in app/templates/providers/_checklistkit.html -- a <style> block
 * included by exactly THREE templates -- so three pages had them and every
 * other page in the product rendered the same markup undressed. The only way
 * to have a breadcrumb was to include the checklist's private partial and
 * inherit its hub, its routes and its interview sheet along with it, which is
 * not a price a page should pay for a back link. Twelve other places wanted
 * the breadcrumb and hand-wrote a bare anchor instead, in a different glyph;
 * the advert page wanted the offer's sheet for take-home pay and did
 * without it.
 *
 * APPENDED AFTER THE FORM KIT, for the reason the form kit gives above: the
 * partial is included from {% block head %}, which base.html emits after this
 * stylesheet is linked, so "after everything else" is exactly where these
 * rules already were. Their cascade is unchanged -- and what the partial
 * legitimately keeps, because it is coupled to the checklist rather than to
 * these shapes (`.offer:not([open]) .route-self`, `.hub-aside .task`, the
 * `.route*` rules), is still emitted after this file and still wins.
 *
 * TOUCH TARGETS KEY ON THE POINTER, NEVER ON THE WIDTH. That is the partial's
 * own note and it travels with the rules it is about. The touch-target block
 * at the foot of the base sheet floors every input, button and chip at 44px
 * under `(max-width: 719px), (pointer: coarse)`; it is written that way
 * because gating on width alone shipped mouse-sized controls to iPad Safari,
 * which also zooms any input under 16px. A <summary> is not an input, a
 * button or a chip, and neither is an <a> that is not a .btn -- so both
 * floors below are written UNCONDITIONALLY rather than behind a second copy
 * of that query. A 44px row is right with a mouse too, and a duplicated
 * media query is how two floors drift apart.
 *
 * Everything here is a LAYOUT, never a second visual language: the colours,
 * radii, shadows and buttons all come from the tokens at the top of this
 * file, and no rule below invents a colour.
 * ======================================================================== */

/* ---- where a page came from -------------------------------------------- */

/* A back link and the name of where you are. `ui.crumb()` in
   app/templates/macros.html renders the pair; see the argument there for why
   it is a macro rather than fourteen hand-written anchors. */
.crumb { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.crumb-here { font-size: 11.5px; font-weight: 800; letter-spacing: .08em;
              text-transform: uppercase; color: var(--mut); }

/* ---- a task, and the list of them --------------------------------------- */

.tasks { display: grid; gap: 10px; list-style: none; margin: 0; padding: 0; }
/* A row is a link, and it is a link rather than a button because it goes
   somewhere: the browser's own affordances — open in a new tab, the status
   bar, the back button — all work, and none of them would if this were script
   pretending to navigate. Floored at 44px unconditionally: the thumb block in
   this file reaches .btn and .chip, and this is neither. */
.task {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; min-height: 44px;
  padding: 13px 16px; text-decoration: none; color: var(--ink);
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-card); box-shadow: var(--shadow);
}
.task:hover { border-color: var(--brand); color: var(--ink); }
.task[aria-current="page"] { border-color: var(--brand); background: var(--brand-soft); }
.task-said { display: grid; gap: 3px; min-width: 0; }
.task-label { font-size: 15px; font-weight: 700; }
.task-detail { font-size: 12.5px; color: var(--mut); }
/* WHETHER A TASK IS ANSWERED — and deliberately NOT in the provenance palette.
   Green, amber and purple mean verified, confirmed and unresolved on this
   platform, and a fourth meaning smuggled into those three would cost more
   than it buys (the same argument the said-vs-drafted section above makes).
   A task's state is about a task; a pill's state is about a claim.

   There is no count and no bar anywhere on the page this draws. 0028 settled
   it — INCOMPLETENESS IS NOT A FAILING — and the designer's own reason for
   choosing the hub over the ladder was that a bar across the top promises an
   end the checks cannot deliver. A meter here would put it straight back.

   Written around the word for it deliberately, and STILL written that way now
   the rule is served from a stylesheet rather than inline. The scan that
   tokenises rendered pages no longer reaches this text, but the vocabulary
   guard was never the only reason: naming the thing in a comment is how the
   thing gets built next time somebody reads for a place to put it. */
.task-state { font-size: 11px; font-weight: 700; border-radius: var(--r-pill);
              padding: 3px 10px; white-space: nowrap; flex: none; }
.task-done { background: var(--bg); border: 1px solid var(--line); color: var(--ink); }
.task-todo { text-transform: uppercase; letter-spacing: .06em; color: var(--mut); }

/* ---- the offer: a card, and the sheet it opens -------------------------- */

/* ONE <details>, TWO STATES, BOTH OF THEM DRAWN IN THE DESIGN. Shut it is a
   card on the page; open it is a sheet over the page. A <details> because
   DECLINING IS A ROUTE and it has to cost one tap, no request and no
   navigation — and because it is the only control in plain HTML that opens
   and closes with no script at all, which the pages that use it require.

   WHERE THE SUMMARY LANDS, AND WHY IT IS NOT AN `order` PER CHILD. Newer
   Chrome slots everything that is not the <summary> into a single
   ::details-content box; every other engine leaves those children on the
   <details> itself. So the markup keeps exactly ONE wrapper — .offer-body —
   and the summary is pushed after it. In the old box model that is one grid
   item at order 0 and the summary at 2; in the new one it is
   ::details-content at 1 and the summary at 2. Same result either way, and a
   rule naming a pseudo-element an engine has never heard of is simply
   dropped by that engine. TWO boxes order correctly in both; three diverge. */
.offer { background: var(--card); border: 1px solid var(--line);
         border-radius: var(--r-card); box-shadow: var(--shadow); }
.offer > summary {
  /* The 44px floor written unconditionally — see the head of this section.
     A <summary> is not an input, a button or a chip, so this file's own
     `(max-width: 719px), (pointer: coarse)` block never reaches it. */
  min-height: 44px; list-style: none; cursor: pointer;
}
.offer > summary::-webkit-details-marker { display: none; }
.offer > summary:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* SHUT: THE CARD, and it is on the page for ever. What it replaced on the
   checklist was one grey line that appeared the moment she answered anything
   — a door drawn so quietly that the owner of this product could not find it
   on his own profile, which is the whole reason this shape exists. */
.offer-card { display: grid; gap: 8px; padding: 18px 20px; }
.offer:not([open]):hover { border-color: var(--brand); }
.offer-line { font-size: 15.5px; font-weight: 700; line-height: 1.4; color: var(--ink); }
.offer-sub { font-size: 13.5px; line-height: 1.55; color: var(--mut); }
.offer-go { justify-self: start; margin-top: 2px; }
.offer[open] .offer-card { display: none; }

/* OPEN: the sheet. Fixed, so it covers the viewport rather than the top of a
   long page, and bottom-anchored on a phone for the reason the checklist's
   own `.sheet` is — that one stays in providers/_checklistkit.html, because
   the interview it panels is the checklist's and nothing else opens one. */
.offer[open] {
  position: fixed; inset: auto 0 0 0; z-index: 30;
  display: grid; gap: 10px;
  max-height: 92vh; overflow-y: auto;
  padding: 22px 20px 24px;
  border: 0; border-top: 1px solid var(--line);
  border-radius: 20px 20px 0 0;
  box-shadow: 0 -8px 28px rgba(var(--shadow-rgb), .16);
}
/* THE SCRIM AS A PSEUDO-ELEMENT, because a <details> is one element and the
   panel has to BE that element for the summary to sit inside it. Fixed rather
   than absolute so the panel's own overflow cannot clip it, and the panel is
   deliberately not transformed — a transform would make it the containing
   block for this and shrink the scrim to the size of the panel. Ink at low
   opacity rather than black: on a warm ground that reads as a shadow instead
   of a hole. */
.offer[open]::before {
  content: ""; position: fixed; inset: 0; z-index: -1;
  background: var(--scrim);
}
.offer[open] > summary { order: 2; }
.offer[open]::details-content { order: 1; }
/* THE ONE NON-SUMMARY WRAPPER. Load-bearing — see the ordering note above.
   A second wrapper beside it and the two engines stop agreeing. */
.offer-body { display: grid; gap: 10px; }
.offer-head { display: grid; gap: 6px; margin-bottom: 6px; }
.offer-head h2 { margin: 0; font-size: var(--t-title); font-weight: 800; letter-spacing: -.01em; }
.offer-head p { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--mut); }
/* A CENTRED DIALOG once there is room for one, at the same 720px .sheet uses.
   Centred with `inset: 0` and auto margins rather than a transform, for the
   scrim's sake — see above. */
@media (min-width: 720px) {
  .offer[open] {
    inset: 0; margin: auto;
    width: min(34rem, calc(100% - 48px));
    height: fit-content; max-height: min(46rem, 88vh);
    border: 1px solid var(--line); border-radius: var(--r-card);
    box-shadow: 0 18px 48px rgba(var(--shadow-rgb), .22);
  }
}

/* ---- hearing a question ------------------------------------------------- */
/* ONE AFFORDANCE, ONE CLASS. The foot bar on /live and the front door both
   offer the same thing — the sentence, spoken — so they wear the same class
   and are painted once here rather than twice in two page-scoped blocks.

   Quiet by construction. It sits beside a label or a lede, never competing
   with the two doors that are the point of the page, so it borrows `--mut`
   and only reaches for `--brand` when a pointer is actually on it. */
.hear {
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 2px 10px;
  margin-inline-start: 8px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--mut);
  cursor: pointer;
  vertical-align: middle;
}
.hear:hover { border-color: var(--brand); color: var(--brand-text); }
.hear[aria-pressed="true"] { border-color: var(--brand); color: var(--brand-text); }

/* The words the clip says, kept in the document beside the control. Anyone
   who cannot hear it reads it, and it is the same sentence either way. */
.hear-said {
  display: block;
  margin-top: 6px;
  font-size: 13.5px;
  color: var(--mut);
}

.hero-hear { margin: 10px 0 0; }


/* ---- the week, drawn ----------------------------------------------------
   Built by app/static/role-builder.js and never by a template, so none of this
   paints for somebody with no script — see that file's own note. It is a VIEW
   of the Start/End boxes underneath it, which stay the form.

   `touch-action: none` on the column is load-bearing on a phone: without it a
   drag down a column scrolls the page instead of drawing an afternoon. */
.cal { display: grid; gap: 6px; margin-bottom: 18px; }
.cal-head,
.cal-body { display: grid; grid-template-columns: 38px repeat(7, minmax(0, 1fr)); gap: 2px; }
.cal-add {
  min-height: 44px; font: inherit; font-size: 12.5px; font-weight: 700;
  color: var(--mut); background: transparent; border: none;
  border-radius: 8px; cursor: pointer;
}
.cal-add:hover { background: var(--brand-soft); color: var(--brand-text); }
.cal-body {
  padding: 6px; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--r-card);
}
.cal-gutter { display: flex; flex-direction: column; }
.cal-gutter span {
  font-size: 10px; line-height: 1; color: var(--mut);
  text-align: right; padding-right: 5px; transform: translateY(-4px);
}
.cal-col {
  position: relative; touch-action: none; border-radius: 6px;
  background: repeating-linear-gradient(
    to bottom, transparent 0 25px, var(--line) 25px 26px);
}
.cal-col:hover { background-color: color-mix(in oklab, var(--brand-soft) 35%, transparent); }
.cal-block {
  position: absolute; left: 1px; right: 1px; overflow: hidden;
  padding: 3px 4px; border: none; border-radius: 7px;
  background: var(--brand); color: var(--brand-ink);
  font: inherit; font-size: 10px; font-weight: 700; line-height: 1.2;
  text-align: left; cursor: pointer;
}
.cal-block:hover { background: var(--link); }
.cal-ghost {
  position: absolute; left: 1px; right: 1px; pointer-events: none;
  border: 1.5px dashed var(--brand); border-radius: 7px;
  background: var(--brand-soft);
}
.cal-typed { margin-top: 14px; }
.cal-typed > summary {
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: 13.5px; font-weight: 700; color: var(--brand-text); cursor: pointer;
}
.cal-typed-body { padding-top: 10px; }

/* THE CARER ASSISTANT (TASK-195). The owner met this page on a phone and the
   defect was the ORDER: a heading about saved facts, a paragraph of what it
   cannot do, a disclosure box, then the control. These rules put the answer
   where the disclaimers were and size it as the thing she came for — the
   heading names the job at title size, the answer outranks it, and the facts
   it read sit under it at label size, so provenance reads as provenance
   rather than as the answer. Written here rather than as `style=` attributes
   on the template, which is where the old card padding lived. */
.assistant-title { font-size: var(--t-title); margin: 0 0 14px; }
.assistant-ask { padding: 18px; margin-bottom: 12px; }
/* THREE ROWS, NOT EIGHT. `rows="2"` on the textarea is overridden by the
   global `textarea { min-height: 8em }` at the top of this file, which is
   sized for a profile summary; here it was 128px of empty box between the
   label and the button, and the answer began at y=731 on a 844px screen with
   the word "preschoolers" sliced through by the fold. This is the one control
   on the page and what follows it is what she came for. */
.assistant-ask textarea { min-height: 4.5em; margin-bottom: 4px; }
.assistant-said { margin: 20px 0 0; }
.assistant-answer {
  margin: 0;
  max-width: 32ch;
  font-size: clamp(21px, 6vw, 27px);
  font-weight: 700;
  line-height: 1.35;
  color: var(--ink);
}
.assistant-note {
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--mut);
  max-width: var(--col-text);
}
/* THE NOTICE WHEN IT IS THE WHOLE REPLY. A refused question and a question the
   stored facts do not carry both render the notice with no answer above it, and
   at 13px grey it was below the fold while a disclaimer was the headline. It is
   the reply on those paths, so it is sized as one — still not the answer type,
   because it is not an answer. */
.assistant-reply { margin-top: 0; font-size: 17px; line-height: 1.45; color: var(--ink); }
.assistant-said .ai-disclosure { margin: 12px 0 0; }
.assistant-facts, .assistant-pairing { padding: 18px; margin-top: 18px; }
.assistant-facts h2, .assistant-pairing h2 { font-size: 15px; margin: 0 0 10px; }
.assistant-limit { margin: 18px 0 0; font-size: 13px; color: var(--mut); }

/* THE ASSISTANT AT THE FOOT OF EVERY SIGNED-IN PAGE (TASK-150).

   A <details> and a form, because this site ships no script and the two
   crawlable surfaces are asserted script-free. It sits below the colophon's
   sibling footer, quiet when shut and no wider than the column the rest of
   the page reads in — a control on two hundred pages must not be the loudest
   thing on any of them.

   Colours are the ones already proved against their own ground: --ink and
   --mut on --card inside the panel, which is the pairing
   `tests/test_a_colour_is_read_against_its_own_ground.py` names as the
   pattern to follow. */
.ask-foot {
  max-width: var(--col);
  margin: 0 auto;
  padding: 0 var(--gutter) 28px;
}
.ask-here > summary {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px;
  border-radius: var(--r-pill);
  font-size: 14px;
  font-weight: 600;
  color: var(--mut);
  background: var(--card);
  border: 1px solid var(--line);
  cursor: pointer;
  list-style: none;
}
.ask-here > summary::-webkit-details-marker { display: none; }
.ask-here[open] > summary { color: var(--ink); }
.ask-here-panel {
  max-width: var(--col-text);
  margin-top: 10px;
  padding: 16px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
}
/* THE REPLY FIRST, THE BOX UNDER IT. She pressed Ask and came back to this
   page; the answer is what she came back for, so it is not below a control
   she has already used. */
.ask-here-said { margin: 0 0 14px; }
.ask-here-asked { margin: 0 0 6px; font-size: 13px; color: var(--mut); }
/* Sized as the reply and not as the page: this is one sentence at the foot of
   somebody else's surface, so it outranks the label under it and nothing
   above it. */
.ask-here-answer {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--ink);
}
.ask-here-note { margin: 8px 0 0; font-size: 13px; color: var(--mut); }
.ask-here-form label { display: block; font-size: 13.5px; }
/* Two rows, not eight. The global textarea min-height is sized for a profile
   summary and would put an empty box the height of a phone screen at the foot
   of every page in the product. */
.ask-here-form textarea { min-height: 3.5em; margin-bottom: 4px; }
/* The report-or-block control (TASK-071): one quiet line at the foot of a
   profile, an advert and a conversation. Small and grey on purpose — a
   person who has decided to press it will find it; nobody else needs it. */
.safety-control { margin: 18px 0 0; font-size: 13px; color: var(--mut); }
.safety-control a { color: inherit; }

/* An adverse decision's door to a second person (TASK-093): the reason it
   was refused, then the one sentence saying where to take it. Quiet on
   purpose — it sits under a refused advert, not on a marketing page. */
.appeal-why { margin: 8px 0 4px; color: var(--ink); }
.appeal-route { margin: 0 0 12px; font-size: 14px; color: var(--mut); }

/* A MESSAGE WAITING FOR A PERSON (TASK-068 AC#2). One line under the body of
   a held message, and it is read in two places: by its sender, on the
   conversation, where it says somebody is looking at what they just typed;
   and by an operator on the message-review queue, where it says the reader
   has not been given it. Quiet, and never a warning colour — a payment
   request is a shape of sentence, not a finding about the person who typed
   it, and dressing this like an alert would make an accusation out of a
   regular expression. */
.held-note { margin: 8px 0 0; font-size: 13px; color: var(--mut); }

/* TASK-310/311: the same two choices on each side of onboarding. */
.onboarding-choices { display: grid; gap: 16px; }
.onboarding-choice {
  color: var(--ink); text-decoration: none; position: relative; margin: 0;
}
.onboarding-choice:hover { border-color: var(--brand); }
.onboarding-choice-hit {
  position: absolute; inset: 0; width: 100%; min-height: 100%; padding: 0;
  border-radius: var(--r-card); background: transparent; color: transparent;
}
.onboarding-choice-hit:hover { background: transparent; }
.onboarding-choice-hit:focus-visible { outline-offset: 3px; }
.onboarding-choices h2 { margin-top: 0; }
.intake-voice-choice { margin: 20px 0 0; }
@media (min-width: 720px) { .onboarding-choices { grid-template-columns: 1fr 1fr; } }
