/* ==========================================================================
   The Choir Press — custom rebuild
   Design tokens sampled from the existing site to keep the look consistent.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   Self-hosted Open Sans (variable, latin + latin-ext).
   No third-party font requests — visitor IPs are never sent to Google.

   These used to live in their own stylesheet, which meant every page made a
   second CSS request before it could even discover the font file. They are here
   so the font is found in the same response as everything else, and the pages
   preload the latin file directly.

   The latin-ext face stays despite nothing in the site's own copy needing it:
   book titles, author names and testimonials are admin-editable, and the first
   author called Bronisław should not get a fallback font. unicode-range means
   it is only ever fetched if a page actually contains one of those characters,
   so it costs nothing to keep.
   --------------------------------------------------------------------------- */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/assets/fonts/open-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/assets/fonts/open-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


:root {
  --red:        #a42128;   /* brand red (buttons, logo, headings) */
  --red-dark:   #85161c;   /* hover state */
  --charcoal:   #3b3b3b;   /* footer / about band */
  --charcoal-2: #2f2f2f;
  /* The greys below carry white or near-black text, so they are set at the
     darkest/lightest value that still reads as the sampled colour while
     clearing 4.5:1 — see the contrast notes in README. */
  --topbar:     #6e7173;   /* utility bar grey (white text, 4.92:1) */
  --band-grey:  #565656;   /* featured testimonial band (white text, 7.34:1) */
  --light:      #f5f5f5;   /* light section background */
  --line:       #e4e4e4;
  --ink:        #333;
  --ink-soft:   #555;
  --ink-mute:   #767676;   /* muted label text on white, 4.54:1 */
  --ink-mute-2: #6f6f6f;   /* muted label text on --light, 4.61:1 */
  --white:      #fff;
  --gold:       #8f6a00;   /* review stars (4.97:1 on white) */
  --maxw:       1180px;
  --radius:     3px;
  --shadow:     0 6px 24px rgba(0,0,0,.10);
  --shadow-lg:  0 18px 50px rgba(0,0,0,.22);
  --font:       'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --serif:      Georgia, 'Times New Roman', serif;
}

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

/* Tapping a control should not wait to see whether a second tap is coming.
   Deliberately not applied with a universal selector: that would break
   double-tap-to-zoom on the book covers and on body text, which some people
   rely on to read. */
a, button, [role="button"], input, select, textarea, label, summary {
  touch-action: manipulation;
}

/* The hidden attribute must win over component display rules (e.g. .btn). */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
/* keep anchored sections clear of the sticky header */
:target { scroll-margin-top: 90px; }

body {
  margin: 0;
  font-family: var(--font);
  color: var(--ink);
  line-height: 1.65;
  font-size: 16px;
  background: var(--white);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;            /* never allow horizontal scrolling of the page */
}

/* height: auto is not optional now that every <img> carries width and height.
   Without it the height attribute wins over the fluid width and every image is
   squashed. Rules further down that set an explicit height (.logo img,
   .cost-media img) are more specific and still win. */
img { max-width: 100%; height: auto; display: block; }
a { color: var(--red); text-decoration: none; text-underline-offset: .18em; }
a:hover { text-decoration: underline; }

/* The browser's own surfaces, in the house colours rather than system blue.
   The selection is a solid pale tint with dark text, not a translucent red: over
   the red CTA bands a red wash would make selected text disappear. */
::selection { background: #f4d6d8; color: #2a2a2a; }
:root { accent-color: var(--red); }
input, textarea { caret-color: var(--red); }

.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }

/* balance: a heading that wraps splits into even lines instead of leaving one
   word, or half of "self-publish", on a line of its own. */
h1, h2, h3, h4 { margin: 0 0 .5em; font-weight: 300; line-height: 1.2; text-wrap: balance; }
h2 { font-size: 2.1rem; }
p { margin: 0 0 1em; color: var(--ink-soft); }

