@charset "utf-8";

/* ==========================================================================
   Hine Eagle Barristers & Solicitors
   Design system. Mobile first. One stylesheet, no build step.

   Brand carried over from the existing site:
     black #000 · white #fff · red #c00
     Open Sans · uppercase nav · rule beneath section headings
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Brand: black, white, red.
     Taken from what the existing stylesheet actually uses #c00 appears 36
     times and var(--red) another 24. The --gold variable it declares is
     referenced zero times, so it is not part of the brand. */
  --ink: #000;
  --ink-80: #1a1a1a;
  --ink-60: #3d3d3d;

  --accent: #c00;
  --accent-hover: #a30000;

  /* #c00 is only 2.5:1 against black, so it is unreadable in the header,
     footer and dark bands. This lighter step is the one used there. */
  --accent-on-dark: #ff4d4d;

  --accent-ring: rgb(204 0 0 / 28%);

  /* Surfaces */
  --paper: #fff;
  --paper-2: #f7f6f3;
  --paper-3: #eeece6;
  --line: #dedbd3;
  --line-dark: #2a2a2a;

  /* Text */
  --text: #1a1a1a;
  --text-muted: #55534e;
  --text-invert: #fff;
  --text-invert-muted: #c9c6be;

  /* Type. Open Sans, matching the previous site.
     Body copy is 300 (light) as it was there. Only three real faces are
     loaded, 300 for body, 600 for UI labels, 700 for headings, so nothing
     relies on the browser synthesising a bold. */
  --font-sans: "Open Sans", "Segoe UI", system-ui, -apple-system, Roboto,
    "Helvetica Neue", Arial, sans-serif;

  --step--1: clamp(0.82rem, 0.79rem + 0.14vw, 0.9rem);
  --step-0: clamp(1rem, 0.96rem + 0.19vw, 1.11rem);
  --step-1: clamp(1.16rem, 1.09rem + 0.35vw, 1.38rem);
  --step-2: clamp(1.36rem, 1.24rem + 0.6vw, 1.73rem);
  --step-3: clamp(1.6rem, 1.39rem + 1vw, 2.16rem);
  --step-4: clamp(1.88rem, 1.55rem + 1.6vw, 2.7rem);
  --step-5: clamp(2.2rem, 1.68rem + 2.5vw, 3.38rem);

  /* Space */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;
  --sp-9: 6rem;

  /* Layout */
  --container: 1180px;
  --container-narrow: 760px;
  --gutter: clamp(1.15rem, 4vw, 2.5rem);
  --header-h: 82px;

  /* Effects */
  --radius: 2px;
  --radius-lg: 4px;
  /* Softer corners, used where an image is the main content. */
  --radius-xl: 14px;
  --shadow-1: 0 1px 2px rgb(0 0 0 / 6%), 0 4px 12px rgb(0 0 0 / 6%);
  --shadow-2: 0 2px 4px rgb(0 0 0 / 8%), 0 12px 32px rgb(0 0 0 / 10%);
  --ease: cubic-bezier(0.2, 0.6, 0.25, 1);
  --dur: 220ms;
}

@media (min-width: 900px) {
  :root {
    --header-h: 102px;
  }
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  font-weight: 300;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;

  /* `clip` rather than `hidden`: the closed mobile drawer is position:fixed and
     translated fully off-screen, and `hidden` does not reliably clip fixed
     descendants, it left 5px of horizontal scroll on phones. `clip` also
     avoids making the body a scroll container, which would break the sticky
     header. The `hidden` line is the fallback for older engines. */
  overflow-x: hidden;
  overflow-x: clip;
}

h1,
h2,
h3,
h4,
p,
figure,
blockquote,
ul,
ol,
dl {
  margin: 0;
}

/* :where() keeps this at zero specificity. Written as `ul[class]` it scores
   (0,1,1) and silently beats any single-class component rule that tries to set
   its own padding, which is a very hard bug to spot. */
:where(ul[class], ol[class]) {
  list-style: none;
  padding: 0;
}

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

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

button {
  cursor: pointer;
}

a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

:target {
  scroll-margin-top: calc(var(--header-h) + 1rem);
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* --------------------------------------------------------------------------
   3. Typography
   -------------------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

h1 {
  font-size: var(--step-5);
}

h2 {
  font-size: var(--step-4);
}

h3 {
  font-size: var(--step-2);
}

h4 {
  font-size: var(--step-1);
}

p {
  text-wrap: pretty;
}

.lede {
  font-size: var(--step-1);
  font-weight: 300;
  line-height: 1.55;
  color: var(--text-muted);
}

.eyebrow {
  display: block;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--sp-3);
}

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

/* The signature motif: a short heavy rule beneath a heading. */
.rule {
  display: block;
  width: 140px;
  max-width: 60%;
  height: 3px;
  border-radius: 2px;
  background: var(--ink);
  margin-top: var(--sp-4);
}

.rule--accent {
  background: var(--accent);
}

/* On black, red drops to 2.5:1. White carries the motif instead. */
.rule--invert {
  background: #fff;
}

@media (min-width: 900px) {
  .rule {
    width: 260px;
  }
}

.rule--center {
  margin-inline: auto;
}

/* --------------------------------------------------------------------------
   4. Layout
   -------------------------------------------------------------------------- */

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

/* Reading width without losing the page spine. The box stays the full
   container so headings line up with every other section; the children are
   what get capped. Narrowing the container itself centres the whole block and
   leaves it aligned to nothing. */
.container--narrow > * {
  max-width: var(--container-narrow);
}

/* Full viewport width less the gutters. For grids of images, where the 1180px
   reading measure is an unnecessary constraint. */
.container--wide {
  max-width: none;
}

.section {
  padding-block: clamp(3rem, 8vw, 6rem);
}

.section--tight {
  padding-block: clamp(2rem, 5vw, 3.5rem);
}

.section--paper2 {
  background: var(--paper-2);
}

/* Oversized brand mark bled off the right edge, as a watermark. White on the
   #f7f6f3 surface is about a 3% luminance step, present enough to read as
   texture, nowhere near enough to fight the text over it.

   The mark is a vector, so it stays clean at this size, and it is drawn on a
   ::before rather than as a background on the section itself so the clipping
   and the stacking order stay independent of the surface colour. */
.section--watermark {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.section--watermark::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  /* The bleed is on the box, not on background-position. A percentage in
     background-position resolves against (container - image), so as soon as
     the mark is wider than the section the sign flips and it drifts off the
     LEFT edge instead. Offsetting the box and anchoring the mark to its right
     keeps the overhang identical at every viewport width. */
  right: -7%;
  background-image: url("/images/logo-mark-white.svg");
  background-repeat: no-repeat;
  background-position: right center;
  background-size: auto 145%;
  pointer-events: none;
  z-index: -1;
}

/* Scaled to viewport width rather than section height on narrow screens: the
   testimonials section grows tall on mobile, so a height-based mark would end
   up wider than the phone and swamp the quotation. */
@media (max-width: 700px) {
  .section--watermark::before {
    right: -20%;
    background-size: 150% auto;
    opacity: 0.55;
  }
}

/* A watermark is decoration; it should not cost ink. */
@media print {
  .section--watermark::before {
    display: none;
  }
}

.section--ink {
  background: var(--ink);
  color: var(--text-invert);
}

.section--ink .lede,
.section--ink .section-sub {
  color: var(--text-invert-muted);
}

.section-head {
  max-width: 46rem;
  margin-bottom: clamp(2rem, 5vw, 3.25rem);
}

.section-head--center {
  margin-inline: auto;
  text-align: center;
}

/* #c00 is 5.9:1 on white and 5.6:1 on the off-white band, so it clears AA for
   headings at any size. */
.section-head--accent :where(h1, h2, h3) {
  color: var(--accent);
}

/* Alternating left/right section headings, as the previous site did down the
   home page. Left-aligned below 900px, right-aligned body text is awkward to
   read on a narrow column. */
@media (min-width: 900px) {
  .section-head--right {
    margin-left: auto;
    text-align: right;
  }

  .section-head--right .rule {
    margin-left: auto;
  }
}

.section-sub {
  margin-top: var(--sp-5);
  color: var(--text-muted);
  font-size: var(--step-1);
  font-weight: 300;
}

.stack > * + * {
  margin-top: var(--sp-4);
}

.stack-lg > * + * {
  margin-top: var(--sp-6);
}

.grid {
  display: grid;
  gap: clamp(1rem, 2.5vw, 1.75rem);
}

