/* ============================================================================
   Dopara Group — the site's one stylesheet, from 16 September 2026.

   READ THIS FIRST IF YOU ARE EDITING THE SITE.

   The older pages on this site (TenureBook, book, contact, privacy, billing and
   the few pages behind a subscription) each carry their own <style> block and do
   NOT load this file. The three pages written for the reset — home, what we've
   built, public sector — load this and carry no styling of their own. So: a rule
   you add here reaches those three pages and nothing else.

   There was a fourth, /schools. It came off on 20 September 2026 when Ben set
   the schools research idea down, and the two-card component that introduced it
   went with it.

   There used to be three shared files here — site.css, app.js and book.js — that
   no page loaded at all. They were deleted on 16 September 2026, but the lesson
   is worth keeping: a rule in a file nothing loads does nothing, and it looks
   completely authoritative when you grep for it. Check which file the page
   actually loads before trusting a rule you found.

   HOW IT IS ORGANISED
     1. Colours, type and spacing        5. The plate (the drawing on the front)
     2. The page itself                  6. Sections, cards and the catalogue
     3. Buttons and links                7. Forms
     4. Call bar, header, footer         8. Small screens

   ONE RULE WORTH KNOWING. Inside calc(), clamp(), min() and max() a plus or
   minus sign needs a space on BOTH sides or the browser throws the whole line
   away without saying anything. This site once lost 265 text sizes that way and
   nobody noticed for a month. tools/check-css.py now refuses a deploy over it.
   ========================================================================== */

/* ============================================================================
   1. COLOURS, TYPE AND SPACING
   ========================================================================== */

:root{
  /* The page is warm off-white with near-black ink — paper, not screen. */
  --canvas:      #F7F6F3;
  --canvas-2:    #FFFFFF;   /* raised cards */
  --canvas-3:    #EFEEE9;   /* insets */
  --ink:         #0B0B0C;
  --muted:       #55555C;   /* body text that is not the main line — 7:1 on canvas */
  --faint:       #63636A;   /* labels and small print — 5.9:1 on canvas */
  --hair:        rgba(0,0,0,0.10);
  --hair-2:      rgba(0,0,0,0.16);
  --hair-strong: rgba(0,0,0,0.28);

  /* The visible edge of anything you can CLICK OR TYPE INTO. It is much darker
     than --hair on purpose: WCAG 2.2 asks for 3:1 against what is behind it,
     and the hairlines that separate one block of content from another are far
     too pale to carry a control. Measured: 3.6:1 here, 3.8:1 on the black. */
  --edge:        rgba(0,0,0,0.48);

  /* One accent, used perhaps four times on the whole site. */
  --accent:      #7F1F2A;

  --display: "Fraunces", Georgia, "Times New Roman", serif;
  --body:    "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono:    "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --maxw: 1240px;
  --gutter: clamp(1.25rem, 5vw, 3.25rem);
  --section-y: clamp(64px, 8vw, 104px);
}

/* The black bands — call bar, header, footer — are the same page with the
   colours swapped over, so every rule below keeps working inside them. */
.scope-dark{
  --canvas:#0B0B0C; --canvas-2:#111113; --canvas-3:#16161A;
  --ink:#F4F3F0; --muted:#B6B6BD; --faint:#9A9AA2;
  --hair:rgba(244,243,240,0.10); --hair-2:rgba(244,243,240,0.16); --hair-strong:rgba(244,243,240,0.26);
  --edge:rgba(244,243,240,0.42);
  background:var(--canvas); color:var(--ink);
}

/* ============================================================================
   2. THE PAGE ITSELF
   ========================================================================== */

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

html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; }
@media (prefers-reduced-motion: reduce){ html{ scroll-behavior:auto; } }

body{
  margin:0;
  background:var(--canvas);
  color:var(--ink);
  font-family:var(--body);
  font-size:16px;
  line-height:1.62;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
  /* The safety net for one long unbreakable word. An email address and a URL
     have nowhere a browser is allowed to break them, so at twice the text size
     on a narrow phone one of them sticks out past the edge and takes the layout
     with it. break-word only breaks a word that could not fit anyway, so at
     every ordinary size this changes nothing at all. Three narrow columns —
     the call bar, the footer lists and the facts table — ask for the stronger
     "anywhere" separately. */
  overflow-wrap:break-word;
}