/* ---------- Buttons -------------------------------------------------------- */
.btn {
  display: inline-block;
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: .04em;
  padding: 13px 26px;
  border-radius: var(--radius);
  cursor: pointer;
  border: 2px solid transparent;
  transition: background .18s ease, color .18s ease, border-color .18s ease, transform .18s ease;
  text-align: center;
  /* A <button> does not inherit font or line-height the way an <a> does, so every
     form's submit button (Contact Us, Next, Send Message, Show My Guide Price)
     was set in the platform's Arial at a shorter line than the link buttons
     beside it. */
  font-family: inherit;
  line-height: inherit;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn-red    { background: var(--red); color: #fff; }
.btn-red:hover { background: var(--red-dark); color: #fff; }
.btn-ghost  { background: transparent; color: #fff; border-color: #fff; }
/* Over a photograph "transparent" means whatever the photo happens to be — the
   hero's Learn More button measured 1.44:1 against a pale part of one slide. A
   dark wash keeps the ghost look and guarantees the label stays readable. */
.hero .btn-ghost, .page-hero .btn-ghost { background: rgba(12,8,6,.55); }
.hero .btn-ghost:hover, .page-hero .btn-ghost:hover { background: #fff; color: var(--ink); }
.btn-ghost:hover { background: #fff; color: var(--ink); }
.btn-outline{ background: transparent; color: var(--red); border-color: var(--red); }
.btn-outline:hover { background: var(--red); color: #fff; }
.btn-lg { padding: 16px 34px; font-size: 1rem; }
.btn-block { display: block; width: 100%; }

/* small "Learn More >" text link used across cards */
.learn-more { color: var(--red); font-weight: 600; }
.learn-more::after { content: " ›"; }

/* ---------- Top utility bar ----------------------------------------------- */
.topbar {
  background: var(--topbar);
  color: #fff;
  font-size: .9rem;
}
.topbar .container { display: flex; align-items: center; gap: 28px; min-height: 42px; flex-wrap: wrap; }
/* On a phone this bar was two stacked lines — 130px of the first screenful,
   above the logo, for contact details that are also a fixed button at the bottom
   of every page. One line, no labels, no wrapping: the tap targets stay 24px and
   the hero starts 65px sooner. */
@media (max-width: 600px) {
  .topbar { font-size: .8rem; }
  .topbar .container {
    gap: 14px; min-height: 34px; flex-wrap: nowrap;
    justify-content: center; padding-top: 2px; padding-bottom: 2px;
  }
  .topbar .tb-item { gap: 5px; min-width: 0; }
  .topbar .tb-item > .tb-label { display: none; }   /* the "Tel:" / "Email:" prefix */
  .topbar .tb-item a { white-space: nowrap; }
  .topbar svg { width: 13px; height: 13px; flex: 0 0 13px; }
}
/* Below about 380px the email address alone is wider than the screen. Clipping
   an address mid-domain is worse than not showing it — the footer carries it,
   and so does every contact form. */
@media (max-width: 400px) {
  .topbar .tb-item:nth-of-type(2) { display: none; }
}
.topbar a { color: #fff; text-decoration: underline; }
.topbar .tb-item { display: inline-flex; align-items: center; gap: 8px; }
.topbar .tb-spacer { margin-left: auto; }
.topbar .tb-cta { text-decoration: none; font-weight: 700; }
.topbar svg { width: 15px; height: 15px; fill: #fff; }

/* ---------- Header / nav --------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: #fff;
  border-bottom: 1px solid var(--line);
  box-shadow: 0 2px 10px rgba(0,0,0,.04);
}
.site-header .container { display: flex; align-items: center; justify-content: space-between; min-height: 84px; }
.logo img { height: 58px; width: auto; }
.main-nav { display: flex; align-items: center; gap: 4px; }
.main-nav a {
  color: var(--ink); font-weight: 600; font-size: .92rem;
  padding: 8px 12px; border-radius: var(--radius);
  white-space: nowrap;                 /* keep every item on a single line */
}
.main-nav a:hover { text-decoration: none; color: var(--red); }
/* Active state: red text with a short, tight 2px underline hugging the text
   itself (text-decoration hugs the glyphs, so it aligns whether the link is a
   direct nav item or a .has-sub > a with asymmetric padding, and it never
   changes the header height). */
.main-nav a.active {
  color: var(--red);
  text-decoration: underline;
  text-decoration-color: var(--red);
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
  text-decoration-skip-ink: none;      /* solid bar, no gaps under descenders */
}
.main-nav a.active:hover { color: var(--red); text-decoration: underline; }
.main-nav a.nav-cta { margin-left: 8px; color: #fff; }
.main-nav a.nav-cta:hover { color: #fff; }
.nav-toggle {
  display: none; background: none; border: 0; cursor: pointer;
  padding: 8px; color: var(--ink);
}
.nav-toggle svg { width: 28px; height: 28px; fill: currentColor; }

/* ---------- Hero ----------------------------------------------------------- */
.hero {
  position: relative; overflow: hidden;
  background: #241610;
  color: #fff;
}
.hero-bg { position: absolute; inset: 0; z-index: 0; }
/* The photograph comes in as --slide / --slide-sm so this rule can pick the
   size, the same way .page-hero does. The SVG under-layer that used to sit
   beneath each photograph is gone: it was a second image fetched on every visit
   and never visible, because the opaque JPEG covered it. */
.hero-slide {
  position: absolute; inset: 0;
  background-image: var(--slide);
  background-size: cover; background-position: center;
  opacity: 0; transition: opacity .9s ease;
}
@media (max-width: 760px) {
  .hero-slide { background-image: var(--slide-sm); }
}
.hero-slide.active { opacity: 1; }
/* The scrim over the photographs. The carousel rotates through slides of very
   different brightness, so this has to be dark enough for the lightest one, not
   the one it was eyeballed against: measured per slide, the old ramp left the
   headline at 2.69:1 and the lead at 2.31:1 on the first slide at phone width. */
.hero::before {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(90deg,
    rgba(20,12,8,.90) 0%, rgba(20,12,8,.84) 34%, rgba(20,12,8,.52) 58%, rgba(20,12,8,.28) 100%);
}
.hero-headline { transition: opacity .3s ease; }
.hero-headline.fading { opacity: 0; }
.hero-controls { display: flex; align-items: center; gap: 14px; margin-top: 28px; }
/* Prev/next arrows sit at the left and right edges of the hero */
.hero-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 6;
  width: 54px; height: 54px; border-radius: 50%;
  border: 2px solid #fff; background: rgba(0,0,0,.5); color: #fff;
  cursor: pointer; display: grid; place-items: center;
  box-shadow: 0 3px 14px rgba(0,0,0,.35);
  transition: background .18s ease, color .18s ease, border-color .18s ease;
}
.hero-arrow svg { width: 24px; height: 24px; display: block; }
.hero-arrow:hover { background: var(--red); border-color: var(--red); color: #fff; }
.hero-arrow.prev { left: 22px; }
.hero-arrow.next { right: 22px; }
/* The arrows are pinned to the viewport edges at z-index 6, while .hero .container
   — which holds the copy and the quote form — is only z-index 2. Once the hero is
   two columns (above 960px) but the viewport is too narrow for the 1180px
   container to leave a margin, the next arrow lands on top of the form. Hit-tested
   in Chromium: at 980, 1024, 1100, 1200 and 1208px, elementFromPoint over the
   right-hand edge of #lead-type returns button.hero-arrow, so clicking the
   dropdown's chevron advances the carousel instead of opening the select. At
   1210px and above the select wins, and below 961px the hero has stacked and the
   arrows have moved to top:28%, clear of the form. So hide them across exactly
   that band and nowhere else, and the 44px dots remain as the control, as they
   already are on phones.

   The band used to stop at 1209px, but that only fixed the hit-test. Drawn, the
   arrows still overlapped from 1210px to about 1300px: the gutter outside the
   1180px container is narrower than the 22px inset plus the 54px arrow, so at
   1280px the prev arrow covered the start of the lead and the "Trusted by" line,
   and the next arrow sat on the edge of the enquiry card. They clear the content
   by 16px from 1316px. */
@media (min-width: 961px) and (max-width: 1315px) {
  .hero-arrow { display: none; }
}
.hero-dots { display: flex; align-items: center; gap: 4px; min-height: 24px; }  /* reserve height before JS injects the controls */
/* Carousel controls. The dots were 11x11 with a 9px gap, which fails the 24x24
   minimum target size — and below 600px the arrows are hidden, so they were the
   only control. The visible dot stays the same size; the tap target around it
   grows. */
/* 44px, not the 24px that clears WCAG 2.2 AA on paper. Below 600px the arrows
   are hidden, so on a phone these dots are the only way to reach slides 2 and 3,
   and a 24px circle is a fiddly thing to hit with a thumb. The visible dot is
   unchanged; only the target around it grows. */
.hero-dots button { min-width: 44px; min-height: 44px; display: grid; place-items: center; background: none; border: 0; padding: 0; cursor: pointer; }
.hero-dots button::before { content: ''; width: 11px; height: 11px; border-radius: 50%; background: rgba(255,255,255,.55); transition: background .2s ease, transform .2s ease; }
.hero-dots button.active::before { background: #fff; transform: scale(1.2); }
.hero-dots button:focus-visible { outline: 2px solid #fff; outline-offset: 1px; border-radius: 50%; }
/* Sits in the same row as the dots, which are now 44px tall, so it needs the
   same height or it drops out of line and reads as a stray fourth dot. */
.hero-pause {
  color: #fff; font-size: .78rem; line-height: 1; letter-spacing: .05em;
  min-width: 44px; min-height: 44px; display: inline-grid; place-items: center;
  background: none; border: 0; padding: 0; cursor: pointer;
}
/* `.hero-dots .hero-pause`, not `.hero-pause`: main.js appends this button inside
   .hero-dots, so `.hero-dots button::before` (0,1,2) matched it and beat a bare
   `.hero-pause::before` (0,1,1) regardless of source order. The reset never
   applied, so the pause control painted an 11px dot of its own — the stray fourth
   dot the comment above says was removed — and, being an inline-grid, stacked it
   above the ❚❚ glyph and out of line with the row. */
.hero-dots .hero-pause::before { content: none; }

.hero .container {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: 1.05fr .95fr; gap: 48px; align-items: center;
  padding-top: 70px; padding-bottom: 70px;
}
.hero-copy h1 { font-size: 3rem; font-weight: 700; letter-spacing: .02em; text-transform: uppercase; margin-bottom: .35em; }
.hero-copy .lead { font-size: 1.2rem; color: #f0eae3; max-width: 30ch; }
.hero-trust { display: flex; align-items: center; gap: 12px; margin: 22px 0 26px; font-size: .95rem; }
.stars { color: var(--gold); letter-spacing: 2px; font-size: 1.05rem; }
.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; }

/* Lead form card in hero */
.lead-card {
  background: #fff; color: var(--ink);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
  padding: 30px 30px 26px;
}
.lead-card h2 { color: var(--red); font-weight: 700; font-size: 1.5rem; margin-bottom: .15em; }
.lead-card .sub { font-size: .92rem; color: var(--ink-soft); margin-bottom: 18px; }

/* Multi-step forms: by default (and on desktop) every step is visible and the
   Back/Next controls stay hidden — it behaves as one normal form. Stepping is
   switched on by JS (data-stepping="on") only on small screens. */
.step-buttons { display: flex; gap: 10px; margin-top: 4px; }
.step-buttons .btn { flex: 1; }
.step-indicator { font-size: .78rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--red); margin: 0 0 12px; }
.multistep[data-stepping="on"] .form-step { display: none; }
.multistep[data-stepping="on"] .form-step.active { display: block; }

.field { margin-bottom: 12px; }
.field label { display: block; font-size: .8rem; font-weight: 600; color: var(--ink-soft); margin-bottom: 4px; }
/* 16px, at every width, not just on phones. iOS zooms the whole page when a
   field with a smaller font takes focus, and does not zoom back out — so the
   visitor is left scrolled sideways in the middle of the form. This rule used to
   live inside @media (max-width: 600px), which covered a phone in portrait and
   nothing else: every iPad, and every large phone turned sideways, still zoomed.
   max() rather than a flat 16px so a larger browser default still wins. */
.field input, .field select, .field textarea,
.est-field input, .est-field select, .price-input {
  font-size: max(16px, 1rem);
}
.field input, .field select, .field textarea,
.est-field input, .est-field select {
  width: 100%; padding: 12px 14px; border: 1px solid #d5d5d5; border-radius: var(--radius);
  font-family: inherit; color: var(--ink); background: #fff;
}
.field input:focus, .field select:focus, .field textarea:focus,
.est-field input:focus, .est-field select:focus, .price-input:focus {
  outline: none; border-color: var(--red); box-shadow: 0 0 0 3px rgba(164,33,40,.12);
}
.field textarea { resize: vertical; min-height: 78px; }
/* Standalone links — the phone number in the topbar, the footer links, the
   breadcrumb — were between 15 and 22px tall, which is a hard thing to hit with
   a thumb and a WCAG 2.2 SC 2.5.8 failure. Links inside a sentence are exempt
   from that rule and are left alone: padding them would wreck the line spacing.
   The padding is vertical only, so nothing moves horizontally. */
.topbar a, .footer-col a, .footer-links a, .breadcrumb a, .socials a,
.footer-bottom a {
  display: inline-flex; align-items: center; min-height: 24px;
}
@media (max-width: 900px) {
  /* More room where a thumb is doing the pointing. */
  .footer-col a, .footer-links a { min-height: 32px; }
}

.form-note { font-size: .85rem; color: var(--ink-mute); margin: 10px 0 0; text-align: center; line-height: 1.5; }
.form-note a { color: #5b5b5b; text-decoration: underline; }
/* Was .72rem — 11.5px. That is the text nobody reads, and it is the text that
   says what happens to their email address. */
.form-msg { font-size: .9rem; margin-top: 10px; padding: 10px 12px; border-radius: var(--radius); display: none; }
.form-msg.ok  { display: block; background: #e8f5e9; color: #256029; }
.form-msg.err { display: block; background: #fdecea; color: #92231b; }
/* Focused programmatically after a failed submit — outline-offset keeps the ring
   outside the tinted panel so it stays visible against it. */
.form-msg:focus { outline: 2px solid var(--red); outline-offset: 2px; }

/* ---------- Google reviews ------------------------------------------------- */
.author-quotes { background: var(--light); padding: 62px 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.author-quotes.on-band { background: transparent; padding: 0; border: 0; }
.author-quotes > .container > h2 { text-align: center; font-weight: 300; font-size: 2rem; color: var(--ink); margin-bottom: 16px; }
.g-head {
  display: flex; align-items: center; justify-content: center; gap: 10px 22px;
  flex-wrap: wrap; margin-bottom: 34px;
}
.g-head .g-logo { display: flex; align-items: center; gap: 10px; }
.g-head .g-logo img { width: 30px; height: 30px; }
.g-head .g-logo b { font-size: 1.1rem; font-weight: 600; color: var(--ink); }
.g-head .g-score { display: flex; align-items: center; gap: 12px; }
.g-head .g-score .num { font-size: 2.1rem; font-weight: 700; color: var(--ink); line-height: 1; }
.g-head .g-score .stars { color: #f2a100; font-size: 1.3rem; letter-spacing: 2px; }
.g-head .g-score .count { display: block; font-size: .82rem; color: var(--ink-soft); margin-top: 3px; }
.g-head .aq-cta { margin-left: 6px; }

.aq-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.aq-card {
  background: #fff; border: 1px solid var(--line); border-top: 3px solid var(--red);
  border-radius: var(--radius); padding: 26px 24px 24px; position: relative; text-align: left;
  transition: box-shadow .18s ease;
}
.aq-card:hover { box-shadow: 0 6px 20px rgba(0,0,0,.08); }
.aq-card .aq-mark { position: absolute; top: 22px; right: 22px; width: 20px; height: 20px; }
.aq-person { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; padding-right: 28px; }
.aq-avatar {
  width: 46px; height: 46px; border-radius: 50%; flex: 0 0 46px;
  display: grid; place-items: center; color: #fff; font-weight: 700; font-size: 1.1rem;
  font-family: var(--serif);
}
.aq-person > span:last-child { display: flex; flex-direction: column; min-width: 0; }
.aq-person .aq-name { font-weight: 700; color: var(--ink); font-size: 1rem; line-height: 1.3; }
.aq-person .aq-role { font-size: .8rem; color: #70757a; margin-top: 2px; }
.aq-card .aq-stars { color: #f2a100; letter-spacing: 2px; font-size: 1.05rem; margin-bottom: 12px; }
.aq-card p { color: var(--ink-soft); font-size: .95rem; line-height: 1.6; margin: 0; }
/* Testimonials come from the admin and can run to more than one paragraph. */
.aq-card p + p { margin-top: .7em; }
.on-band .aq-card { border-top: 3px solid var(--red); }

/* ---------- Service cards -------------------------------------------------- */
.services { background: var(--light); padding: 70px 0; }
.service-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 36px; }
/* A column with the button pushed to the foot, so the three Learn More buttons
   share a baseline however many lines each description runs to. The fixed
   84px min-height on the paragraph that used to do this is three lines, and the
   first card's copy is four at desktop, so its button sat 22px below the others. */
.service-card { text-align: center; display: flex; flex-direction: column; }
.service-card .btn { margin-top: auto; align-self: center; }
.service-icon {
  width: 92px; height: 92px; border-radius: 50%; background: #e6e6e6;
  display: grid; place-items: center; margin: 0 auto 22px;
  transition: background .2s ease;
}
.service-icon svg { width: 40px; height: 40px; fill: #6d6d6d; transition: fill .2s ease; }
.service-card:hover .service-icon { background: var(--red); }
.service-card:hover .service-icon svg { fill: #fff; }
.service-card h3 { text-transform: uppercase; letter-spacing: .06em; color: #6d6d6d; font-size: 1.15rem; font-weight: 600; }

/* ---------- Section helpers ------------------------------------------------ */
.section { padding: 74px 0; }
.section-red-title { color: var(--red); font-size: 2.4rem; }
.eyebrow { color: var(--red); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; font-size: .82rem; margin: 0 0 8px; }
/* Consistent section heading: red eyebrow + dark title */
.sec-head { margin-bottom: 24px; }
.sec-title { color: var(--ink); font-weight: 300; font-size: 2.2rem; margin: 0; line-height: 1.2; }
.author-quotes .eyebrow { text-align: center; }

/* ---------- Credibility / stats strip -------------------------------------- */
.stats-band { background: var(--charcoal); color: #fff; border-top: 3px solid var(--red); }
.stats-band .container {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px;
  padding: 40px 24px; text-align: center;
}
.stat { padding: 4px 12px; }
.stat + .stat { border-left: 1px solid rgba(255,255,255,.14); }
/* Fluid, for the same reason .stat-row .st-num below is: these values are single
   unbreakable words ("International"), and at 320px the band is two ~135px columns
   where a fixed size overflows the viewport. break-word backs up any longer value. */
.stat-num {
  display: block; font-size: clamp(1.35rem, 5vw, 2.1rem); font-weight: 700; color: #fff;
  line-height: 1.1; overflow-wrap: break-word;
}
.stat-label { display: block; font-size: .8rem; letter-spacing: .06em; text-transform: uppercase; color: #b7b7b7; margin-top: 8px; }

/* Find out more / cost */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 48px; align-items: center; }
.cost-media {
  background: #f2f2f2; border-radius: var(--radius); min-height: 320px;
  display: grid; place-items: center; color: #b5b5b5; text-align: center;
  border: 1px solid var(--line); overflow: hidden;
}
.cost-media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Book-cover collage (Our Services) */
.book-collage { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.mini-cover {
  aspect-ratio: 3/4; border-radius: var(--radius); color: #fff; padding: 14px;
  display: flex; flex-direction: column; justify-content: flex-end;
  box-shadow: 0 8px 20px rgba(0,0,0,.16); text-decoration: none;
  transition: transform .2s ease; overflow: hidden; background: #eee;
}
.mini-cover img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.mini-cover:has(img) { position: relative; padding: 0; }
.mini-cover:hover { transform: translateY(-4px); text-decoration: none; }
.mini-cover .mc-title { font-family: var(--serif); font-weight: 700; font-size: .95rem; line-height: 1.15; }
.mini-cover .mc-author { font-size: .72rem; opacity: .85; margin-top: 4px; }
.book-collage .tall { grid-row: span 1; }

/* Featured testimonial band */
.testimonial-band { background: var(--band-grey); color: #fff; padding: 70px 0; }
.testimonial-band h2 { text-align: center; letter-spacing: .5em; font-size: 2rem; text-indent: .5em; margin-bottom: 28px; }
.testimonial-band .quote { max-width: 900px; margin: 0 auto; text-align: center; font-size: 1.08rem; color: #f3f3f3; }
.testimonial-band .quote p { color: #f3f3f3; }
.testimonial-band .cite { display: block; margin-top: 18px; font-weight: 600; }
/* A testimonial may carry the author's own website. Inline it measures 23px
   tall — just under the 24px minimum target — and unlike a link in a
   paragraph of prose it is a destination someone deliberately taps, so it
   gets the height rather than the SC 2.5.8 running-text exception. */
.cite a { display: inline-block; padding: 3px 0; }
.testimonial-band .cite a { color: #7fdfe9; text-decoration: underline; }

/* Our services + accordion */
.accordion-item { border-bottom: 1px solid var(--line); }
.accordion-head {
  width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  display: flex; align-items: center; gap: 14px; padding: 18px 4px; font-size: 1.05rem; color: var(--ink);
  font-family: inherit;
}
.accordion-head .tick {
  width: 26px; height: 26px; flex: 0 0 26px; background: var(--red); color: #fff;
  display: grid; place-items: center; border-radius: 3px; font-weight: 700; font-size: 1.1rem;
}
.accordion-item.open .accordion-head { color: var(--red); }
.accordion-body { max-height: 0; overflow: hidden; transition: max-height .35s ease; }
/* Fallback cap if JS is unavailable; JS sets the exact height so panels never clip. */
.accordion-item.open .accordion-body { max-height: 2000px; }
.acc-inner { padding: 2px 8px 22px 44px; }
.acc-inner p { margin: 0 0 12px; }
.acc-inner ul { list-style: none; margin: 0; padding: 0; }
.acc-inner li { position: relative; padding: 5px 0 5px 22px; color: var(--ink-soft); }
.acc-inner li::before { content: "•"; color: var(--red); font-weight: 700; position: absolute; left: 4px; }
.tick-icon::before { content: "+"; }
.accordion-item.open .tick-icon::before { content: "–"; }
.check-list { list-style: none; padding: 0; margin: 0 0 22px; }
.check-list li { padding: 6px 0 6px 28px; position: relative; color: var(--ink-soft); }
.check-list li::before { content: "›"; color: var(--red); font-weight: 700; position: absolute; left: 6px; }

/* ---------- Big CTA banner (new) ------------------------------------------ */
.cta-banner { background: var(--red); color: #fff; text-align: center; padding: 60px 0; }
.cta-banner h2 { font-size: 2.2rem; font-weight: 300; }
.cta-banner p { color: #ffdada; max-width: 620px; margin: 0 auto 26px; }
.cta-banner .hero-actions { justify-content: center; }
.cta-banner .btn-ghost:hover { color: var(--red); }

/* ---------- About band ----------------------------------------------------- */
.about-band {
  background: linear-gradient(rgba(30,34,40,.72), rgba(30,34,40,.82)),
              linear-gradient(120deg, #3a4048, #1d2126);
  color: #fff; text-align: center; padding: 90px 0;
}
.about-band h2 { font-size: 2.2rem; }
.about-band p { color: #e2e2e2; max-width: 720px; margin: 0 auto 22px; }

/* ---------- Footer --------------------------------------------------------- */
.site-footer { background: var(--charcoal); color: #cfcfcf; padding: 64px 0 0; }
.footer-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; }
.footer-col h3 {
  color: #fff; font-size: 1.15rem; font-weight: 400; padding-bottom: 12px; position: relative; margin-bottom: 18px;
}
.footer-col h3::after {
  content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 2px;
  background: linear-gradient(90deg, var(--red) 0 40%, #666 40% 100%);
}
.footer-links { list-style: none; padding: 0; margin: 0; }
.footer-links li { border-bottom: 1px solid rgba(255,255,255,.12); }
.footer-links a { color: #cfcfcf; display: block; padding: 11px 0; }
.footer-links a::before { content: "› "; color: #cfcfcf; }
.footer-links a:hover { color: #fff; text-decoration: none; }
.footer-col p { color: #bdbdbd; }
.footer-col a { color: #fff; }
.footer-contact strong { color: #fff; display: block; }
.socials { display: flex; gap: 12px; margin-top: 16px; }
.socials a {
  width: 42px; height: 42px; border-radius: 50%; background: #fff; display: grid; place-items: center;
}
.socials svg { width: 20px; height: 20px; fill: var(--charcoal); }
.footer-bottom { border-top: 1px solid rgba(255,255,255,.12); margin-top: 54px; padding: 24px 0; }
.footer-bottom .container { color: #b3b3b3; font-size: .88rem; }
.footer-bottom a { color: #ddd; }
/* On a phone the copyright line wrapped after its separator and left a stray
   "|" hanging at the end of the line. Below 600px the legal links start their
   own line and the separator before them goes. */
@media (max-width: 600px) {
  .fb-sep { display: none; }
  .fb-links::before { content: "\A"; white-space: pre; }
}

/* ---------- Testimonials / portfolio page --------------------------------- */
/* The photograph arrives as two custom properties rather than a finished
   background-image, so this stylesheet can pick the right one. A hero is 1920px
   wide and a phone shows it across 390 — even at 3x that is 1170px, and most
   phones are 2x. The -sm copies are 1200px and 39-50% smaller.

   It has to be done this way round because the photograph differs per page and
   therefore lives in an inline style, and a media query cannot override an
   inline style. Custom properties can be set inline and read from here. */
.page-hero {
  background: var(--charcoal); color: #fff; padding: 66px 0; text-align: center;
}
.page-hero[style*="--hero"] {
  background-image: var(--hero-scrim), var(--hero);
  background-size: cover;
  background-position: center;
}
@media (max-width: 760px) {
  .page-hero[style*="--hero"] { background-image: var(--hero-scrim), var(--hero-sm); }
}
.page-hero h1 { font-size: 2.6rem; font-weight: 300; }
.page-hero p { color: #d8d8d8; max-width: 640px; margin: 0 auto; }
.filters { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin: 0 0 36px; }
/* Twelve categories wrapping and centring turned into a ragged column roughly
   700px tall — the books, which are the point of the page, started below the
   second screenful. A single swipeable row keeps them one gesture away and gives
   the grid the screen back. scroll-padding keeps the active chip clear of the
   edge when it is scrolled into view. */
@media (max-width: 700px) {
  .filters {
    flex-wrap: nowrap; justify-content: flex-start;
    overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x proximity; scroll-padding-inline: 18px;
    /* Full-bleed so the row can run to both edges, with the padding put back
       inside — otherwise the first and last chip look clipped. */
    margin-inline: -18px; padding: 4px 18px 12px;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .filters::-webkit-scrollbar { display: none; }
  .filter-btn { flex: 0 0 auto; scroll-snap-align: start; min-height: 40px; }
}
.filter-btn {
  border: 1px solid var(--line); background: #fff; color: var(--ink-soft);
  padding: 8px 18px; border-radius: var(--radius); cursor: pointer; font-family: inherit; font-size: .9rem;
}
.filter-btn.active, .filter-btn:hover { background: var(--red); color: #fff; border-color: var(--red); }
.book-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 28px; }
/* Sixty-five cards render in one pass on the portfolio. content-visibility lets
   the browser skip layout, style and paint for the ones off screen, which on a
   mid-range phone is most of the work the page does. contain-intrinsic-size is
   not optional with it: without a placeholder height the off-screen cards
   collapse to nothing and the scrollbar jumps about as you scroll, which trades
   a rendering problem for a worse layout-shift one. 'auto' means the browser
   remembers each card's real height once it has rendered it. */
.book-card {
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: #fff;
  transition: box-shadow .2s ease, transform .2s ease;
  content-visibility: auto;
  /* Measured, not guessed. A rendered card is 419-487px tall once the grid has
     two or more columns, so 470px is the middle of that range; the flat 420px
     that used to be here was short everywhere and 168px short at phone width,
     which understated the portfolio's height by roughly 11,000px across 65 cards
     — the page kept growing as you scrolled and the End key never reached the
     bottom in one go. Below the two-column threshold the cover is a 3:4 crop of
     the full column width, so the card is 590px at 390px wide and 736px at 500px;
     620px sits in the middle of the widths real phones use. */
  contain-intrinsic-size: auto 470px;
}
@media (max-width: 515px) {   /* one column: 220px min + 28px gap + padding */
  .book-card { contain-intrinsic-size: auto 620px; }
}
.book-card:hover { box-shadow: var(--shadow); transform: translateY(-3px); }
.book-cover { position: relative; aspect-ratio: 3/4; background: #8a2028; display: grid; place-items: center; color: #fff; text-align: center; padding: 18px; overflow: hidden; }
/* Every cover sits on a white panel of the same size, so the burgundy around it
   is the same width on all four sides whatever the shape of the image. The
   client asked for this (24 September 2026): the covers carried over from the
   old site each have their own white frame baked in, 4% to 12% of their width,
   and their shapes run from 2:3 to square, so with the image alone the burgundy
   showed as a thin line beside one cover and a deep band above and below the
   next. object-fit: contain letterboxes the image inside the panel, the white
   background fills the letterbox, and the padding keeps a white margin on every
   side even for a cover supplied without a frame of its own. */
.book-cover img { width: 100%; height: 100%; object-fit: contain; background: #fff; padding: 10px; }
/* Genre-coloured placeholder cover (used until a real cover image is set) */
.cover-ph { position: absolute; inset: 0; background: var(--cover, #8a2028); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 26px 20px; box-shadow: inset 0 0 0 1px rgba(255,255,255,.16); }
.cover-ph-title { font-size: 1.04rem; font-weight: 700; line-height: 1.28; letter-spacing: .005em; }
.cover-ph-rule { width: 34px; height: 2px; background: rgba(255,255,255,.55); }
.cover-ph-author { font-size: .74rem; font-weight: 400; opacity: .82; text-transform: uppercase; letter-spacing: .09em; line-height: 1.3; }
.book-body { padding: 16px 18px 20px; }
.book-body h3 { font-size: 1.05rem; font-weight: 600; color: var(--ink); margin-bottom: 4px; }
.book-body .author { color: var(--red); font-size: .88rem; font-weight: 600; margin-bottom: 8px; }
.book-body .cat { display: inline-block; font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-mute-2); background: var(--light); padding: 3px 10px; border-radius: 30px; }
.state { text-align: center; padding: 50px 0; color: #5f5f5f; }
.book-card--click { cursor: pointer; }
/* "Featured" ribbon on portfolio covers */
.featured-flag {
  position: absolute; top: 10px; left: -1px; z-index: 2;
  background: var(--red); color: #fff;
  font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
  padding: 5px 12px 5px 10px; box-shadow: 0 2px 8px rgba(0,0,0,.25);
  clip-path: polygon(0 0, 100% 0, calc(100% - 8px) 50%, 100% 100%, 0 100%);
}
.featured-chip {
  display: inline-block; background: var(--red); color: #fff;
  font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  padding: 3px 10px; border-radius: 30px; vertical-align: 1px;
}
.book-card--click:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

/* Book detail modal */
.book-modal { position: fixed; inset: 0; z-index: 200; display: grid; place-items: center; padding: 24px; }
.bm-backdrop { position: absolute; inset: 0; background: rgba(20, 12, 8, .72); }
.bm-dialog {
  position: relative; background: #fff; border-radius: var(--radius); box-shadow: var(--shadow-lg);
  width: min(880px, 100%); max-height: min(86vh, 900px); overflow-y: auto;
  display: grid; grid-template-columns: 300px 1fr; gap: 34px; padding: 34px;
  border-top: 3px solid var(--red);
}
.bm-close {
  position: absolute; top: 10px; right: 12px; background: none; border: 0; cursor: pointer;
  font-size: 1.9rem; line-height: 1; color: var(--ink-mute); padding: 6px;
}
.bm-close:hover { color: var(--red); }
.bm-cover img, .bm-cover .cover-ph { width: 100%; height: auto; display: block; box-shadow: var(--shadow); }
.bm-cover .cover-ph { position: static; aspect-ratio: 3/4; display: flex; }
.bm-body h3 { font-size: 1.55rem; font-weight: 600; color: var(--ink); margin-bottom: 2px; }
.bm-author { color: var(--red); font-weight: 600; margin-bottom: 10px; }
.bm-desc { margin: 16px 0 20px; }
.bm-desc p { font-size: .95rem; line-height: 1.65; }
.bm-specs { border-top: 1px solid var(--line); margin-bottom: 22px; }
.bm-spec { display: flex; justify-content: space-between; gap: 18px; padding: 8px 0; border-bottom: 1px solid var(--line); font-size: .9rem; }
.bm-spec span { color: var(--ink-mute); }
.bm-spec strong { font-weight: 600; color: var(--ink); text-align: right; }
@media (max-width: 700px) {
  .bm-dialog { grid-template-columns: 1fr; gap: 22px; padding: 24px; }
  .bm-cover { max-width: 220px; margin: 0 auto; }
}

/* ---------- Admin ---------------------------------------------------------- */
.admin-wrap { max-width: 960px; margin: 0 auto; padding: 40px 24px 80px; }
.admin-login { max-width: 380px; margin: 60px auto; background: #fff; padding: 34px; border-radius: var(--radius); box-shadow: var(--shadow); }
.admin-bar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 30px; flex-wrap: wrap; gap: 12px; }
.card { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 24px; margin-bottom: 26px; }
.card h2 { font-size: 1.3rem; color: var(--red); font-weight: 600; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.admin-list { list-style: none; padding: 0; margin: 0; }
.admin-list li { display: flex; align-items: center; gap: 14px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.admin-list .thumb { width: 46px; height: 60px; border-radius: 3px; background: linear-gradient(135deg,#7a1418,#a42128); object-fit: cover; flex: 0 0 46px; }
.admin-list .meta { flex: 1; }
.admin-list .meta strong { display: block; }
.admin-list .meta span { font-size: .82rem; color: #6b6b6b; }
/* A .badge is a span, and it lives inside .meta, so the rule above beat it on
   specificity and repainted it #6b6b6b on the badge's own #e8e8e8 — 4.35:1 at
   13.12px, under the 4.5 it needs. Restore the badge's own colour and size; on
   #e8e8e8 the intended #4a4a4a is 7.2:1. */
.admin-list .meta .badge { font-size: .7rem; color: #4a4a4a; }
.admin-actions { display: flex; gap: 8px; flex: 0 0 auto; }
.upload-row { display: flex; gap: 10px; align-items: stretch; }
.upload-row input[name="cover_url"] { flex: 1; }
.upload-btn { display: inline-flex; align-items: center; cursor: pointer; white-space: nowrap; }
.upload-msg:empty { display: none; }
.btn-del { background: none; border: 1px solid #d99; color: #b3261e; padding: 7px 14px; border-radius: var(--radius); cursor: pointer; font-family: inherit; }
.btn-del:hover { background: #b3261e; color: #fff; }
.btn-edit { background: none; border: 1px solid #bbb; color: var(--ink); padding: 7px 14px; border-radius: var(--radius); cursor: pointer; font-family: inherit; }
.btn-edit:hover { background: var(--charcoal); color: #fff; border-color: var(--charcoal); }
.badge { background: #e8e8e8; color: #4a4a4a; font-size: .7rem; padding: 2px 8px; border-radius: 20px; text-transform: uppercase; letter-spacing: .05em; }
.field-note { font-size: .8rem; color: #6b6b6b; line-height: 1.5; margin: 6px 0 0; }
.field-note a { color: var(--red); }

/* Admin sections: one panel at a time instead of one very long page. */
.admin-tabs { display: flex; flex-wrap: wrap; gap: 2px; margin-bottom: 26px; border-bottom: 1px solid var(--line); }
.admin-tab {
  background: none; border: 1px solid transparent; border-bottom: 0; margin-bottom: -1px;
  padding: 11px 18px; font-family: inherit; font-size: .92rem; color: var(--ink-soft);
  cursor: pointer; border-radius: var(--radius) var(--radius) 0 0;
}
.admin-tab:hover { color: var(--red); }
.admin-tab.is-active { background: #fff; border-color: var(--line); color: var(--red); font-weight: 600; }
.admin-tab:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

.inline-form { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; margin-bottom: 4px; }
.inline-form .field { flex: 1 1 220px; margin: 0; }

/* 404 page */
/* A whole feature card that is a link — the hover lift is the affordance. */
.feature-link { text-decoration: none; color: inherit; display: block; transition: box-shadow .2s ease, transform .2s ease, border-color .2s ease; }
.feature-link:hover { box-shadow: var(--shadow); transform: translateY(-3px); border-color: #d5d5d5; }
.feature-link .feature-more { display: block; margin-top: 12px; color: var(--red); font-weight: 600; font-size: .88rem; }
.feature-link:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }
.nf-more { margin-top: 54px; padding-top: 40px; border-top: 1px solid var(--line); }
.nf-more > h2 { font-size: 1.5rem; font-weight: 300; color: var(--ink); margin-bottom: 24px; }
.nf-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 30px 34px; }
.nf-cols h3 { font-size: .82rem; text-transform: uppercase; letter-spacing: .07em; color: var(--red); margin-bottom: 12px; }
.nf-links { list-style: none; margin: 0; padding: 0; }
.nf-links li { margin-bottom: 8px; }
.nf-links a { color: var(--ink-soft); text-decoration: none; font-size: .93rem; }
.nf-links a::before { content: "\203A"; color: var(--red); margin-right: 8px; font-weight: 700; }
.nf-links a:hover { color: var(--red); text-decoration: underline; }

/* Enquiries */
.tab-count {
  display: inline-block; margin-left: 7px; padding: 1px 7px; border-radius: 20px;
  background: var(--red); color: #fff; font-size: .72rem; font-weight: 600; line-height: 1.5;
}
.admin-tab.is-active .tab-count { background: var(--red); color: #fff; }
.enquiry { border: 1px solid var(--line); border-left: 3px solid var(--red); border-radius: var(--radius); padding: 18px 20px; margin-bottom: 12px; }
.enquiry-head { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.enquiry-head h3 { font-size: 1.05rem; font-weight: 600; color: var(--ink); margin: 0; }
.enquiry-when { font-size: .78rem; color: #6b6b6b; white-space: nowrap; }
.enquiry-contact { margin: 6px 0 0; font-size: .9rem; }
.enquiry-contact a { color: var(--red); }
.enquiry-meta { margin: 4px 0 0; font-size: .78rem; text-transform: uppercase; letter-spacing: .05em; color: #6b6b6b; }
.enquiry-message { margin: 12px 0 0; font-size: .93rem; line-height: 1.6; color: var(--ink-soft); white-space: pre-wrap; }
.enquiry-actions { display: flex; gap: 8px; align-items: center; margin-top: 14px; flex-wrap: wrap; }
.btn-sm { padding: 6px 14px; font-size: .82rem; }
/* Honour the operating system's reduced-motion setting. Nothing here respected it
   before — including the hero cross-fade and the site-wide smooth scrolling. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* Sticky bars must not sit over whatever has just been focused. */
:target, :focus { scroll-margin-top: 96px; scroll-margin-bottom: 72px; }

/* A file input that is invisible but still focusable. `hidden` (and
   display:none) removes it from the tab order entirely, which made the admin's
   cover-image upload unreachable by keyboard — a staff member using only a
   keyboard could not add a cover to a book at all. */
/* `input.visually-hidden-input`, not `.visually-hidden-input`: these file inputs
   sit inside a .field, so `.field input { width: 100% }` matched them at equal
   specificity and won. Absolutely positioned, that resolved to the full viewport
   width from a static position two thirds of the way across — a 1280px box ending
   at x=2323 — so the admin's Books and Blog tabs scrolled sideways because of an
   input nobody can see. The tag selector puts this rule ahead of it. */
input.visually-hidden-input {
  position: absolute; width: 1px; height: 1px; opacity: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
.upload-btn:focus-within { outline: 2px solid var(--red); outline-offset: 2px; }

/* Skip link. Off-screen until focused, then pinned to the top-left so a keyboard
   user can jump the 14 header tab stops that precede content on every page. */
.skip-link {
  position: absolute; top: -100px; left: 8px; z-index: 200;
  background: var(--red); color: #fff; padding: 12px 20px;
  border-radius: 0 0 var(--radius) var(--radius); font-weight: 600; text-decoration: none;
  transition: top .15s ease;
}
.skip-link:focus { top: 0; outline: 3px solid #fff; outline-offset: -6px; }

/* A honeypot field. Positioned off-screen rather than display:none, because some
   bots skip inputs that are obviously hidden; aria-hidden and tabindex=-1 keep it
   away from screen readers and the keyboard. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Visible to screen readers only. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Price table */
.price-h3 { font-size: .95rem; color: var(--ink); margin: 26px 0 10px; padding-bottom: 6px; border-bottom: 1px solid var(--line); }
.price-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 8px 22px; }
.price-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: .88rem; font-weight: 400; }
.price-name { color: var(--ink-soft); }
.price-flag { display: block; font-size: .7rem; text-transform: uppercase; letter-spacing: .05em; color: #6b6b6b; }
.price-input {
  width: 112px; flex: 0 0 112px; margin: 0; text-align: right;
  padding: 8px 10px; border: 1px solid #d5d5d5; border-radius: var(--radius);
  /* No font-size here. .price-input is deliberately listed in the max(16px, 1rem)
     group above, and a `.9rem` at equal specificity but later in the file simply
     cancelled it — every price field computed to 14.4px, so iOS zoomed on focus
     and did not zoom back. The price grid is 184 such fields on one screen. */
  font-family: inherit; color: var(--ink); background: #fff;
}
.price-input.is-changed { border-color: var(--red); background: #fdf6f6; }
.price-actions { margin-top: 28px; padding-top: 20px; border-top: 1px solid var(--line); display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.pct-row { display: flex; align-items: center; gap: 6px; }
.pct-row input { width: 100px; margin: 0; }
.pct-sign { color: var(--ink-soft); }
.price-result { width: 100%; border-collapse: collapse; margin-top: 18px; }
.price-result th, .price-result td { padding: 9px 12px; border-bottom: 1px solid var(--line); font-size: .92rem; text-align: left; }
.price-result th { font-weight: 400; color: var(--ink-soft); width: 55%; }
.price-result td { font-weight: 600; }
.check-form [hidden] { display: none !important; }

@media (max-width: 640px) {
  .admin-tabs { gap: 0; }
  .admin-tab { flex: 1 1 auto; padding: 10px 12px; font-size: .84rem; }
  .price-grid { grid-template-columns: 1fr; }
  .price-row { gap: 10px; }
  .price-input { width: 96px; flex: 0 0 96px; }
}

@media (max-width: 420px) {
  /* Let the row wrap so the actions drop under the title instead of being
     clipped off the side of a viewport that cannot scroll horizontally. */
  .admin-list li { flex-wrap: wrap; }
  .admin-list .meta { flex: 1 1 100%; min-width: 0; }
  .admin-list .admin-actions { flex: 1 1 100%; }
  .admin-list .thumb { order: -1; }
}

/* ---------- Cost estimator (Self-Publishing Costs) ------------------------- */
.estimator-band { background: var(--light); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.estimator {
  max-width: 900px; margin: 0 auto; background: #fff;
  border: 1px solid var(--line); border-top: 3px solid var(--red);
  border-radius: var(--radius); padding: 34px 34px 30px; box-shadow: var(--shadow);
}
/* Until the options have loaded there is nothing to show but the button. */
.estimator:not(.is-ready) .est-actions { display: none; }

.est-group { border: 0; padding: 0; margin: 0 0 26px; }
.est-group legend {
  padding: 0; margin-bottom: 14px; font-size: .78rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .08em; color: var(--red);
}
.est-choices { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; }
.est-choice {
  position: relative; display: flex; flex-direction: column; gap: 4px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius); padding: 15px 17px;
  transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;
  font-weight: 400; margin: 0;
}
.est-choice:hover { border-color: #c9c9c9; }
.est-choice input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.est-choice.is-on { border-color: var(--red); background: #fdf7f7; box-shadow: inset 0 0 0 1px var(--red); }
.est-choice:focus-within { outline: 2px solid var(--red); outline-offset: 2px; }
.est-choice-label { font-weight: 600; color: var(--ink); font-size: .98rem; }
.est-choice-note { font-size: .8rem; color: #6b6b6b; line-height: 1.45; }

/* minmax(0, 1fr) — a <select> with long option text has a wide min-content
   size, and plain 1fr lets that blow the grid out past the viewport. */
.est-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 22px; }
.est-field { display: flex; flex-direction: column; min-width: 0; }
.est-field label { font-size: .84rem; font-weight: 600; color: var(--ink); margin-bottom: 6px; }
.est-field select, .est-field input { margin: 0; max-width: 100%; }
.est-note { font-size: .77rem; color: #6b6b6b; line-height: 1.45; margin-top: 5px; }
/* A note under a field's heading, above its dropdown: the copies wording. The
   field takes the whole row so the note has room and nothing beside it is
   pushed out of line, and the dropdown keeps the width of one column (half the
   row, less half the 22px column gap) so it lines up with the fields above. */
.est-field--wide { grid-column: 1 / -1; }
.est-field--wide select { width: calc(50% - 11px); }
.est-hint { font-size: .77rem; color: #6b6b6b; line-height: 1.45; margin: -2px 0 8px; }
/* The link to Section B of the File Preparation Guidelines. Red on grey text is
   1.4:1, so the colour alone does not mark it as a link; the underline does. */
.est-choice-note a { text-decoration: underline; }

.est-actions { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: 26px; padding-top: 24px; border-top: 1px solid var(--line); }
.est-msg { font-size: .86rem; color: var(--ink-soft); }
.est-msg.is-err { color: #b3261e; }
.est-msg:empty { display: none; }

.est-result { margin-top: 30px; padding-top: 28px; border-top: 1px solid var(--line); }
.est-result-head { font-size: .78rem; font-weight: 600; text-transform: uppercase; letter-spacing: .08em; color: var(--red); margin-bottom: 16px; }
.est-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }
.est-card { background: var(--light); border-radius: var(--radius); padding: 22px 24px; display: flex; flex-direction: column; gap: 3px; }
.est-card-title { font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; color: #5f5f5f; }
.est-total { font-size: 2.3rem; font-weight: 300; color: var(--red); line-height: 1.1; }
/* Open Sans defaults to proportional figures, so a column of prices or opening
   times does not line up digit for digit. */
.est-total, .est-unit, .price-input, .price-result td, .cs-hours li span:last-child { font-variant-numeric: tabular-nums; }
.est-unit { font-size: .92rem; color: var(--ink); font-weight: 600; }
.est-card-note { font-size: .82rem; color: #5f5f5f; }
.est-reprints { font-size: .92rem; color: var(--ink); margin: 16px 0 0; }
.est-reprints strong { color: var(--ink); }
.est-facts { font-size: .84rem; color: #6b6b6b; margin: 10px 0 0; line-height: 1.6; }
.est-cta { margin-top: 26px; padding: 24px 26px; background: var(--charcoal); border-radius: var(--radius); }
.est-cta p { color: #d6d6d6; font-size: .92rem; line-height: 1.6; margin: 0 0 18px; }
.est-cta strong { color: #fff; }
.est-cta .btn-outline { border-color: #7d7d7d; color: #fff; }
.est-cta .btn-outline:hover { background: #fff; color: var(--charcoal); border-color: #fff; }
.est-fallback { max-width: 640px; margin: 0 auto; text-align: center; }
.est-fallback a { color: var(--red); font-weight: 600; }

@media (max-width: 700px) {
  .estimator { padding: 24px 20px 22px; }
  .est-fields { grid-template-columns: minmax(0, 1fr); }
  .est-field--wide select { width: 100%; }
  .est-choices { grid-template-columns: 1fr; }
  .est-total { font-size: 2rem; }
  .est-actions { flex-direction: column; align-items: stretch; }
  .est-actions .btn { width: 100%; }
  .est-cta { padding: 20px; }
}

/* ---------- Dropdown menus -------------------------------------------------- */
.main-nav .has-sub { position: relative; display: inline-flex; align-items: center; }
.main-nav .has-sub > a { padding-right: 4px; }
.sub-caret { background: none; border: 0; cursor: pointer; color: var(--ink); font-size: .7rem; padding: 10px 6px; line-height: 1; }
.sub-menu {
  position: absolute; top: 100%; left: 0; min-width: 250px;
  background: #fff; border: 1px solid var(--line); border-top: 3px solid var(--red);
  box-shadow: var(--shadow); padding: 6px; border-radius: var(--radius);
  display: none; z-index: 60;
}
/* Opening on hover is a nicety for a mouse. On a touchscreen there is no hover,
   so the browser fakes one on the first tap — which is why a hover-only dropdown
   makes the first tap open the menu and the second follow the link, and why the
   faked state sometimes sticks. The caret button (.sub-caret, with aria-expanded)
   is the real control and works everywhere; this rule is enhancement only, so it
   is gated on the pointer actually being able to hover. */
@media (hover: hover) and (pointer: fine) {
  .main-nav .has-sub:hover .sub-menu { display: block; }
}
.main-nav .has-sub.open .sub-menu { display: block; }
.sub-menu a { display: block; padding: 9px 14px; color: var(--ink); font-weight: 600; font-size: .92rem; border-radius: 2px; white-space: nowrap; }
.sub-menu a:hover { background: var(--light); color: var(--red); text-decoration: none; }

/* Tiered tightening so the single-line nav fits every width down to the
   820px mobile breakpoint (items never wrap — see white-space above). */
@media (max-width: 1180px) {
  .main-nav a { font-size: .86rem; padding: 8px 8px; }
  .main-nav a.nav-cta { margin-left: 4px; }
  .sub-caret { padding: 10px 4px; }
}
@media (max-width: 1020px) {
  .logo img { height: 46px; }
  .main-nav { gap: 0; }
  .main-nav a { font-size: .78rem; padding: 8px 6px; }
  .main-nav a.nav-cta { margin-left: 2px; }
  .sub-caret { padding: 10px 3px; font-size: .6rem; }
}

/* ---------- Interior (content) pages --------------------------------------- */
.page-hero--doc { text-align: left; padding: 42px 0 48px; }
.page-hero .breadcrumb { font-size: .85rem; color: rgba(255,255,255,.7); padding: 0 0 14px; }
.page-hero .breadcrumb a { color: rgba(255,255,255,.7); }
.page-hero .breadcrumb a:hover { color: #fff; }
.page-hero .breadcrumb .sep { margin: 0 8px; opacity: .5; }
.page-hero--doc .eyebrow { color: #e79aa0; }
.page-hero--doc h1 { font-size: 2.4rem; }
.page-hero--doc p { color: #d8d8d8; max-width: 720px; margin: 10px 0 0; }
/* Author testimonials on the home page (replaces the old review strip) */
.t-head { max-width: 760px; margin: 0 auto 34px; text-align: center; }
.t-head p { color: var(--ink-soft); font-size: 1.02rem; margin-bottom: 18px; }
.t-mark { display: block; font-family: var(--serif); font-size: 3rem; line-height: .5; color: var(--red); margin-bottom: 14px; }
/* The cards in a row are as tall as the longest quote, so with the author simply
   following the text the three names sat at three different heights. A column
   with the author pushed to the foot brings them down together; padding rather
   than margin keeps the 18px minimum gap under the shortest quote. */
.author-quotes .aq-card { display: flex; flex-direction: column; }
.author-quotes .aq-card .aq-person { margin-top: auto; padding-top: 18px; }
/* That alone still leaves a name 20px low wherever its book title fits on one
   line and its neighbours' wrap to two, because the author blocks are then
   different heights. Where the cards sit in a grid, each one spans two rows of
   it as a subgrid, so the author row is shared and every name starts on the
   same line. Phones keep the column: there the cards are a swipeable row, seen
   one at a time. */
@supports (grid-template-rows: subgrid) {
  @media (min-width: 601px) {
    .author-quotes .aq-card { display: grid; grid-row: span 2; grid-template-rows: subgrid; row-gap: 0; }
    .author-quotes .aq-card .aq-person { margin-top: 0; align-self: start; }
  }
}
.author-quotes .aq-card .aq-role em { font-style: italic; }

/* Photo hero bands get a little more breathing room than the flat ones */
.page-hero[style*="/media/heroes/"] { padding: 64px 0 70px; }
/* Call-to-action in the page hero */
.hero-cta { margin-top: 24px; }
.page-hero--doc .hero-cta { justify-content: flex-start; }
.hero-cta .btn-ghost { border-width: 2px; }

.interior { display: grid; grid-template-columns: 1fr 320px; gap: 50px; align-items: start; }
.prose { color: var(--ink-soft); font-size: 1.02rem; }
.prose .lead-para { font-size: 1.15rem; color: var(--ink); }
.prose h2 { color: var(--ink); font-weight: 300; font-size: 1.6rem; margin: 1.5em 0 .5em; }
.prose h3 { color: var(--red); font-weight: 600; font-size: 1.2rem; margin: 1.4em 0 .4em; }
.prose p { margin: 0 0 1.1em; }
.prose ul { margin: 0 0 1.2em; padding: 0; list-style: none; }
.prose ul li { position: relative; padding: 5px 0 5px 26px; }
.prose ul li::before { content: "\203A"; color: var(--red); font-weight: 700; position: absolute; left: 6px; }
.prose a { font-weight: 600; }
.prose ol { margin: 0 0 1.2em; padding-left: 24px; }
.prose ol li { padding: 5px 0; }
.prose blockquote {
  margin: 1.4em 0; padding: 18px 24px;
  background: var(--light); border-left: 3px solid var(--red);
  font-style: italic; color: var(--ink-soft);
}
.prose blockquote p { margin: 0 0 .6em; }
.prose blockquote footer { font-style: normal; font-size: .88rem; font-weight: 600; color: var(--ink); }
.prose blockquote footer::before { content: "— "; color: var(--red); }
/* A testimonial can link the author's name to their own website (Florent
   Coudyser's does). The client asked for that name to be black like every other
   name on the wall, so it takes the footer's colour; it is still a link, and
   still underlines on hover like every other link on the site. */
.prose blockquote footer a { color: inherit; }
/* Supporting photos in prose: never upscale past their natural size (the
   source images are ~500px wide) and cap the display width so they read as
   tasteful supporting imagery rather than dominating the column. Full width
   on narrow screens. */
.prose .content-img { display: block; width: auto; max-width: min(100%, 420px); height: auto; border-radius: var(--radius); margin: 12px 0 30px; box-shadow: var(--shadow); }
/* Cover pictures three covers across (662px wide). Shown at the same scale as
   the 500px two-across ones are at 420px, so the covers in both come out the
   same size. */
.prose .content-img--wide { max-width: min(100%, 556px); }
/* Testimonials page: masonry-style two-column quote wall */
.quote-wall { column-count: 2; column-gap: 26px; margin: 8px 0 20px; }
.quote-wall blockquote { break-inside: avoid; margin: 0 0 26px; }
/* Copy is full width once the hero stacks, so the horizontal ramp no longer lines
   up with the text — use an even scrim instead. This has to change on the SAME
   breakpoint as the stacking. It sat at 900px while .hero .container stacks at
   960px, so from 901px to 960px the copy spanned the full width while the scrim
   was still the horizontal ramp that fades to .28 on the right: measured 2.20:1
   on the headline and 1.83:1 on the lead, against 10.85:1 at 900px and 6.43:1 at
   961px. contrast-pixels only samples 390px and 1280px, so the band was untested. */
@media (max-width: 960px) {
  .hero::before {
    background: linear-gradient(180deg, rgba(20,12,8,.80) 0%, rgba(20,12,8,.86) 100%);
  }
}
@media (max-width: 900px) {
 .quote-wall { column-count: 1; } }
/* Numbered steps in a sidebar box (Contact page) */
.side-steps { margin: 0; padding-left: 20px; }
.side-steps li { padding: 6px 0; font-size: .9rem; color: var(--ink-soft); line-height: 1.5; }
.side-steps li::marker { color: var(--red); font-weight: 700; }

/* ---------- Interior design components (full-width bands per page) ---------- */
/* Section wrappers — drop into a page's .pre.html / .post.html partials. */
.band { padding: 62px 0; }
.band--light { background: var(--light); }
.band--tint { background: linear-gradient(180deg, #fbf6f6 0%, #fff 100%); }
.band--charcoal { background: var(--charcoal); color: #fff; }
.band--charcoal p { color: #d6d6d6; }
/* The attribution was left at var(--red) on charcoal — 1.51:1, effectively
   unreadable. Same pink the eyebrows use on this background (about 6:1). */
.band--charcoal .pull-quote cite { color: #e79aa0; }
.band-head { text-align: center; max-width: 720px; margin: 0 auto 42px; }
.band-head .eyebrow { color: var(--red); }
.band--charcoal .band-head .eyebrow { color: #e79aa0; }
.band-head h2 { font-size: 2rem; font-weight: 300; color: var(--ink); line-height: 1.15; }
.band--charcoal .band-head h2 { color: #fff; }
.band-head p { color: var(--ink-soft); font-size: 1.05rem; margin: 12px 0 0; }
.band--charcoal .band-head p { color: #d6d6d6; }

/* Feature cards: icon + title + copy */
.feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.feature-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.feature-grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
.feature-card { background: #fff; border: 1px solid var(--line); border-top: 3px solid var(--red); border-radius: var(--radius); padding: 30px 26px; transition: box-shadow .2s ease, transform .2s ease; }
.feature-card:hover { box-shadow: var(--shadow); transform: translateY(-3px); }
.feature-card.center { text-align: center; }
.feature-ico { display: grid; place-items: center; width: 60px; height: 60px; margin-bottom: 16px; border-radius: 50%; background: #fbecec; }
.feature-card.center .feature-ico { margin-left: auto; margin-right: auto; }
.feature-ico svg { width: 28px; height: 28px; fill: var(--red); }
.feature-card h3 { font-size: 1.14rem; font-weight: 700; color: var(--ink); margin-bottom: 8px; }
.feature-card p { font-size: .94rem; color: var(--ink-soft); margin: 0 0 .6em; line-height: 1.6; }
.feature-card p:last-child { margin-bottom: 0; }
.feature-card .learn-more { font-size: .88rem; }
a.feature-card, a.feature-card:hover { text-decoration: none; color: inherit; }

/* Image + text split band */
.split-band { display: grid; grid-template-columns: 1fr 1fr; gap: 50px; align-items: center; }
.split-band .split-media img { width: 100%; height: auto; display: block; border-radius: var(--radius); box-shadow: var(--shadow); }
.split-band--reverse .split-media { order: 2; }
.split-copy .eyebrow { color: var(--red); }
.split-copy h2 { font-size: 1.85rem; font-weight: 300; color: var(--ink); margin-bottom: .45em; line-height: 1.2; }
.split-copy p { color: var(--ink-soft); }
.split-copy ul { margin: 0 0 1.2em; padding: 0; list-style: none; }
.split-copy ul li { position: relative; padding: 5px 0 5px 26px; color: var(--ink-soft); }
.split-copy ul li::before { content: "\203A"; color: var(--red); font-weight: 700; position: absolute; left: 6px; }

/* Stat row (use inside .band--charcoal) */
.stat-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; text-align: center; }
.stat-row .st { padding: 6px 8px; }
.stat-row .st + .st { border-left: 1px solid rgba(255,255,255,.16); }
/* The numbers include single unbreakable words ("International"), so the size is
   fluid: at 320px two columns are only ~135px wide and a fixed 2.1rem overflows
   the viewport. break-word is the backstop for any future longer value. */
.stat-row .st-num {
  display: block; font-size: clamp(1.35rem, 5vw, 2.1rem); font-weight: 700; color: #fff;
  line-height: 1.1; overflow-wrap: break-word;
}
.stat-row .st-label { display: block; margin-top: 8px; font-size: .84rem; letter-spacing: .05em; text-transform: uppercase; color: #c9c9c9; }

/* Big pull-quote */
.pull-quote { max-width: 820px; margin: 0 auto; text-align: center; }
.pull-quote p { font-family: var(--serif); font-size: 1.5rem; line-height: 1.5; color: var(--ink); font-style: italic; }
.band--charcoal .pull-quote p { color: #fff; }
.pull-quote::before { content: "\201C"; display: block; font-family: var(--serif); font-size: 4rem; line-height: .6; color: var(--red); margin-bottom: 8px; }
.pull-quote cite { display: block; margin-top: 16px; font-style: normal; font-weight: 700; font-size: .95rem; color: var(--red); }

/* Full-width CTA band */
.page-cta { background: var(--red); color: #fff; text-align: center; }
.page-cta.charcoal { background: var(--charcoal); }
.page-cta h2 { color: #fff; font-size: 1.9rem; font-weight: 300; margin-bottom: .4em; }
.page-cta p { color: rgba(255,255,255,.9); max-width: 620px; margin: 0 auto 22px; }
.page-cta .hero-actions { justify-content: center; }

/* Numbered process steps */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; counter-reset: step; }
.steps.cols-4 { grid-template-columns: repeat(4, 1fr); }
.step-card { position: relative; padding: 8px 0 0; }
.step-card .step-n { display: grid; place-items: center; width: 46px; height: 46px; border-radius: 50%; background: var(--red); color: #fff; font-weight: 700; font-size: 1.1rem; margin-bottom: 14px; }
.step-card h3 { font-size: 1.08rem; font-weight: 700; color: var(--ink); margin-bottom: 6px; }
.step-card p { font-size: .93rem; color: var(--ink-soft); margin: 0; line-height: 1.6; }

/* Prose callout box */
.prose .callout { background: #fbf3f3; border: 1px solid #f0d9da; border-left: 3px solid var(--red); border-radius: var(--radius); padding: 20px 24px; margin: 1.6em 0; }
.prose .callout p { margin: 0; }
.prose .callout p + p { margin-top: .7em; }
.prose .callout strong { color: var(--ink); }

/* Check list. Every use is inside .split-copy, whose own `ul li::before` (0,1,3)
   outranked `.checks li::before` (0,1,2): the tick took the red text colour on
   its red disc, so it was invisible, and the list rendered as plain red blobs
   butted against the text. The .split-copy selector restores the white tick and
   the 30px indent. top is the first line's half-leading less half the disc, so
   the disc centres on the first line however many lines the item wraps to. */
.prose ul.checks li::before, .split-copy ul.checks li::before, .checks li::before {
  content: "\2713"; color: #fff; background: var(--red); border-radius: 50%;
  width: 18px; height: 18px; font-size: .72rem; line-height: 1;
  display: grid; place-items: center;
  position: absolute; left: 3px; top: calc(5px + .825rem - 9px);
}
.prose ul.checks li, .split-copy ul.checks li, .checks li { position: relative; padding-left: 30px; }

@media (max-width: 900px) {
  .feature-grid, .feature-grid.cols-4, .steps, .steps.cols-4 { grid-template-columns: 1fr 1fr; }
  .split-band { grid-template-columns: 1fr; gap: 28px; }
  .split-band--reverse .split-media { order: 0; }
  .stat-row { grid-template-columns: 1fr 1fr; gap: 26px 10px; }
  .stat-row .st { padding: 6px 4px; min-width: 0; }
  .stat-row .st:nth-child(odd) { border-left: 0; }
}
@media (max-width: 600px) {
  .band { padding: 46px 0; }
  /* .steps.cols-4 by name, as the feature grids are: the two-up rule for it at
     900px is (0,2,0) and a bare .steps here is (0,1,0), so four-step rows stayed
     two across on a phone, in 160px columns that set the copy seven lines deep. */
  .feature-grid, .feature-grid.cols-2, .feature-grid.cols-4, .steps, .steps.cols-4 { grid-template-columns: 1fr; }
  .band-head h2, .page-cta h2, .split-copy h2 { font-size: 1.6rem; }
  .pull-quote p { font-size: 1.25rem; }
}

/* ---------- Contact page --------------------------------------------------- */
.contact-methods { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-bottom: 40px; }
.contact-method {
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
  background: #fff; border: 1px solid var(--line); border-top: 3px solid var(--red);
  border-radius: var(--radius); padding: 24px 22px; text-decoration: none; color: var(--ink);
  transition: box-shadow .2s ease, transform .2s ease;
}
.contact-method:hover { box-shadow: var(--shadow); transform: translateY(-3px); text-decoration: none; }
.cm-icon { display: grid; place-items: center; width: 46px; height: 46px; border-radius: 50%; background: var(--light); margin-bottom: 8px; }
.cm-icon svg { width: 22px; height: 22px; fill: var(--red); }
.cm-label { font-size: .74rem; font-weight: 700; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-mute); }
.cm-value { font-size: 1.05rem; font-weight: 700; color: var(--ink); line-height: 1.3; word-break: break-word; }
.cm-note { font-size: .85rem; color: var(--red); font-weight: 600; margin-top: 2px; }

.contact-grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 34px; align-items: start; }
.contact-form-card { margin: 0; padding: 30px 30px 34px; border-top: 3px solid var(--red); }
.contact-form-card h2 { font-size: 1.5rem; color: var(--ink); margin-bottom: 6px; }
.contact-form-sub { font-size: .95rem; color: var(--ink-soft); margin-bottom: 20px; }
.contact-side { display: flex; flex-direction: column; gap: 20px; }
.cs-box { background: var(--light); border-radius: var(--radius); padding: 22px 24px; }
.cs-box h3 { font-size: 1.05rem; font-weight: 700; color: var(--red); margin-bottom: 12px; }
.cs-hours { list-style: none; margin: 0 0 12px; padding: 0; }
.cs-hours li { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--line); font-size: .92rem; }
.cs-hours li span:first-child { color: var(--ink-soft); }
.cs-hours li span:last-child { font-weight: 600; color: var(--ink); }
.cs-note { font-size: .88rem; color: var(--ink-soft); margin: 0; line-height: 1.55; }

.contact-map { margin-top: 40px; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--line); background: var(--light); }
.contact-map iframe { display: block; width: 100%; height: 360px; border: 0; }

@media (max-width: 820px) {
  .contact-methods { grid-template-columns: 1fr; gap: 14px; }
  .contact-grid { grid-template-columns: 1fr; gap: 26px; }
  .contact-map iframe { height: 300px; }
}

/* ---------- Sticky mobile action bar --------------------------------------- */
.mobile-cta { display: none; }
@media (max-width: 640px) {
  .mobile-cta {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
    box-shadow: 0 -2px 14px rgba(0,0,0,.18);
    padding-bottom: env(safe-area-inset-bottom);   /* clear iOS home indicator */
  }
  /* Nothing reserved the space the bar occupies, so the last few links in the
     footer sat underneath it and could not be tapped at all. The inset term
     matters: .mobile-cta adds env(safe-area-inset-bottom) on top of its 54px
     rows, so on a phone with a home indicator the bar is taller than 54px. A
     second, flat `body { padding-bottom: 54px }` further down this same block
     used to win on source order and throw the inset away, which put the footer
     links back under the bar on exactly those phones. */
  body { padding-bottom: calc(54px + env(safe-area-inset-bottom)); }
  .mcta {
    flex: 1; display: flex; align-items: center; justify-content: center; gap: 8px;
    min-height: 54px; padding: 8px; font-weight: 700; font-size: .98rem;
    text-decoration: none; letter-spacing: .01em;
  }
  .mcta:hover { text-decoration: none; }
  .mcta svg { width: 18px; height: 18px; fill: currentColor; }
  .mcta-call { background: var(--charcoal); color: #fff; }
  .mcta-quote { background: var(--red); color: #fff; }
}

.card-links { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; margin: 6px 0 1.2em; }
.card-link { border: 1px solid var(--line); border-top: 3px solid var(--red); border-radius: var(--radius); padding: 20px; display: block; }
.card-link:hover { text-decoration: none; box-shadow: var(--shadow); }
.card-link strong { display: block; color: var(--ink); font-size: 1.05rem; margin-bottom: 4px; }
.card-link span { color: var(--ink-soft); font-size: .9rem; }

.side { position: sticky; top: 100px; display: grid; gap: 20px; }
.side-cta { background: var(--charcoal); color: #fff; border-top: 3px solid var(--red); padding: 26px 24px; }
.side-cta h3 { color: #fff; font-weight: 400; font-size: 1.25rem; margin-bottom: 8px; }
.side-cta p { color: #cfcfcf; font-size: .92rem; margin-bottom: 16px; }
.side-nav { border: 1px solid var(--line); padding: 6px 20px 14px; }
/* h2, not h4: the accessibility pass lifted the markup to h2 so the outline does
   not skip two levels, and this rule was left behind on h4. The headings fell
   back to the full 2.1rem h2 size, so "Self-Publishing a Book" ran to two
   oversized lines above a list of small links. */
.side-nav h2 { text-transform: uppercase; letter-spacing: .08em; font-size: .76rem; color: var(--ink-soft); margin: 16px 0 6px; font-weight: 700; line-height: 1.4; }
.side-nav a { display: block; padding: 8px 0; color: var(--ink); font-weight: 600; font-size: .92rem; border-bottom: 1px solid var(--line); }
.side-nav a:last-child { border-bottom: 0; }
.side-nav a:hover { color: var(--red); text-decoration: none; }
.side-nav a.current { color: var(--red); }

/* ---------- Responsive ----------------------------------------------------- */
@media (max-width: 960px) {
  .hero .container { grid-template-columns: 1fr; gap: 34px; }
  .hero-arrow { top: 28%; }               /* sit over the image, clear of the form below */
  .hero-copy { text-align: center; }
  .hero-copy .lead { max-width: none; }
  .hero-trust, .hero-actions, .hero-controls { justify-content: center; }
  .split { grid-template-columns: minmax(0, 1fr); }   /* let the single column shrink below child min-content */
  .footer-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 820px) {
  .nav-toggle { display: block; }
  .main-nav {
    position: absolute; top: 100%; left: 0; right: 0; background: #fff;
    flex-direction: column; align-items: stretch; gap: 0; padding: 8px 16px 16px;
    border-bottom: 1px solid var(--line); box-shadow: var(--shadow);
    display: none;
  }
  .main-nav.open { display: flex; }
  /* The panel is absolutely positioned inside a sticky header, so it does not
     scroll with the page — and with no height bound of its own an open submenu
     made it 700-750px tall, taller than a 667px viewport. "More" and the Get a
     Quote link were simply unreachable: off the bottom of the screen with nothing
     to scroll. Bound it to the space between the header and the fixed bottom bar
     and let the panel itself scroll. Desktop is unaffected — the nav is not
     absolutely positioned there. */
  .main-nav { max-height: calc(100vh - 84px - 54px); overflow-y: auto; overscroll-behavior: contain; }
  .main-nav a { padding: 13px 8px; font-size: .95rem; border-radius: 0; border-bottom: 1px solid var(--line); white-space: normal; }
  .main-nav a.active { border-bottom: 1px solid var(--line); text-decoration: none; color: var(--red); }
  .main-nav .nav-cta { margin: 12px 0 0; font-size: .95rem; }
  /* Dropdowns become inline expanders on mobile */
  .main-nav .has-sub { display: block; position: static; border-bottom: 1px solid var(--line); }
  .main-nav .has-sub > a { flex: 1; border-bottom: 0; }
  .main-nav .has-sub { display: flex; flex-wrap: wrap; align-items: center; }
  .sub-caret { margin-left: auto; font-size: 1rem; padding: 13px 10px; }
  .sub-menu { position: static; display: none; box-shadow: none; border: 0; border-top: 0; padding: 0 0 8px 14px; min-width: 0; width: 100%; }
  .main-nav .has-sub.open .sub-menu { display: block; }
  .sub-menu a { padding: 11px 8px; border-bottom: 1px solid var(--line); font-weight: 400; }
  .service-grid { grid-template-columns: 1fr; gap: 44px; }
  .aq-grid { grid-template-columns: 1fr 1fr; }
  .hero-copy h1 { font-size: 2.3rem; }
}
@media (max-width: 600px) {
  .hero-arrow { display: none; }          /* phones: use the dots instead (arrows would cover the form) */

  /* Tighter vertical rhythm */
  .container { padding: 0 18px; }
  .section, .services, .author-quotes, .testimonial-band, .cta-banner { padding: 46px 0; }
  .about-band { padding: 58px 0; }
  .page-hero { padding: 46px 0; }
  .site-footer { padding-top: 46px; }
  .hero .container { padding-top: 38px; padding-bottom: 46px; }

  /* Typographic scale */
  h2, .section-red-title, .sec-title { font-size: 1.65rem; }
  .stats-band .container { grid-template-columns: 1fr 1fr; gap: 26px 6px; padding: 34px 18px; }
  .stats-band .stat + .stat { border-left: 0; }
  /* Reserve two lines for the heading so slides with a shorter title don't
     change height and shift the page as the carousel advances. */
  .hero-copy h1 { font-size: 1.9rem; min-height: 2.4em; }
  .hero-copy .lead { font-size: 1.02rem; }
  .cta-banner h2, .about-band h2, .page-hero h1 { font-size: 1.7rem; }
  .testimonial-band h2 { letter-spacing: .18em; font-size: 1.4rem; text-indent: .18em; }

  /* Hero */
  .hero-trust { flex-direction: column; gap: 5px; }
  .hero-actions { flex-direction: column; align-items: stretch; width: 100%; }
  .hero-actions .btn { width: 100%; }
  .lead-card { padding: 24px 20px 20px; }
  .lead-card .grid-2 { grid-template-columns: 1fr !important; }

  /* Compact, centred top utility bar. The font-size, container padding/gap and
     tb-item gap used to be repeated here as well as in the compaction block near
     the top of the file. Same media condition, same selectors, same specificity —
     so these later copies quietly won and the bar rendered 42px tall with 9px
     padding instead of the 34px/2px it was rewritten to use. Only the rules that
     are not declared up there belong in this block. */
  .topbar .container { text-align: center; }
  .topbar .tb-spacer, .topbar .tb-cta { display: none; }

  /* Smaller icons + shorter placeholders */
  .service-icon { width: 76px; height: 76px; }
  .cost-media { min-height: 190px; }

  /* Google reviews: one compact swipeable row instead of a tall stack */
  .aq-grid {
    display: flex; grid-template-columns: none; gap: 14px;
    overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
    margin: 0 -18px; padding: 4px 18px 12px; scrollbar-width: none;
  }
  .aq-grid::-webkit-scrollbar { display: none; }
  .aq-card { flex: 0 0 84%; scroll-snap-align: center; padding: 18px; }
  .aq-card p { font-size: .92rem; line-height: 1.5; }
  .aq-card .aq-stars { font-size: .95rem; letter-spacing: 1px; margin-bottom: 8px; }
  .aq-avatar { width: 40px; height: 40px; flex-basis: 40px; }
  .g-head { gap: 12px; margin-bottom: 22px; }
  .g-head .g-score .num { font-size: 2rem; }
  .book-collage { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
}
@media (max-width: 900px) {
  .interior { grid-template-columns: 1fr; gap: 34px; }
  .side { position: static; }
  .card-links { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .footer-grid { grid-template-columns: 1fr; }
  .grid-2 { grid-template-columns: 1fr; }
  .page-hero--doc h1 { font-size: 1.9rem; }
}