@media (min-width: 640px) {
  .grid--2 {
    grid-template-columns: repeat(2, 1fr);
  }

  .grid--3 {
    grid-template-columns: repeat(2, 1fr);
  }

  .grid--4 {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 980px) {
  .grid--3 {
    grid-template-columns: repeat(3, 1fr);
  }

  .grid--4 {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Top-aligned, not centred. Centring two columns of unequal height leaves the
   shorter one floating with dead space above and below it. */
.split {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}

@media (min-width: 900px) {
  .split {
    grid-template-columns: 1.05fr 0.95fr;
  }

  .split--reverse > :first-child {
    order: 2;
  }

  /* Media stretches to the height of the text beside it. Without this a fixed
     aspect ratio leaves a slab of dead space under the shorter column. */
  .split--fill {
    align-items: stretch;
  }

  .split--fill .media {
    height: 100%;
    aspect-ratio: auto;
  }
}

/* --------------------------------------------------------------------------
   5. Accessibility helpers
   -------------------------------------------------------------------------- */

.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: var(--sp-4);
  z-index: 200;
  transform: translateY(-200%);
  background: var(--accent);
  color: #fff;
  font-weight: 600;
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius);
  transition: transform var(--dur) var(--ease);
}

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

:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius);
}

.section--ink :where(a, button):focus-visible,
.site-header :where(a, button):focus-visible,
.mobile-nav :where(a, button):focus-visible,
.site-footer :where(a, button):focus-visible,
.hero :where(a, button):focus-visible,
.page-hero :where(a, button):focus-visible,
.cta-band :where(a, button):focus-visible {
  outline-color: #fff;
}

/* --------------------------------------------------------------------------
   6. Buttons
   -------------------------------------------------------------------------- */

.btn {
  --btn-bg: var(--ink);
  --btn-fg: #fff;
  --btn-bd: var(--ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  min-height: 48px;
  padding: 0.75rem 1.6rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 2px solid var(--btn-bd);
  border-radius: var(--radius);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
    border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}

.btn:hover {
  transform: translateY(-2px);
}

.btn:active {
  transform: translateY(0);
}

/* White on #c00 is 6.7:1. Black on #c00 is only 3.1:1, so text stays white. */
.btn--accent {
  --btn-bg: var(--accent);
  --btn-fg: #fff;
  --btn-bd: var(--accent);
}

.btn--accent:hover {
  --btn-bg: var(--accent-hover);
  --btn-bd: var(--accent-hover);
}

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  --btn-bd: var(--ink);
}

.btn--ghost:hover {
  --btn-bg: var(--ink);
  --btn-fg: #fff;
}

.btn--ghost-invert {
  --btn-bg: transparent;
  --btn-fg: #fff;
  --btn-bd: rgb(255 255 255 / 65%);
}

.btn--ghost-invert:hover {
  --btn-bg: #fff;
  --btn-fg: var(--ink);
  --btn-bd: #fff;
}

.btn--block {
  width: 100%;
}

.btn .icon {
  width: 1.05em;
  height: 1.05em;
  flex: none;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
}

/* Text link with an animated underline. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-weight: 600;
  font-size: var(--step--1);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  padding-bottom: 2px;
  background-image: linear-gradient(var(--accent), var(--accent));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 2px;
  transition: background-size var(--dur) var(--ease), color var(--dur) var(--ease);
}

.link-arrow:hover {
  color: var(--accent);
  background-size: 100% 2px;
}

.link-arrow .icon {
  width: 0.9em;
  height: 0.9em;
  transition: transform var(--dur) var(--ease);
}

.link-arrow:hover .icon {
  transform: translateX(4px);
}

/* --------------------------------------------------------------------------
   7. Header and navigation
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--ink);
  color: #fff;
  border-bottom: 1px solid var(--line-dark);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  min-height: var(--header-h);
}

.brand {
  display: inline-flex;
  align-items: center;
  flex: none;
  padding-block: var(--sp-3);
}

/* The logo file has almost no transparent margin (2.4% of its area), so there
   is nothing to crop, size is the only lever. The header grows with it to
   keep the breathing room either side.

   The mark is a single master SVG whose blacks are currentColor, so `color`
   below is what paints it white here; the same file renders black wherever it
   sits on a light surface. aspect-ratio is stated explicitly rather than left
   to the viewBox, so the width is reserved before the SVG is parsed and the
   nav cannot shift sideways on load. */
.brand__logo {
  display: block;
  width: auto;
  height: 54px;
  aspect-ratio: 1209.327 / 277.588;
  color: #fff;

  /* Ring weight, in viewBox units. The artwork draws the ring at 2, which is
     only about 0.55px once the logo is 76px tall, too fine to read as motion
     while it draws. It is drawn heavier, then settles back to the artwork's
     own weight. Tune here rather than in the keyframes. */
  --ring-w-draw: 6;
  --ring-w-rest: 2;
}

@media (min-width: 900px) {
  .brand__logo {
    height: 76px;
  }
}

/* --- Logo intro ---------------------------------------------------------
   Mirrors the After Effects build: the ring draws, the eagle settles in, the
   wordmark rises, then the strapline fades up. Roughly 2s end to end.

   Everything is scoped under .logo-intro, a class added in <head> on the home
   page only. No class means no hidden state at all, so a visitor with
   JavaScript off, or a crawler, gets the finished logo, and interior pages
   never rebuild it while someone is reading through them.

   Note that transform lengths inside an SVG resolve in user units, not CSS
   pixels: the 10px rise below is 10 of 277 viewBox units, about 2.7px on
   screen at header size. That is what makes it a nudge rather than a lurch. */
.logo-intro .brand__logo #Red_Ring circle {
  /* pathLength="1" is set in the SVG, so the dash array is 1 whole path
     regardless of the circle's real circumference. */
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transform-box: fill-box;
  transform-origin: center;
  /* SVG circles start at 3 o'clock; this starts the draw at 12. */
  transform: rotate(-90deg);
  /* Two animations rather than extra stops on one. A stop at 73% would become
     an interval boundary for every property in the keyframe, re-applying
     ease-in-out either side of it and visibly distorting the draw. Separate
     animations keep the draw's easing intact. */
  animation:
    he-logo-ring 1.1s ease-in-out forwards,
    he-logo-ring-weight 2s ease-out forwards;
}

.logo-intro .brand__logo #Black_Part_of_Picture_Logo,
.logo-intro .brand__logo #HINE_EAGLE,
.logo-intro .brand__logo #Red_Circle,
.logo-intro .brand__logo #barristers_and_solicitors {
  opacity: 0;
}

.logo-intro .brand__logo #Black_Part_of_Picture_Logo {
  transform-box: fill-box;
  transform-origin: center;
  animation: he-logo-eagle 0.55s ease-out 1.1s forwards;
}

.logo-intro .brand__logo #HINE_EAGLE,
.logo-intro .brand__logo #Red_Circle {
  transform-box: fill-box;
  animation: he-logo-rise 0.55s ease-out 1.25s forwards;
}

.logo-intro .brand__logo #barristers_and_solicitors {
  animation: he-logo-fade 0.5s ease-out 1.5s forwards;
}

@keyframes he-logo-ring {
  to { stroke-dashoffset: 0; }
}

/* Holds the heavier weight through the draw and while the wordmark rises,
   then eases down to the artwork weight over the last 500ms. 2s matches the
   strapline's finish, so the ring settling is the last thing that happens and
   the whole logo resolves together rather than in two separate beats. */
@keyframes he-logo-ring-weight {
  0%, 75% { stroke-width: var(--ring-w-draw); }
  100%    { stroke-width: var(--ring-w-rest); }
}

@keyframes he-logo-eagle {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes he-logo-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes he-logo-fade {
  to { opacity: 1; }
}

/* The head script already declines to add .logo-intro under reduced motion.
   This is the backstop for anyone who changes the setting mid-session. */
@media (prefers-reduced-motion: reduce) {
  .logo-intro .brand__logo #Red_Ring circle,
  .logo-intro .brand__logo #Black_Part_of_Picture_Logo,
  .logo-intro .brand__logo #HINE_EAGLE,
  .logo-intro .brand__logo #Red_Circle,
  .logo-intro .brand__logo #barristers_and_solicitors {
    animation: none;
    opacity: 1;
    transform: none;
    stroke-dashoffset: 0;
  }
}