img, svg, canvas{ max-width:100%; display:block; }
a{ color:inherit; }
::selection{ background:var(--ink); color:var(--canvas); }

/* The attribute must beat anything that sets a display of its own, or an
   element the page has hidden carries on showing. This site shipped a
   US-only sentence on top of a UK one for weeks for want of this line. */
[hidden]{ display:none !important; }

.wrap{ width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--gutter); }
.section{ padding-block:var(--section-y); position:relative; }
.rule{ border:0; border-top:1px solid var(--hair); margin:0; }

h1, h2, h3, h4{
  font-family:var(--display);
  font-weight:600;
  margin:0;
  letter-spacing:-0.022em;
  line-height:1.06;
}
h1{ font-size:clamp(2.7rem, 1.7rem + 4.6vw, 5rem); letter-spacing:-0.035em; }
h2{ font-size:clamp(1.9rem, 1.35rem + 2.3vw, 3.1rem); }
h3{ font-size:clamp(1.18rem, 1.05rem + 0.55vw, 1.5rem); line-height:1.2; }
h4{ font-size:1.02rem; line-height:1.3; }

p{ margin:0 0 1rem; }
p:last-child{ margin-bottom:0; }

.eyebrow{
  font-family:var(--mono);
  font-size:0.76rem;
  font-weight:500;
  letter-spacing:0.34em;
  text-transform:uppercase;
  color:var(--faint);
  margin:0 0 1.15rem;
}
.eyebrow .on{ color:var(--ink); }

.lead{
  font-size:clamp(1.09rem, 1rem + 0.55vw, 1.3rem);
  line-height:1.6;
  color:var(--muted);
  max-width:56ch;
}
.prose{ max-width:68ch; color:var(--muted); }
.prose h3{ color:var(--ink); margin:2.4rem 0 0.7rem; }
.prose h3:first-child{ margin-top:0; }
.prose strong{ color:var(--ink); font-weight:600; }
.prose ul{ margin:0 0 1rem; padding-left:1.15rem; }
.prose li{ margin-bottom:0.45rem; }
.small{ font-size:0.9rem; color:var(--faint); }

/* ============================================================================
   3. BUTTONS AND LINKS
   ========================================================================== */