/* Printing a half-drawn logo would be bad. */
@media print {
  .brand__logo :is(#Red_Ring circle, #Black_Part_of_Picture_Logo, #HINE_EAGLE, #Red_Circle, #barristers_and_solicitors) {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
    stroke-dashoffset: 0 !important;
  }
}

/* Desktop nav */
.nav {
  display: none;
}

.nav__list {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 1.9rem);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav__link {
  display: inline-block;
  padding: var(--sp-2) 0;
  font-size: 0.95rem;
  font-weight: 300;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: #fff;
  border-bottom: 2px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.nav__link:hover {
  color: var(--accent-on-dark);
  border-bottom-color: var(--accent-on-dark);
}

.nav__link[aria-current="page"] {
  color: var(--accent-on-dark);
  border-bottom-color: var(--accent-on-dark);
}

@media (min-width: 1080px) {
  .nav {
    display: flex;
    /* Pushes the links hard right against the gutter, with the logo alone
       on the left. */
    margin-left: auto;
  }
}

/* Hamburger */
.nav-toggle {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  width: 48px;
  height: 48px;
  padding: 0 11px;
  background: none;
  border: 0;
  flex: none;
}

.nav-toggle__bar {
  display: block;
  width: 26px;
  height: 2px;
  background: #fff;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease),
    background var(--dur) var(--ease);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar {
  background: var(--accent-on-dark);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) {
  transform: translateY(8px) rotate(45deg);
}

/* Collapsed to nothing, not merely transparent. The bar is 26px wide but the
   rotated X spans only 20px, so at opacity 0 it still occupies 3px either side
   of the cross, and iOS Safari paints a sliver of it, which reads as a stray
   dash beside the X. scaleX(0) leaves no area to paint at all. */
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) {
  opacity: 0;
  transform: scaleX(0);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) {
  transform: translateY(-8px) rotate(-45deg);
}

@media (min-width: 1080px) {
  .nav-toggle {
    display: none;
  }
}

.mobile-nav__shielded {
  display: flex;
  justify-content: center;
  margin-top: var(--sp-6);
}

.mobile-nav__shielded img {
  width: 34px;
  height: 34px;
}

/* Mobile drawer */
.mobile-nav {
  position: fixed;
  inset: var(--header-h) 0 0;
  z-index: 99;
  background: var(--ink);
  color: #fff;
  padding: var(--sp-6) 0 var(--sp-8);
  overflow-y: auto;
  overscroll-behavior: contain;
  transform: translateX(100%);
  visibility: hidden;
  transition: transform var(--dur) var(--ease), visibility var(--dur);
}

.mobile-nav[data-open="true"] {
  transform: translateX(0);
  visibility: visible;
}

@media (min-width: 1080px) {
  .mobile-nav {
    display: none;
  }
}

.mobile-nav__list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line-dark);
}

.mobile-nav__list a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: 60px;
  padding: var(--sp-4) 0;
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: #fff;
  border-bottom: 1px solid var(--line-dark);
}

.mobile-nav__list a[aria-current="page"] {
  color: var(--accent-on-dark);
}

.mobile-nav__list a .icon {
  width: 1em;
  height: 1em;
  color: var(--text-invert-muted);
}

.mobile-nav__cta {
  margin-top: var(--sp-6);
  display: grid;
  gap: var(--sp-4);
}

.mobile-nav__contact {
  margin-top: var(--sp-7);
  color: var(--text-invert-muted);
  font-size: var(--step--1);
  line-height: 1.9;
}

.mobile-nav__contact a {
  color: var(--accent-on-dark);
}

body[data-nav-open="true"] {
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   8. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  display: grid;
  align-items: center;
  min-height: clamp(30rem, 72vh, 44rem);
  background: var(--ink);
  color: #fff;
  overflow: hidden;
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 42%;
}

.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
      100deg,
      rgb(0 0 0 / 88%) 0%,
      rgb(0 0 0 / 72%) 45%,
      rgb(0 0 0 / 42%) 100%
    ),
    linear-gradient(to top, rgb(0 0 0 / 55%), transparent 45%);
}

/* The container keeps the page's normal 1180px spine so the hero starts on the
   same left edge as every section below it. Capping the children rather than
   the container is what keeps the lines readable without centring the block. */
.hero__inner {
  position: relative;
  z-index: 1;
  padding-block: clamp(3.5rem, 10vw, 6rem);
}

.hero__inner > * {
  max-width: 46rem;
}

/* Entrance.
   Each element rises in on load, staggered. `backwards` fill applies the start
   state only during the delay, so the end state is the normal one, if
   animations never run, nothing is hidden. Deliberately a load-in rather than
   a scroll reveal: scroll reveals leave off-screen content at opacity 0, which
   is what made whole sections vanish from screenshots and print earlier. */
@media (prefers-reduced-motion: no-preference) {
  .hero__inner > *,
  .page-hero__inner > * {
    animation: rise-in 620ms var(--ease) backwards;
  }

  .hero__inner > *:nth-child(1),
  .page-hero__inner > *:nth-child(1) {
    animation-delay: 40ms;
  }

  .hero__inner > *:nth-child(2),
  .page-hero__inner > *:nth-child(2) {
    animation-delay: 120ms;
  }

  .hero__inner > *:nth-child(3),
  .page-hero__inner > *:nth-child(3) {
    animation-delay: 190ms;
  }

  .hero__inner > *:nth-child(4),
  .page-hero__inner > *:nth-child(4) {
    animation-delay: 250ms;
  }

  .hero__inner > *:nth-child(5),
  .page-hero__inner > *:nth-child(5) {
    animation-delay: 310ms;
  }
}

/* --------------------------------------------------------------------------
   Scroll reveals

   The hidden state is scoped to .reveal-on-scroll, which the script adds to
   <html> only once it knows it has an IntersectionObserver and that motion is
   allowed. So if the script never runs, is blocked, or errors, nothing is ever
   hidden, that was the failure mode that made whole sections vanish before.
   Print always forces everything visible.
   -------------------------------------------------------------------------- */

.reveal-on-scroll [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
}

.reveal-on-scroll [data-reveal].is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 620ms var(--ease), transform 620ms var(--ease);
}

/* Second element in a section trails the first slightly. */
.reveal-on-scroll [data-reveal="late"].is-visible {
  transition-delay: 130ms;
}

@media print {
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
}

@keyframes rise-in {
  from {
    opacity: 0;
    transform: translateY(14px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@media print {
  .hero__inner > *,
  .page-hero__inner > *,
  .profile__aside > *,
  .profile > * {
    animation: none;
  }
}

.hero h1 {
  font-weight: 300;
  letter-spacing: -0.02em;
}

.hero h1 strong {
  font-weight: 700;
}

.hero__text {
  margin-top: var(--sp-5);
  font-size: var(--step-1);
  font-weight: 300;
  line-height: 1.6;
  color: #e8e6e0;
  max-width: 40rem;
}

.hero .btn-row {
  margin-top: var(--sp-6);
}

/* Compact hero for interior pages */
/* Tighter than it was: at clamp(2.5rem, 7vw, 4.5rem) the practice pages ran to
   539px of near-empty black before any content started. */
.page-hero {
  position: relative;
  background: var(--ink);
  color: #fff;
  padding-block: clamp(1.75rem, 3.5vw, 2.75rem) clamp(2.25rem, 4.5vw, 3.25rem);
  overflow: hidden;
}

.page-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(
    120% 140% at 88% 0%,
    rgb(204 0 0 / 12%),
    transparent 62%
  );
}

/* Same treatment as the home hero: full container width, capped children. */
.page-hero__inner {
  position: relative;
}

.page-hero__inner > * {
  max-width: 48rem;
}

.page-hero h1 {
  font-size: var(--step-5);
  font-weight: 300;
}

.page-hero h1 strong {
  font-weight: 700;
}

.page-hero__text {
  margin-top: var(--sp-5);
  font-size: var(--step-1);
  font-weight: 300;
  color: var(--text-invert-muted);
  max-width: 42rem;
}

/* --------------------------------------------------------------------------
   9. Breadcrumbs
   -------------------------------------------------------------------------- */

/* Dark, so the nav, the breadcrumb and the page header read as one block.
   A pale strip between two black bands chopped the top of the page into
   three and was the main reason it looked disjointed. */
.breadcrumbs {
  padding-block: var(--sp-4) 0;
  background: var(--ink);
  color: var(--text-invert-muted);
  font-size: var(--step--1);
}

.breadcrumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
  color: #8f8b82;
}

.breadcrumbs li {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.breadcrumbs li + li::before {
  content: "/";
  color: #5a5750;
}

.breadcrumbs a {
  color: #8f8b82;
  text-decoration: none;
}

.breadcrumbs a:hover {
  color: #fff;
  text-decoration: underline;
}

.breadcrumbs [aria-current="page"] {
  color: #fff;
}

/* --------------------------------------------------------------------------
   10. Trust strip
   -------------------------------------------------------------------------- */

/* Reads as a continuation of the dark hero rather than a new band. The red
   divider that used to sit here made the join feel like a hard stop. */
.trust {
  background: var(--ink);
  color: #fff;
}

.trust__list {
  display: grid;
  gap: clamp(1.75rem, 4vw, 2.5rem);
  padding-block: clamp(2.5rem, 5vw, 3.75rem);
  list-style: none;
  margin: 0;
  text-align: center;
}

@media (min-width: 720px) {
  .trust__list {
    grid-template-columns: repeat(4, 1fr);
    gap: clamp(1.5rem, 3vw, 3rem);
    text-align: left;
  }
}

.trust__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
}

@media (min-width: 720px) {
  .trust__item {
    align-items: flex-start;
    padding-left: clamp(1.5rem, 3vw, 3rem);
    border-left: 1px solid var(--line-dark);
  }

  .trust__item:first-child {
    padding-left: 0;
    border-left: 0;
  }
}

.trust__item .icon {
  width: 24px;
  height: 24px;
  color: #fff;
  opacity: 0.75;
}

.trust__item strong {
  font-size: var(--step-0);
  font-weight: 600;
  line-height: 1.35;
}

.trust__item span {
  font-size: 0.875rem;
  color: var(--text-invert-muted);
  line-height: 1.6;
  max-width: 24ch;
}

/* --------------------------------------------------------------------------
   11. Cards
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: clamp(1.5rem, 3vw, 2rem);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

a.card:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-2);
  transform: translateY(-3px);
}

.card__icon {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: var(--radius);
  background: var(--ink);
  color: #fff;
  flex: none;
}

.card__icon .icon {
  width: 26px;
  height: 26px;
}

.card h3 {
  font-size: var(--step-1);
}

.card p {
  color: var(--text-muted);
  font-size: var(--step--1);
  line-height: 1.65;
  margin: 0;
}

.card__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--sp-2);
  font-size: var(--step--1);
  color: var(--text-muted);
}

.card__list li {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
}

.card__list .icon {
  width: 1em;
  height: 1em;
  margin-top: 0.42em;
  flex: none;
  color: var(--accent);
}

.card__foot {
  margin-top: auto;
  padding-top: var(--sp-2);
}

/* --------------------------------------------------------------------------
   11b. Practice cards
   Treatment for the three practice areas: unboxed icon, and a rule that draws
   across the top on hover. Everything reads without hover, which matters on
   touch.
   -------------------------------------------------------------------------- */

.pcard {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: clamp(1.75rem, 3vw, 2.5rem);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  text-decoration: none;
  color: inherit;
  overflow: hidden;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

.pcard::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 340ms var(--ease);
}

.pcard:hover,
.pcard:focus-visible {
  border-color: var(--ink);
  box-shadow: var(--shadow-2);
  transform: translateY(-4px);
}

.pcard:hover::before,
.pcard:focus-visible::before {
  transform: scaleX(1);
}

.pcard__icon {
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  background: var(--paper-2);
  border: 1px solid var(--line);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
    color var(--dur) var(--ease);
}

.pcard__icon .icon {
  width: 27px;
  height: 27px;
  color: var(--ink);
  stroke-width: 1.5;
  transition: color var(--dur) var(--ease);
}

.pcard:hover .pcard__icon {
  background: var(--ink);
  border-color: var(--ink);
}

.pcard:hover .pcard__icon .icon {
  color: #fff;
}

.pcard h3 {
  font-size: var(--step-2);
  margin: 0;
}

.pcard p {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--step--1);
  line-height: 1.65;
}

/* The matters each area actually covers. Gives the card substance, puts real
   keywords in context, and removes the need for a separate tile grid. */
.pcard__list {
  display: grid;
  gap: var(--sp-3);
  margin: 0;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
  list-style: none;
  font-size: var(--step--1);
  line-height: 1.4;
  color: var(--text);
}

.pcard__list li {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
}

.pcard__list li::before {
  content: "";
  flex: none;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
  transform: translateY(-2px);
}

.pcard__more {
  margin-top: auto;
  padding-top: var(--sp-2);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
}

.pcard__more .icon {
  width: 1em;
  height: 1em;
  transition: transform var(--dur) var(--ease);
}

.pcard:hover .pcard__more .icon {
  transform: translateX(5px);
}

/* Compact service tile, mirrors the icon grid on the current home page. */
.tile {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  min-height: 84px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
  font-weight: 600;
  font-size: var(--step--1);
  line-height: 1.4;
  transition: border-left-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

.tile:hover {
  border-left-color: var(--accent);
  box-shadow: var(--shadow-1);
  transform: translateX(3px);
}

.tile .icon {
  width: 24px;
  height: 24px;
  flex: none;
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   12. Prose
   -------------------------------------------------------------------------- */

.prose {
  max-width: 44rem;
}

.prose > * + * {
  margin-top: var(--sp-5);
}

.prose h2 {
  font-size: var(--step-3);
  margin-top: var(--sp-8);
}

.prose h3 {
  font-size: var(--step-1);
  margin-top: var(--sp-7);
}

.prose h2:first-child,
.prose h3:first-child {
  margin-top: 0;
}

.prose p,
.prose li {
  color: var(--text-muted);
}

.prose strong {
  color: var(--text);
  font-weight: 600;
}

.prose ul,
.prose ol {
  padding-left: 1.25rem;
  display: grid;
  gap: var(--sp-3);
}

.prose li::marker {
  color: var(--accent);
}

.prose a {
  color: var(--accent);
  font-weight: 600;
}

.prose-aside {
  padding: var(--sp-5);
  background: var(--paper-2);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

.prose-aside p {
  margin: 0;
  font-size: var(--step--1);
}

.prose-aside p + p {
  margin-top: var(--sp-3);
}

/* --------------------------------------------------------------------------
   13. FAQ. Native details/summary, no JS, indexable by default.
   -------------------------------------------------------------------------- */

.faq {
  display: grid;
  gap: var(--sp-3);
  max-width: 48rem;
}

.faq__item {
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--paper);
  overflow: hidden;
}

.faq__item[open] {
  border-color: var(--accent);
}

.faq__item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: 56px;
  padding: var(--sp-4) var(--sp-5);
  font-weight: 600;
  font-size: var(--step-0);
  cursor: pointer;
  list-style: none;
}

.faq__item summary::-webkit-details-marker {
  display: none;
}

.faq__item summary::after {
  content: "";
  width: 12px;
  height: 12px;
  flex: none;
  border-right: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--dur) var(--ease);
}

.faq__item[open] summary::after {
  transform: rotate(-135deg) translate(-3px, -3px);
}

/* While collapsing, `open` is still set (it is removed once the animation
   finishes), so the chevron needs its own cue to turn back in step. */
.faq__item.is-closing summary::after {
  transform: rotate(45deg) translate(-2px, -2px);
}

/* The animated box carries no padding of its own. With box-sizing:border-box a
   padded box cannot shrink below its own padding, so the collapse would stall
   at 24px and then jump. Padding lives on the inner element instead. */
.faq__body {
  overflow: hidden;
}

.faq__inner {
  padding: 0 var(--sp-5) var(--sp-5);
  color: var(--text-muted);
  font-size: var(--step--1);
  line-height: 1.7;
}

/* Quieter than an FAQ row: this is supporting detail, not a question. */
.team-about {
  background: transparent;
  border-color: var(--line);
}

.team-about summary {
  font-weight: 600;
  color: var(--text-muted);
}

.team-about[open] summary {
  color: var(--ink);
}

.faq__inner > * + * {
  margin-top: var(--sp-4);
}

/* --------------------------------------------------------------------------
   14. Reviews
   -------------------------------------------------------------------------- */

/* No card, no border, no background, the quote and the stars carry it. */
.review {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* The viewport is as tall as the longest testimonial, so a short one left
     top-aligned strands a block of empty space beneath it, very obvious on a
     phone, where the longest quote runs to eight lines. Centring puts that
     slack above and below instead, which reads as breathing room. */
  justify-content: center;
  gap: clamp(1.25rem, 3vw, 1.75rem);
  max-width: 46rem;
  margin-inline: auto;
  padding: 0;
  text-align: center;
}