.btn{
  --pad-y:0.95rem; --pad-x:1.55rem;
  display:inline-flex; align-items:center; gap:0.6rem;
  font-family:var(--mono);
  font-size:0.78rem;
  font-weight:500;
  letter-spacing:0.14em;
  text-transform:uppercase;
  padding:var(--pad-y) var(--pad-x);
  border-radius:2px;
  border:1px solid transparent;
  text-decoration:none;
  /* NOT nowrap. A button that refuses to wrap sets the minimum width of the
     grid track it sits in, and at twice the text size on a narrow phone that
     dragged the whole hero column off the side of the screen. At ordinary sizes
     there is room and nothing wraps, so this costs nothing and only shows up
     when the alternative was losing the button altogether. */
  text-align:center;
  cursor:pointer;
  line-height:1;
}
.btn svg{ width:14px; height:14px; flex:none; }
.btn-primary{ background:var(--ink); color:var(--canvas); border-color:var(--ink); }
.btn-ghost{ background:transparent; color:var(--ink); border-color:var(--edge); }
.btn-primary:hover, .btn-primary:focus-visible{ background:var(--accent); border-color:var(--accent); color:#F7F6F3; }
.btn-ghost:hover, .btn-ghost:focus-visible{ border-color:var(--ink); }
.btn[disabled]{ opacity:0.55; cursor:default; }
@media (prefers-reduced-motion: no-preference){
  .btn{ transition:background-color .22s ease, color .22s ease, border-color .22s ease, transform .16s ease; }
  .btn:not([disabled]):hover, .btn:not([disabled]):focus-visible{ transform:translateY(-1px); }
  .btn:not([disabled]):active{ transform:translateY(0) scale(.99); transition-duration:.06s; }
}

a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible{
  outline:2px solid var(--ink); outline-offset:3px;
}

/* A text link that carries its own underline, for use inside paragraphs. */
.link{ color:var(--ink); text-decoration:underline; text-underline-offset:0.18em; text-decoration-thickness:1px; }
.link:hover{ text-decoration-color:var(--accent); }

/* The arrow link used to end a section. */
.more{
  display:inline-flex; align-items:center; gap:0.5rem;
  font-family:var(--mono); font-size:0.78rem; letter-spacing:0.12em; text-transform:uppercase;
  color:var(--ink); text-decoration:none;
  border-bottom:1px solid var(--hair-strong); padding-bottom:0.3rem;
}
.more:hover{ border-bottom-color:var(--ink); }

.skip{
  position:absolute; left:0; top:0; transform:translateY(-120%);
  background:#0B0B0C; color:#F7F6F3;
  padding:0.75rem 1.25rem; font-family:var(--mono); font-size:0.8rem; letter-spacing:0.08em;
  z-index:300; text-decoration:none;
}
.skip:focus{ transform:translateY(0); }

/* ============================================================================
   4. CALL BAR, HEADER, FOOTER
   ========================================================================== */

/* Ben asked for the phone number to be obvious at the top of every page. This
   bar sits above the header and scrolls away with the page; the header keeps
   the top of the screen. */
.callbar{ border-bottom:1px solid var(--hair); }
.callbar-in{
  display:flex; align-items:center; gap:0.9rem 1.5rem; flex-wrap:wrap;
  padding-block:0.34rem; min-height:34px;
  font-family:var(--mono); font-size:0.76rem; letter-spacing:0.06em;
}
.callbar-tel{
  display:inline-flex; align-items:center; gap:0.5rem;
  color:var(--ink); text-decoration:none;
  /* Padding here is reach and nothing else — it makes the link big enough to
     hit with a thumb. 26px plus the bar's own padding clears the 24px that
     WCAG 2.2 asks for. */
  padding-block:0.42rem; min-height:26px;
}
.callbar-tel svg{ width:14px; height:14px; flex:none; }
.callbar-tel:hover{ color:#fff; }
.callbar-note{ color:var(--muted); min-width:0; }
/* An email address has nowhere a browser is allowed to break it, so at 200% text
   it sticks out past the edge of the page and takes the whole layout with it.
   This lets it break anywhere rather than overflow. Found by setting the root
   text size to 32px and asking which element ended up past the right edge. */
.callbar-note a{ color:var(--ink); overflow-wrap:anywhere; }

.site-header{ position:sticky; top:0; z-index:100; background:var(--canvas); }
/* The row WRAPS, and that is the whole point of the line. At ordinary sizes it
   never does. At twice the text size on a 320px phone the wordmark, the call to
   action and the menu button add up to 560px of a 320px screen, and without a
   wrap the header simply hangs off the side — which body{overflow-x:hidden}
   then quietly clips, so the button is not scrolled to, it is gone. Wrapping
   drops the button to a second line instead, which is ugly at that size and
   still works, and working is the requirement. */
.header-row{ display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:0.6rem 1.5rem; min-height:68px; padding-block:0.4rem; }
.header-cta{ margin-left:auto; }

/* The header and footer carry Ben's own wordmark, painted as a mask rather than
   dropped in as a picture — so it takes its colour from the band it sits on and
   there is no white box baked into the artwork. The typed word "Dopara" stays in
   the markup underneath: that is what a screen reader says, what a search engine
   reads, and what shows if a browser cannot do masks. */
.wordmark{ font-family:var(--display); font-weight:700; font-size:1.3rem; letter-spacing:-0.03em; color:var(--ink); text-decoration:none; }
@supports ((-webkit-mask-image:url("/assets/dopara-wordmark.png")) or (mask-image:url("/assets/dopara-wordmark.png"))){
  .site-header .wordmark{
    display:block; box-sizing:content-box;
    width:calc(1.3rem * 3.7188);   /* the artwork's own ratio, 595 x 160 */
    height:1.3rem;
    padding:12px 10px; margin:-12px -10px;   /* reach, then cancel it so nothing moves */
    background-color:currentColor;
    -webkit-mask:url("/assets/dopara-wordmark.png") content-box left center/contain no-repeat;
            mask:url("/assets/dopara-wordmark.png") content-box left center/contain no-repeat;
    font-size:0; line-height:0;
  }
  .site-footer .footer-brand .wordmark{
    display:block; box-sizing:content-box;
    width:calc(1.54rem * 3.7188);
    height:1.54rem;
    padding:11px 10px; margin:-11px -10px -5px;
    background-color:currentColor;
    -webkit-mask:url("/assets/dopara-wordmark.png") content-box left center/contain no-repeat;
            mask:url("/assets/dopara-wordmark.png") content-box left center/contain no-repeat;
    font-size:0; line-height:0;
  }
}

.nav-links{ display:flex; align-items:center; gap:1.5rem; list-style:none; margin:0; padding:0; }
.nav-links a{
  font-family:var(--mono); font-size:0.76rem; letter-spacing:0.1em; text-transform:uppercase;
  color:var(--muted); text-decoration:none;
}
.nav-links a:hover, .nav-links a:focus-visible, .nav-links a[aria-current="page"]{ color:var(--ink); }
.header-cta{ display:flex; align-items:center; gap:0.85rem; }
.header-cta .btn{ --pad-y:0.68rem; --pad-x:1.1rem; }
.header-cta .btn-primary{ background:var(--ink); color:#0B0B0C; border-color:var(--ink); }

.menu-toggle{
  display:none; width:42px; height:42px; align-items:center; justify-content:center;
  background:transparent; border:1px solid var(--edge); border-radius:2px;
  color:var(--ink); cursor:pointer; flex:none;
}
.menu-toggle svg{ width:18px; height:18px; }

@media (max-width: 1000px){
  .nav-links{ display:none; }
  .menu-toggle{ display:inline-flex; }
  .site-header.nav-open .nav-links{
    display:flex; flex-direction:column; align-items:flex-start; gap:1.1rem;
    position:absolute; left:0; right:0; top:100%;
    background:var(--canvas); border-bottom:1px solid var(--hair);
    padding:1.35rem var(--gutter) 1.6rem;
  }
  .site-header.nav-open .nav-links a{ font-size:0.86rem; }
}
@media (max-width: 600px){
  .wordmark{ flex:none; }
  .header-row{ gap:0.75rem; }
  .header-cta{ gap:0.5rem; }
  .header-cta .btn{ --pad-x:0.85rem; }
  .callbar-note{ display:none; }
}

.site-footer{ padding-block:clamp(48px, 6vw, 76px) 30px; }
.footer-top{
  display:grid; gap:2.4rem 2rem;
  grid-template-columns:minmax(240px, 1.5fr) repeat(3, minmax(140px, 1fr));
  padding-bottom:2.6rem; border-bottom:1px solid var(--hair);
}
.footer-pos{ color:var(--muted); max-width:34ch; margin:1rem 0 0; font-size:0.94rem; }
.fcol h3{ font-family:var(--mono); font-size:0.72rem; font-weight:500; letter-spacing:0.22em; text-transform:uppercase; color:var(--faint); margin:0 0 0.9rem; }
.fcol ul{ list-style:none; margin:0; padding:0; }
/* overflow-wrap here for the same reason as the call bar: an email address is one
   unbreakable word, and in a narrow column at 200% text it pushes the page sideways. */
.fcol li{ margin-bottom:0.55rem; font-size:0.94rem; color:var(--muted); overflow-wrap:anywhere; }
.fcol a{ color:var(--muted); text-decoration:none; }
.fcol a:hover{ color:var(--ink); }
.footer-legal{
  display:flex; flex-wrap:wrap; gap:0.55rem 0.85rem;
  padding-top:1.6rem; font-size:0.83rem; color:var(--faint);
}
.footer-legal a{ color:var(--faint); }
.footer-legal a:hover{ color:var(--ink); }
.social-row{ display:flex; gap:0.6rem; margin-top:1.3rem; }
.social-btn{
  display:inline-flex; align-items:center; justify-content:center;
  width:38px; height:38px; border:1px solid var(--edge); border-radius:2px; color:var(--muted);
}
.social-btn svg{ width:17px; height:17px; }
.social-btn:hover{ color:var(--ink); border-color:var(--hair-strong); }

@media (max-width: 860px){
  .footer-top{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 520px){
  .footer-top{ grid-template-columns:minmax(0, 1fr); gap:1.9rem; }
}

/* ============================================================================
   5. THE MASTHEAD — the black band every page opens with

   The call bar, the header and this band are one continuous black block at the
   top of the page, and the footer is the same black at the bottom. Between them
   the page is warm off-white. That is the whole visual idea of the site.

   Behind the band is a field of pale dots, drawn by assets/masthead.js. It is
   masked to fade in under the header and out into whatever follows, so the band
   has no hard edge anywhere — Ben asked for that specifically the first time
   this existed, and it is the thing that makes the black read as a band rather
   than a box.
   ========================================================================== */

.stage{ position:relative; overflow:hidden; }
.stage .wrap{ position:relative; z-index:1; }

.wavedots{
  position:absolute; inset:0; width:100%; height:100%; z-index:0;
  -webkit-mask-image:linear-gradient(to bottom, transparent 0%, #000 12%, #000 62%, transparent 100%);
          mask-image:linear-gradient(to bottom, transparent 0%, #000 12%, #000 62%, transparent 100%);
}

/* The front page's masthead carries the name at the size of a poster. It is
   decoration — the section is aria-hidden and the real words are below it — so
   it can be as large as it likes without being something a reader has to get
   past. */
.stage-name{ padding-block:clamp(2.6rem, 6vw, 5.5rem) clamp(0.5rem, 1.5vw, 1.5rem); }
.stage-inner{ position:relative; min-height:clamp(190px, 25vw, 340px); display:flex; align-items:center; }
.giant{
  font-family:var(--display); font-weight:800;
  font-size:clamp(3rem, 12.5vw, 12rem);
  line-height:0.9; letter-spacing:-0.04em;
  color:var(--ink);
  white-space:nowrap;
  position:absolute; left:50%; top:50%; transform:translate(-50%, -50%);
  opacity:0.9;
  -webkit-user-select:none; user-select:none;
  pointer-events:none;
}
.giant .thin{ -webkit-text-stroke:1.5px var(--ink); color:transparent; }
@media (max-width: 640px){ .stage-inner{ min-height:150px; } }

@media (prefers-reduced-motion: no-preference){
  .js .giant{ animation:giant-rise 1.1s cubic-bezier(.2,.7,.2,1) both; }
  @keyframes giant-rise{
    from{ opacity:0; transform:translate(-50%, -46%) scale(.965); }
    to{ opacity:0.9; transform:translate(-50%, -50%) scale(1); }
  }
}

/* The other pages open with the same band, carrying their own title instead of
   the name. Same black, same dots, so the site reads as one thing. */
.stage-page{ padding-block:clamp(2.6rem, 5vw, 4.2rem) clamp(3rem, 6vw, 5rem); }
.stage-page .sec-head{ margin-bottom:0; }

/* ============================================================================
   5b. THE HERO

   The drawing is assets/plate.svg, made by tools/make-hero.mjs. It is an
   abstract — fine lines flowing over an invisible landscape — so there is
   nothing in it that could be read as a claim about a client or a result.
   ========================================================================== */

.hero{ padding-block:clamp(1rem, 2vw, 2rem) clamp(56px, 8vw, 104px); overflow:hidden; }
.hero h1{ margin-bottom:1.5rem; max-width:16ch; }
.hero .lead{ max-width:54ch; }
.hero-actions{ display:flex; flex-wrap:wrap; gap:0.85rem; margin-top:2.2rem; }
.hero-note{
  margin-top:2.2rem; padding-top:1.4rem; border-top:1px solid var(--hair);
  font-family:var(--mono); font-size:0.76rem; letter-spacing:0.05em; color:var(--faint);
  max-width:46ch; line-height:1.75;
}

/* The engraved plate that sat beside the hero from 16 to 20 September is drawn
   by tools/make-hero.mjs and is no longer on the site: the masthead is the front
   page's picture now. The generator and its comments are kept, so it is one
   <img> away if it is ever wanted again. */

/* ============================================================================
   6. SECTIONS, CARDS AND THE CATALOGUE
   ========================================================================== */

.sec-head{ max-width:62ch; margin-bottom:clamp(2.2rem, 4vw, 3.4rem); }
/* A heading that opens a block of prose needs air under it. Headings carry no
   margin by default because in a card or a grid cell the gap does that job. */
.sec-head h1, .sec-head h2, .split h2, .form-grid h2{ margin-bottom:1.1rem; }

/* Four plain statements of what we do. No icons — the words are the thing. */
.grid-4{ display:grid; gap:1px; background:var(--hair); border-block:1px solid var(--hair); grid-template-columns:repeat(4, minmax(0, 1fr)); }
.grid-4 > *{ background:var(--canvas); padding:2rem 1.7rem 2.2rem; }
.cell-n{ font-family:var(--mono); font-size:0.74rem; letter-spacing:0.18em; color:var(--faint); display:block; margin-bottom:1.1rem; }
.cell h3{ margin-bottom:0.6rem; }
.cell p{ color:var(--muted); font-size:0.96rem; }

@media (max-width: 1000px){ .grid-4{ grid-template-columns:repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px){ .grid-4{ grid-template-columns:minmax(0, 1fr); } }

/* A section with the argument on one side and the evidence on the other. */
.split{ display:grid; gap:clamp(2rem, 5vw, 4rem); grid-template-columns:minmax(0, 1fr) minmax(0, 0.95fr); align-items:start; }
@media (max-width: 860px){ .split{ grid-template-columns:minmax(0, 1fr); } }

/* The five things, set like entries in a ledger rather than a feature list —
   each one a name and the plain truth about it. */
.ledger{ list-style:none; margin:0; padding:0; border-top:1px solid var(--hair); }
.ledger li{
  display:flex; justify-content:space-between; align-items:baseline; gap:1.2rem 2rem; flex-wrap:wrap;
  padding-block:1.05rem; border-bottom:1px solid var(--hair);
}
.ledger-t{ font-size:1rem; color:var(--ink); max-width:30ch; }
.ledger-s{ font-family:var(--mono); font-size:0.73rem; letter-spacing:0.08em; color:var(--faint); text-align:right; }

/* A plainer list, for things that are not a ledger. Deliberately NOT .ledger:
   two of those in a row down one page read as the same block twice, and the
   second one is a list of work rather than a record of anything. */
.things{ list-style:none; margin:0; padding:0; }
.things li{
  font-size:clamp(1rem, 0.96rem + 0.2vw, 1.1rem);
  line-height:1.45;
  color:var(--ink);
  padding-block:1.15rem;
  border-top:1px solid var(--hair);
}
.things li:first-child{ border-top:0; padding-top:0; }

/* The .grid-2 and .door rules that sat here drew two side-by-side cards on the
   front page — one for the public sector, one for schools. With the schools
   page gone there is one door, and one card in a two-card grid looks broken, so
   that section is now a .split with the argument on the left and what a council
   actually buys on the right. The rules went rather than sitting here unused:
   this site has been bitten twice by CSS that looked live and reached nothing. */

/* The catalogue. Each real thing we have built is one entry, set like a page in
   a reference book: a number, the name, what it is, and a status line that says
   plainly what is true today. The status line is the point of the page. */
.cat{ list-style:none; margin:0; padding:0; }
.cat > li{ border-top:1px solid var(--hair); padding-block:clamp(2rem, 3.5vw, 3rem); }
.cat > li:last-child{ border-bottom:1px solid var(--hair); }
.cat-row{ display:grid; gap:1.4rem 2.6rem; grid-template-columns:5.5rem minmax(0, 1.05fr) minmax(0, 0.95fr); align-items:start; }
.cat-n{ font-family:var(--mono); font-size:0.78rem; letter-spacing:0.16em; color:var(--faint); padding-top:0.45rem; }
.cat-main h2, .cat-main h3{ margin-bottom:0.85rem; }
.cat-main p{ color:var(--muted); }
.cat-side{ display:flex; flex-direction:column; gap:1.1rem; }
.cat-k{ font-family:var(--mono); font-size:0.7rem; letter-spacing:0.2em; text-transform:uppercase; color:var(--faint); display:block; margin-bottom:0.35rem; }
.cat-v{ font-size:0.94rem; color:var(--muted); }
.cat-v strong{ color:var(--ink); font-weight:600; }
.cat-tags{ display:flex; flex-wrap:wrap; gap:0.4rem; }
.tag{
  font-family:var(--mono); font-size:0.68rem; letter-spacing:0.08em;
  border:1px solid var(--hair-2); padding:0.28rem 0.5rem; color:var(--faint); border-radius:2px;
}
@media (max-width: 900px){
  .cat-row{ grid-template-columns:3.2rem 1fr; }
  .cat-side{ grid-column:2; }
}
/* On a narrow phone the number's own column costs more width than the heading
   can spare, so it goes above the entry instead of beside it. */
@media (max-width: 560px){
  .cat-row{ grid-template-columns:minmax(0, 1fr); gap:1rem; }
  .cat-n{ padding-top:0; }
  .cat-side{ grid-column:auto; }
}

/* A plain fact table — used on the public-sector page, where a buyer wants the
   company number and the answers in one place rather than in prose. */
.facts{ width:100%; border-collapse:collapse; font-size:0.96rem; }
.facts th, .facts td{ text-align:left; vertical-align:top; padding:0.95rem 1rem 0.95rem 0; border-top:1px solid var(--hair); }
.facts tr:last-child th, .facts tr:last-child td{ border-bottom:1px solid var(--hair); }
.facts th{ font-family:var(--mono); font-weight:500; font-size:0.74rem; letter-spacing:0.12em; text-transform:uppercase; color:var(--faint); width:15rem; padding-top:1.15rem; }
.facts td{ color:var(--muted); overflow-wrap:anywhere; }
.facts td strong{ color:var(--ink); font-weight:600; }
.facts-scroll{ overflow-x:auto; }
@media (max-width: 660px){
  .facts th{ width:auto; display:block; border-bottom:0; padding-bottom:0.2rem; }
  .facts td{ display:block; border-top:0; padding-top:0; }
  .facts tr{ display:block; border-top:1px solid var(--hair); padding-block:0.6rem; }
  .facts tr:last-child{ border-bottom:1px solid var(--hair); }
  .facts tr:last-child th, .facts tr:last-child td{ border-bottom:0; }
}

/* A held / not held marker, so a buyer can see at a glance. */
.held{ font-family:var(--mono); font-size:0.7rem; letter-spacing:0.14em; text-transform:uppercase; }
.held-y{ color:var(--ink); }
.held-n{ color:var(--accent); }

/* ============================================================================
   7. FORMS
   ========================================================================== */

.form-band{ background:var(--canvas-3); border-top:1px solid var(--hair); }
.form-grid{ display:grid; gap:clamp(2.2rem, 5vw, 4rem); grid-template-columns:minmax(0, 1fr) minmax(0, 1fr); align-items:start; }
@media (max-width: 900px){ .form-grid{ grid-template-columns:minmax(0, 1fr); } }

.form-card{ background:var(--canvas-2); border:1px solid var(--hair); padding:clamp(1.5rem, 3vw, 2.2rem); }
.field{ margin-bottom:1.15rem; }
.field label{ display:block; font-family:var(--mono); font-size:0.72rem; letter-spacing:0.14em; text-transform:uppercase; color:var(--faint); margin-bottom:0.5rem; }
.input{
  width:100%; font-family:var(--body); font-size:1rem; color:var(--ink);
  background:var(--canvas); border:1px solid var(--edge); border-radius:2px;
  padding:0.8rem 0.9rem;
}
.input::placeholder{ color:#6F6F76; }  /* 4.6:1 on the field */
.input:focus{ border-color:var(--ink); }
textarea.input{ min-height:118px; resize:vertical; }
.field-pair{ display:grid; gap:1.15rem; grid-template-columns:repeat(2, minmax(0, 1fr)); }
@media (max-width: 520px){ .field-pair{ grid-template-columns:minmax(0, 1fr); } }
.field-error, .form-error{ color:var(--accent); font-size:0.86rem; margin:0.4rem 0 0; }
.form-error{ margin-top:0.9rem; }
.btn-block{ width:100%; justify-content:center; }
.form-foot{ margin-top:0.95rem; font-size:0.83rem; color:var(--faint); }
.form-foot a{ color:var(--faint); }
/* The honeypot. A person never sees it; something filling in every field does. */
.hp{ position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }
.form-done{ font-family:var(--display); font-size:1.6rem; margin:0 0 0.6rem; }