/* Matches the previous site's treatment: a red quote mark, roughly 36px,
   centred above the quotation. */
.review__quote {
  display: flex;
  color: var(--accent);
}

.review__quote .icon {
  width: 36px;
  height: 36px;
}

.review blockquote {
  margin: 0;
  font-size: var(--step-2);
  font-weight: 300;
  line-height: 1.55;
  color: var(--text);
  text-wrap: pretty;
}

.review figcaption {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   14b. Testimonial slider
   -------------------------------------------------------------------------- */

.slider__viewport {
  overflow: hidden;
}

.slider__track {
  display: flex;
  margin: 0;
  padding: 0;
  list-style: none;
  transition: transform 520ms var(--ease);
  will-change: transform;
}

/* One review per view at every width. */
.slider__slide {
  flex: 0 0 100%;
  min-width: 0;
  padding-inline: calc(clamp(1rem, 2.5vw, 1.5rem) / 2);
  display: flex;
}

.slider__slide .review {
  flex: 1;
}

/* No negative margin to cancel the per-slide padding: pulling the viewport
   wider than its container pushes the whole page sideways on a phone. The
   half-gutter inset on the outer slides is a fair trade. */

/* Without JS the track becomes a plain wrapped grid and the controls go away,
   so every review is still readable. */
.no-js .slider__track {
  flex-wrap: wrap;
  row-gap: clamp(1rem, 2.5vw, 1.5rem);
  transform: none !important;
}

.no-js .slider__controls {
  display: none;
}

.slider__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--sp-4);
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
}

.slider__btn {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  flex: none;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--ink);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
    color var(--dur) var(--ease);
}

.slider__btn:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

.slider__btn .icon {
  width: 18px;
  height: 18px;
}

.icon--flip {
  transform: rotate(180deg);
}

.icon--up {
  transform: rotate(-90deg);
}

/* --------------------------------------------------------------------------
   Back to top
   Appears once a page is long enough to have been scrolled. Rendered with the
   hidden attribute and only revealed by script, so it never shows on a short
   page or with JavaScript off.
   -------------------------------------------------------------------------- */

.to-top {
  position: fixed;
  right: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  z-index: 60;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  background: rgb(0 0 0 / 78%);
  border: 1px solid rgb(255 255 255 / 22%);
  border-radius: 50%;
  color: #fff;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
    background var(--dur) var(--ease);
}

.to-top[hidden] {
  display: none;
}

.to-top.is-visible {
  opacity: 1;
  transform: none;
}

.to-top:hover {
  background: var(--accent);
  border-color: var(--accent);
}

.to-top .icon {
  width: 20px;
  height: 20px;
  stroke-width: 2;
}

@media print {
  .to-top {
    display: none !important;
  }
}

/* One dot per page, and on a phone that is one page per review, nine of them.
   Wrapping keeps the row inside the viewport however many there are. */
.slider__dots {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  max-width: 100%;
}


/* The button is a real 44px target; the visible bar is drawn inside it. Faking
   the hit area with a pseudo-element works but is invisible to any audit. */
.slider__dot {
  position: relative;
  width: 34px;
  height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
}

.slider__dot::after {
  content: "";
  position: absolute;
  left: 2px;
  right: 2px;
  top: 50%;
  height: 4px;
  margin-top: -2px;
  border-radius: 2px;
  background: var(--line);
  transition: background var(--dur) var(--ease), left var(--dur) var(--ease),
    right var(--dur) var(--ease);
}

.slider__dot:hover::after {
  background: #b9b5ab;
}

.slider__dot[aria-current="true"]::after {
  left: 0;
  right: 0;
  background: var(--accent);
}

/* Nine reviews means nine dots. Alongside two 46px buttons this measured 442px
   inside a 338px phone, and because .slider__controls wraps it broke into three
   stacked rows, chevron, dots, chevron.

   The arrows are dropped rather than shrunk: the track already handles swipe
   (see the touchstart/touchend pair in site.js), which is how people move a
   carousel on a phone anyway, and the dots remain as real buttons so there is
   still a discrete control for anyone not swiping. That leaves 266px of dots
   in 338px, comfortably on one line.

   This block sits after the base .slider__dot rules deliberately. The previous
   560px override was declared before them at equal specificity, so the base
   34px width won and the override never applied at any viewport. */
@media (max-width: 560px) {
  .slider__controls {
    flex-wrap: nowrap;
  }

  .slider__btn {
    display: none;
  }

  .slider__dots {
    flex-wrap: nowrap;
    gap: 4px;
  }

  .slider__dot {
    width: 26px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .slider__track {
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   15. Team
   -------------------------------------------------------------------------- */

/* Fixed column counts rather than auto-fill: auto-fill gave five small
   portraits across a wide screen, and the faces are the point. */
/* Two across even on the narrowest phone, three from tablet up. */
.team-grid {
  display: grid;
  gap: clamp(0.75rem, 2.2vw, 1.75rem);
  grid-template-columns: repeat(2, 1fr);
}

@media (min-width: 940px) {
  .team-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}


.person {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  overflow: hidden;
  background: var(--paper);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

.person:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-2);
  transform: translateY(-3px);
}

.person__photo {
  position: relative;
  aspect-ratio: 4 / 5;
  background: var(--paper-3);
  overflow: hidden;
}

/* Greyscale unifies portraits shot at different times against different
   backgrounds; colour returns on hover. Touch devices have no hover, so they
   stay monochrome, which is the intended look anyway. */
.person__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  filter: grayscale(1);
  transition: opacity var(--dur) var(--ease), filter 320ms var(--ease);
}

.person:hover .person__photo img,
.person:focus-visible .person__photo img {
  filter: grayscale(0);
}

/* The two-portrait hover swap from the current site. */
.person__photo .is-alt {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.person:hover .person__photo .is-alt,
.person:focus-visible .person__photo .is-alt {
  opacity: 1;
}

.person__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-4) var(--sp-3);
  text-align: center;
}

@media (max-width: 559px) {
  .person__body {
    padding: var(--sp-3) var(--sp-2);
  }
}

.person__text {
  display: grid;
  gap: 2px;
  justify-items: center;
  min-width: 0;
}

.person__name {
  font-size: var(--step-0);
  font-weight: 400;
  line-height: 1.25;
  color: var(--accent);
  text-wrap: balance;
}

.person__role {
  font-size: var(--step--1);
  line-height: 1.3;
  color: var(--text-muted);
}

.person__chev {
  flex: none;
  margin-top: var(--sp-2);
  color: var(--accent);
  transition: transform var(--dur) var(--ease);
}

.person__chev .icon {
  width: 20px;
  height: 20px;
  stroke-width: 2;
}

.person:hover .person__chev {
  transform: translateX(4px);
}

/* Profile page */
.profile {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: start;
}

@media (min-width: 900px) {
  .profile {
    grid-template-columns: 340px 1fr;
  }
}

.profile__aside {
  display: grid;
  gap: var(--sp-5);
}

/* Entrance. Profile content sits above the fold, so this is a load-in rather
   than a scroll reveal, picking up where the page header's stagger leaves off.
   `backwards` fill means the start state exists only during the delay, if
   animations never run, nothing is hidden. */
@media (prefers-reduced-motion: no-preference) {
  .profile__aside > *:nth-child(1) {
    animation: rise-in 620ms var(--ease) 150ms backwards;
  }

  .profile__aside > *:nth-child(2) {
    animation: rise-in 620ms var(--ease) 240ms backwards;
  }

  .profile > *:nth-child(2) {
    animation: rise-in 620ms var(--ease) 330ms backwards;
  }
}

@media (min-width: 900px) {
  .profile__aside {
    position: sticky;
    top: calc(var(--header-h) + 1.5rem);
  }
}

.profile__photo {
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--paper-3);
  border-bottom: 4px solid var(--accent);
}

.profile__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

.profile__facts {
  display: grid;
  gap: var(--sp-5);
  padding: var(--sp-5);
  background: var(--paper-2);
  border-radius: var(--radius-lg);
}

.profile__facts h2 {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--sp-3);
}

.profile__facts ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--sp-2);
  font-size: var(--step--1);
  color: var(--text-muted);
}

.profile__facts a {
  color: var(--accent);
  font-weight: 600;
  word-break: break-word;
}

/* Who a person works with, shown with faces. */
.people-strip {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
}

.people-strip a {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-3);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

.people-strip a:hover {
  border-color: var(--ink);
  box-shadow: var(--shadow-1);
  transform: translateY(-2px);
}

.people-strip__photo {
  flex: none;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--paper-3);
}

.people-strip__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 12%;
  filter: grayscale(1);
  transition: filter 320ms var(--ease);
}

.people-strip a:hover .people-strip__photo img {
  filter: grayscale(0);
}

.people-strip__text {
  display: grid;
  gap: 1px;
  min-width: 0;
  margin-right: auto;
}

.people-strip__name {
  font-weight: 700;
  font-size: var(--step--1);
  line-height: 1.3;
}

.people-strip__role {
  font-size: 0.78rem;
  color: var(--text-muted);
}

.people-strip .icon {
  flex: none;
  width: 18px;
  height: 18px;
  stroke-width: 2;
  color: var(--accent);
  transition: transform var(--dur) var(--ease);
}

.people-strip a:hover .icon {
  transform: translateX(3px);
}

/* --------------------------------------------------------------------------
   16. Forms
   -------------------------------------------------------------------------- */

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

.field {
  display: grid;
  gap: var(--sp-2);
}

.field > label {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.04em;
}

.field .req {
  color: var(--accent);
}

.field .hint {
  font-size: var(--step--1);
  color: var(--text-muted);
}

.field input,
.field textarea,
.field select,
.field .picker-button {
  width: 100%;
  min-height: 50px;
  padding: 0.7rem 0.9rem;
  background: var(--paper);
  border: 1px solid #b9b5ab;
  border-radius: var(--radius);
  font-size: 1rem;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

/* Browsers add their own internal padding to a select on top of ours, so it
   rendered noticeably taller than the inputs beside it. A fixed height and
   horizontal-only padding makes every control in a row the same size. */
.field select,
.field .picker-button {
  height: 50px;
  padding-block: 0;
  line-height: 1.2;
}

.field input:not([type="date"]),
.field input[type="date"] {
  height: 50px;
}

/* The control sits at the top of the field, so a hint under one field does not
   drag its neighbour's box out of line. */
.field {
  align-content: start;
}

.form__row > .field > label {
  min-height: 1.4em;
}

.field textarea {
  min-height: 160px;
  resize: vertical;
}

.field input:focus,
.field textarea:focus,
.field select:focus {
  border-color: var(--ink);
  box-shadow: 0 0 0 3px var(--accent-ring);
  outline: none;
}

.field input:user-invalid,
.field textarea:user-invalid {
  border-color: var(--accent);
}

@media (min-width: 720px) {
  .form__row {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-5);
  }
}

.form__note {
  font-size: var(--step--1);
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Modal picker
   Replaces the native select on the enquiry form. The select stays in the DOM
   and keeps holding the value, so the form submits identically and still works
   if this never initialises.
   -------------------------------------------------------------------------- */

.field[data-picker-ready] select {
  display: none;
}

.picker-button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  text-align: left;
  cursor: pointer;
}

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

.picker-button .icon {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--accent);
  transform: rotate(90deg);
}

.picker {
  width: min(30rem, calc(100vw - 2rem));
  padding: 0;
  border: 0;
  border-radius: var(--radius-xl);
  background: var(--paper);
  color: var(--text);
  box-shadow: var(--shadow-2);
}

.picker::backdrop {
  background: rgb(0 0 0 / 55%);
}

/* Keyframes rather than transitions with @starting-style / allow-discrete:
   those are the tidier modern approach but are not yet everywhere, and where
   they are missing the dialog simply vanishes on close. The script holds the
   dialog open until the exit animation ends, so this works in any engine. */
@media (prefers-reduced-motion: no-preference) {
  .picker[open] {
    animation: picker-in 220ms var(--ease);
  }

  .picker[open]::backdrop {
    animation: picker-backdrop-in 220ms var(--ease);
  }

  .picker.is-closing {
    animation: picker-out 180ms var(--ease) forwards;
  }

  .picker.is-closing::backdrop {
    animation: picker-backdrop-out 180ms var(--ease) forwards;
  }
}

@keyframes picker-in {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }
}

@keyframes picker-out {
  to {
    opacity: 0;
    transform: translateY(10px) scale(0.98);
  }
}

@keyframes picker-backdrop-in {
  from {
    background: rgb(0 0 0 / 0%);
  }
}

@keyframes picker-backdrop-out {
  to {
    background: rgb(0 0 0 / 0%);
  }
}

.picker__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-5);
  border-bottom: 1px solid var(--line);
}

.picker__head h2 {
  font-size: var(--step-1);
  margin: 0;
}

.picker__close {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  flex: none;
  background: none;
  border: 0;
  border-radius: 50%;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--text-muted);
}

.picker__close:hover {
  background: var(--paper-2);
  color: var(--ink);
}

.picker__list {
  list-style: none;
  margin: 0;
  padding: var(--sp-4);
  display: grid;
  gap: var(--sp-2);
}

.picker__option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  width: 100%;
  min-height: 56px;
  padding: var(--sp-4);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  font-size: var(--step-0);
  text-align: left;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
    color var(--dur) var(--ease);
}

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

.picker__option[aria-checked="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 600;
}

.picker__option .icon {
  width: 18px;
  height: 18px;
  flex: none;
  opacity: 0;
}

.picker__option[aria-checked="true"] .icon {
  opacity: 1;
}

/* Confirmation dialog. Shares the picker's shell and animation. */
.confirm {
  width: min(38rem, calc(100vw - 2rem));
}

.confirm__eyebrow {
  display: block;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--sp-2);
}

.confirm .picker__head h2 {
  font-size: var(--step-2);
  color: var(--accent);
  line-height: 1.2;
}

.confirm__points {
  margin: 0;
  padding: var(--sp-5);
  display: grid;
  gap: var(--sp-4);
  list-style: none;
  font-size: var(--step--1);
  line-height: 1.65;
  color: var(--text-muted);
  max-height: 52vh;
  overflow-y: auto;
}

.confirm__points li {
  padding-left: 1.1rem;
  position: relative;
}

.confirm__points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

.confirm__points strong {
  color: var(--text);
  font-weight: 700;
}

.confirm__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--sp-3);
  padding: var(--sp-5);
  border-top: 1px solid var(--line);
}

/* Honeypot. Hidden from people, visible to naive bots. */
.form__hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   17. Contact details block
   -------------------------------------------------------------------------- */

.contact-list {
  display: grid;
  gap: var(--sp-5);
  list-style: none;
  margin: 0;
  padding: 0;
}

.contact-list li {
  display: flex;
  gap: var(--sp-4);
  align-items: flex-start;
}

.contact-list .icon {
  width: 22px;
  height: 22px;
  flex: none;
  margin-top: 0.25rem;
  color: var(--accent);
}

.contact-list dt,
.contact-list strong {
  display: block;
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--sp-1);
}

.contact-list a {
  color: var(--ink);
  font-weight: 600;
  font-size: var(--step-1);
  text-decoration: none;
  border-bottom: 2px solid var(--accent);
}

.contact-list a:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* --------------------------------------------------------------------------
   18. CTA band
   -------------------------------------------------------------------------- */

.cta-band {
  position: relative;
  background: var(--ink);
  color: #fff;
  overflow: hidden;
}

.cta-band__media {
  position: absolute;
  inset: 0;
}

.cta-band__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Favours the table, chairs and screen over the ceiling. */
  object-position: center 58%;
}

/* Dark enough behind the centred text to keep white legible over the bright
   window and pale tabletop, easing off at the edges so the room is actually
   visible. A flat 76% scrim hid the photo completely. */
.cta-band__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    rgb(0 0 0 / 42%) 0%,
    rgb(0 0 0 / 80%) 28%,
    rgb(0 0 0 / 80%) 72%,
    rgb(0 0 0 / 42%) 100%
  );
}

@media (max-width: 767px) {
  /* Too narrow for the edges to read as anything but noise. */
  .cta-band__media::after {
    background: rgb(0 0 0 / 74%);
  }
}

.cta-band__inner {
  position: relative;
  padding-block: clamp(3.5rem, 9vw, 7rem);
  min-height: clamp(20rem, 34vw, 26rem);
  align-content: center;
  text-align: center;
  display: grid;
  justify-items: center;
  gap: var(--sp-5);
}

/* The row is centred as a block, but its buttons also need centring, once
   they wrap onto two lines they otherwise sit flush left under centred text. */
.cta-band .btn-row {
  justify-content: center;
}

.cta-band h2 {
  font-size: var(--step-3);
  font-weight: 300;
  max-width: 34ch;
}

.cta-band h2 strong {
  font-weight: 700;
  color: var(--accent-on-dark);
}

.cta-band p {
  color: var(--text-invert-muted);
  max-width: 52ch;
}

/* --------------------------------------------------------------------------
   19. Footer
   -------------------------------------------------------------------------- */

.site-footer {
  background: var(--ink);
  color: var(--text-invert-muted);
  border-top: 3px solid var(--accent);
  font-size: var(--step--1);
}

/* Multi-column, not grid, on a phone. Grid sizes each row by its tallest item,
   so the address block left a large hole beside it; columns flow and balance
   instead. One column stacked was tidy but half again as tall. */
.site-footer__grid {
  columns: 2;
  column-gap: var(--sp-5);
  padding-block: clamp(2.5rem, 6vw, 4rem);
}

.site-footer__grid > * {
  break-inside: avoid;
  margin-bottom: var(--sp-6);
}

.site-footer__brand {
  column-span: all;
}

@media (min-width: 560px) {
  .site-footer__grid {
    columns: auto;
    display: grid;
    gap: clamp(1.75rem, 5vw, 3rem);
    grid-template-columns: repeat(2, 1fr);
  }

  .site-footer__grid > * {
    margin-bottom: 0;
  }

  .site-footer__brand {
    grid-column: 1 / -1;
  }
}

/* Four link groups on one row from tablet up; the brand still spans above. */
@media (min-width: 620px) {
  .site-footer__grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (min-width: 1024px) {
  .site-footer__grid {
    grid-template-columns: 1.5fr repeat(4, 1fr);
  }

  .site-footer__brand {
    grid-column: auto;
  }
}

.site-footer__brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.site-footer__hours {
  margin-top: var(--sp-4);
}

.site-footer__areas {
  padding-block: var(--sp-4);
  text-align: center;
  font-size: 0.82rem;
  line-height: 1.6;
  color: #8f8b82;
}

.site-footer__hours strong {
  color: #fff;
  font-weight: 600;
}

.site-footer__brand + div h2,
.site-footer__grid > div > h2 {
  margin-top: 0;
}

/* h3, not h2: footer column labels are navigation, and as h2 they sat in the
   document outline alongside the page's actual sections and diluted it. */
.site-footer h3 {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #fff;
  margin-bottom: var(--sp-4);
}

.site-footer ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--sp-3);
}

.site-footer a {
  color: var(--text-invert-muted);
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--accent-on-dark);
  text-decoration: underline;
}

.site-footer address {
  font-style: normal;
  line-height: 1.9;
}

.site-footer__logo {
  width: auto;
  height: 54px;
  margin-bottom: var(--sp-4);
}

.site-footer__social {
  display: flex;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
}

.site-footer__social a {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--line-dark);
  border-radius: 50%;
  color: #fff;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
    color var(--dur) var(--ease);
}

.site-footer__social a:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--ink);
}

.site-footer__social .icon {
  width: 18px;
  height: 18px;
}

.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding-block: var(--sp-5);
  font-size: 0.82rem;
  color: #8f8b82;
}

.site-footer__legal ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-5);
}

/* --------------------------------------------------------------------------
   19b. Fees
   -------------------------------------------------------------------------- */

.fee-list {
  margin: 0;
  display: grid;
  gap: var(--sp-4);
}

.fee-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-bottom: var(--sp-4);
  border-bottom: 1px solid var(--line);
}

.fee-row:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.fee-row dt {
  font-weight: 600;
  font-size: var(--step-0);
  flex: 1 1 12rem;
}

.fee-row dd {
  margin: 0;
  text-align: right;
  flex: 0 0 auto;
}

.fee-row dd strong {
  display: block;
  font-size: var(--step-0);
  color: var(--ink);
  white-space: nowrap;
}

.fee-row dd span,
.fee-note {
  display: block;
  font-size: 0.82rem;
  font-weight: 300;
  line-height: 1.45;
  color: var(--text-muted);
}

.fee-note {
  margin-top: var(--sp-1);
}

.fee-aid {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  padding: var(--sp-4);
  background: var(--paper-2);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--text-muted);
}

.fee-aid .icon {
  width: 18px;
  height: 18px;
  margin-top: 0.25em;
  color: var(--accent);
}

.fee-aid a {
  color: var(--accent);
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   Contact page
   -------------------------------------------------------------------------- */

.contact-cards {
  display: grid;
  gap: clamp(0.75rem, 2vw, 1.25rem);
  grid-template-columns: repeat(2, 1fr);
}

@media (min-width: 900px) {
  .contact-cards {
    grid-template-columns: repeat(4, 1fr);
  }
}

.contact-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: clamp(1rem, 2.2vw, 1.5rem);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  border-top: 3px solid var(--accent);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

a.contact-card:hover {
  border-color: var(--ink);
  border-top-color: var(--accent);
  box-shadow: var(--shadow-1);
  transform: translateY(-2px);
}

.contact-card .icon {
  width: 22px;
  height: 22px;
  color: var(--accent);
  margin-bottom: var(--sp-2);
}

.contact-card__label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.contact-card__value {
  font-size: var(--step-0);
  font-weight: 600;
  line-height: 1.3;
  word-break: break-word;
}

.contact-card__sub {
  font-size: 0.82rem;
  color: var(--text-muted);
}

.contact-side {
  display: grid;
  gap: var(--sp-5);
  align-content: start;
}

.contact-urgent {
  margin-bottom: clamp(1.5rem, 3vw, 2rem);
}

/* Fills the column beside the form instead of sitting in its own section
   below, which left the right-hand column empty for most of the page. */
.contact-map {
  min-height: clamp(20rem, 42vw, 30rem);
  border-radius: var(--radius-xl);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--paper-3);
}

.contact-map {
  position: relative;
}

.contact-map iframe {
  display: block;
  width: 100%;
  height: 100%;
  min-height: inherit;
  position: relative;
  z-index: 1;
}

/* Holds the space until the iframe arrives, so nothing shifts when it does. */
.contact-map__placeholder {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #b9b5ab;
}

.contact-map__placeholder .icon {
  width: 34px;
  height: 34px;
}

.contact-side .btn {
  justify-self: start;
}

/* --------------------------------------------------------------------------
   Price cards
   -------------------------------------------------------------------------- */

.pricecards {
  display: grid;
  gap: clamp(0.75rem, 2vw, 1.25rem);
  grid-template-columns: 1fr;
}

@media (min-width: 560px) {
  .pricecards {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* --cols is set per section from the number of services, so a two-service
   area is not left with an empty cell in a three-column grid. */
@media (min-width: 940px) {
  .pricecards {
    grid-template-columns: repeat(var(--cols, 3), 1fr);
  }
}

.pricecard {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  border-top: 3px solid var(--accent);
}

.pricecard__name {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  line-height: 1.4;
}

.pricecard__price {
  font-size: clamp(1.7rem, 3.2vw, 2.3rem);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-wrap: nowrap;
}

.pricecard__gst {
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--text-muted);
  white-space: nowrap;
}

.pricecard__unit {
  font-size: var(--step--1);
  color: var(--text-muted);
  line-height: 1.5;
}

.pricecard__note {
  margin-top: auto;
  padding-top: var(--sp-2);
  font-size: 0.8rem;
  line-height: 1.55;
  color: var(--text-muted);
}

/* Legal Aid note and the practice-area link, beneath the cards. */
.fee-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-top: clamp(1.5rem, 3vw, 2rem);
}

.fee-foot .fee-aid {
  flex: 1 1 22rem;
}

/* Bureau fee, disbursements and SuperGold, a second row inside the
   conveyancing section, since they do not apply to criminal or family work. */
.fee-extras {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  padding-top: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid var(--line);
}

.fee-extra__title {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--sp-3);
}

.fee-extra__body {
  color: var(--text-muted);
  font-size: var(--step--1);
  line-height: 1.65;
}

.fee-extra__body strong {
  color: var(--text);
}

.fee-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
}

.fee-table caption {
  text-align: left;
  font-weight: 700;
  font-size: var(--step-0);
  color: var(--ink);
  padding-bottom: var(--sp-3);
}

.fee-table th,
.fee-table td {
  padding: var(--sp-3) var(--sp-2);
  border-bottom: 1px solid var(--line);
  text-align: left;
}

.fee-table th {
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 2px solid var(--ink);
}

.fee-table td:last-child,
.fee-table th:last-child {
  text-align: right;
  font-weight: 600;
}

/* Only the figures stay on one line. Header text must be free to wrap, or a
   long column heading forces the whole table wider than a phone screen. */
.fee-table td:last-child {
  white-space: nowrap;
}

/* Any table that still cannot fit scrolls inside itself rather than pushing
   the page sideways. */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.fee-table tbody tr:last-child td {
  border-bottom: 0;
}

/* --------------------------------------------------------------------------
   19b2. Tabs
   -------------------------------------------------------------------------- */

/* Sits under the intro copy in the same section, so it needs its own space
   above rather than a second section's worth of padding. */
.tabs-wrap {
  margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
}

/* Hidden until the script takes over, so no-JS visitors are not shown a strip
   of buttons that do nothing, they get every panel as one long page instead. */
.tabs__list {
  display: none;
}

/* Wrapping chips rather than a scrolling strip. With eight topics an
   underline strip runs off the side of a phone and half the options are
   hidden behind a sideways drag; wrapped chips show all of them at once at
   every width. */
.tabs[data-tabs-ready] .tabs__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.tabs__tab {
  flex: 0 1 auto;
  padding: 0.7rem 1.05rem;
  min-height: 48px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-align: left;
  color: var(--text-muted);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
    color var(--dur) var(--ease);
}

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

/* White on #c00 is 6.7:1. */
.tabs__tab[aria-selected="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* Panels only ever get hidden by the script, via the hidden attribute. */
.tabs__panel:focus {
  outline: none;
}

/* Switching tabs fades the incoming panel in. The hidden attribute is
   display:none, so un-hiding renders the element fresh and the animation
   restarts on its own, no JS needed to retrigger it. */
@media (prefers-reduced-motion: no-preference) {
  .tabs[data-tabs-ready] .tabs__panel:not([hidden]) {
    animation: panel-in 300ms var(--ease);
  }
}

@keyframes panel-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* Without the tab strip the panels run together, so they need separating. */
.tabs:not([data-tabs-ready]) .tabs__panel + .tabs__panel {
  margin-top: clamp(2.5rem, 6vw, 4rem);
  padding-top: clamp(2.5rem, 6vw, 4rem);
  border-top: 1px solid var(--line);
}

/* --------------------------------------------------------------------------
   19c. On-this-page jump nav
   -------------------------------------------------------------------------- */

.jump {
  position: sticky;
  top: var(--header-h);
  z-index: 50;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 rgb(0 0 0 / 4%);
}

.jump ul {
  display: flex;
  gap: var(--sp-5);
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-x: auto;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}

.jump li {
  flex: none;
}

.jump a {
  display: block;
  padding: var(--sp-4) 0;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  color: var(--text-muted);
  border-bottom: 3px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.jump a:hover {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

/* --------------------------------------------------------------------------
   19d. Profile detail lists
   -------------------------------------------------------------------------- */

.detail-heading {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--sp-4);
  padding-bottom: var(--sp-3);
  border-bottom: 2px solid var(--line);
}

.detail-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--sp-3);
  font-size: var(--step--1);
  color: var(--text-muted);
}

.detail-list li {
  padding-left: 1.1rem;
  position: relative;
}

.detail-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

/* --------------------------------------------------------------------------
   19e. Touch targets
   On a phone every interactive element needs a comfortable hit area. Inline
   links in running prose are exempt  they are read, not aimed at  but
   standalone navigation links are not.
   -------------------------------------------------------------------------- */

@media (pointer: coarse), (max-width: 767px) {
  .site-footer ul a,
  .site-footer p a,
  .site-footer address a,
  .site-footer__legal ul a,
  .mobile-nav__contact a,
  .breadcrumbs a,
  .jump a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  .site-footer ul {
    gap: 0;
  }

  .contact-list a,
  .profile__facts a,
  .fee-aid a,
  .link-arrow {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  .profile__facts ul {
    gap: 0;
  }

  .link-arrow {
    align-items: center;
  }
}

/* --------------------------------------------------------------------------
   20. Utilities
   -------------------------------------------------------------------------- */

.text-center {
  text-align: center;
}

.mt-0 {
  margin-top: 0;
}

.mt-6 {
  margin-top: var(--sp-6);
}

.mt-7 {
  margin-top: var(--sp-7);
}

.icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}

.icon--fill {
  fill: currentColor;
  stroke: none;
}

.media {
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--paper-3);
}

.media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.media--4x3 {
  aspect-ratio: 4 / 3;
}

.media--3x2 {
  aspect-ratio: 3 / 2;
}

/* --------------------------------------------------------------------------
   21. Print
   -------------------------------------------------------------------------- */

@media print {
  .site-header,
  .mobile-nav,
  .cta-band,
  .site-footer__social,
  .breadcrumbs,
  .btn {
    display: none !important;
  }

  body {
    color: #000;
    font-size: 11pt;
  }

  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
  }
}

/* --------------------------------------------------------------------------
   22. Appointment confirmation
   -------------------------------------------------------------------------- */

/* Mirrors the details block in the confirmation email, so the browser version
   and the email read as the same document. */
.appt-card {
  padding: clamp(1.5rem, 4vw, 2.25rem);
  background: var(--paper-2);
  border-radius: var(--radius-xl);
}

.appt-card__list {
  margin: 0 0 var(--sp-6) 0;
}

/* Icon in its own column, spanning the label and the value beside it. The
   label sits above the value rather than to its left, which is what lets this
   hold together at 320px without a separate mobile rule — the old 6.5rem label
   column left the date wrapping awkwardly. */
.appt-card__list > div {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--sp-4);
  align-items: start;
  padding-block: var(--sp-3);
  border-bottom: 1px solid var(--line);
}

.appt-card__list > div:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.appt-card__list .icon {
  grid-row: 1 / span 2;
  width: 1.375rem;
  height: 1.375rem;
  color: var(--accent);
  /* Optically centred on the label's cap height rather than its line box. */
  margin-top: 0.15em;
}

.appt-card__list dt {
  grid-column: 2;
  margin: 0;
  font-size: 0.6875rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.appt-card__list dd {
  grid-column: 2;
  margin: 0;
  font-size: var(--step-1);
  line-height: 1.5;
}

.appt-card__list strong {
  font-weight: 600;
}

.appt-card__sub {
  display: inline-block;
  padding-top: 0.15rem;
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--text-muted);
}

.appt-note {
  margin-top: var(--sp-7);
  font-size: var(--step--1);
  line-height: 1.7;
  color: var(--text-muted);
}

/* Numbered "what to bring", mirroring the email's list. */
.appt-list {
  counter-reset: appt;
  margin: var(--sp-5) 0 0;
  padding: 0;
  list-style: none;
}

.appt-list > li {
  counter-increment: appt;
  position: relative;
  padding: var(--sp-5) 0 var(--sp-5) 3rem;
  border-bottom: 1px solid var(--line);
}

.appt-list > li:last-child { border-bottom: 0; }

.appt-list > li::before {
  content: counter(appt) ".";
  position: absolute;
  left: 0;
  top: var(--sp-5);
  font-size: var(--step-1);
  font-weight: 600;
  color: var(--accent);
}

.appt-list h3 {
  margin: 0 0 var(--sp-2);
  font-size: var(--step-1);
  font-weight: 600;
}

.appt-list p {
  margin: 0;
  color: var(--text-muted);
  line-height: 1.7;
}

/* The two callout treatments: red-edged for consequences, plain for context. */
.appt-alert,
.appt-note-box {
  padding: var(--sp-4) var(--sp-5);
  border-radius: 0 var(--radius) var(--radius) 0;
}

.appt-alert {
  background: #fdf6f6;
  border-left: 3px solid var(--accent);
}

.appt-note-box {
  background: var(--paper-2);
  border-radius: var(--radius);
}

.appt-alert p,
.appt-note-box p {
  margin: 0;
  line-height: 1.7;
}

.appt-policy {
  margin: 0;
  padding-left: 1.2rem;
  color: var(--text-muted);
}

.appt-policy li { margin-bottom: var(--sp-3); line-height: 1.7; }
.appt-policy li:last-child { margin-bottom: 0; }

/* The "do not email documents early" warning: it sits inside a list item, so
   it needs to read as a caution rather than more body copy. */
.appt-warn {
  margin-top: var(--sp-3) !important;
  color: var(--ink) !important;
}

.appt-warn strong { color: var(--accent); }

.appt-map {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.appt-map-note {
  margin-top: calc(var(--sp-2) * -1) !important;
  font-size: var(--step--1);
  color: var(--text-muted);
}
