/* The public site — redesign v2, July 2026.
   Colours, type and corners come from assets/brand.css — the names below are
   this file's own shorthand for them, so every rule underneath keeps reading
   the way it always has while there is only one place a colour is actually
   decided. Add a NEW colour to brand.css, never here. */
:root {
  --navy: var(--wws-navy);
  --navy-deep: var(--wws-navy-deep);
  --blue: var(--wws-blue);
  --blue-ink: var(--wws-blue-ink);
  --blue-soft: var(--wws-blue-soft);
  --blue-tint: var(--wws-blue-tint);
  --slate: var(--wws-slate);
  --mist: var(--wws-mist);
  --ink: var(--wws-ink);
  --white: var(--wws-white);
  --border: var(--wws-line);
  --green: var(--wws-green-ink);
  --amber: var(--wws-amber-ink);
  --red: var(--wws-red-ink);
  --radius: var(--wws-radius);
  --maxw: 1120px;
}

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  color: var(--ink);
  background: var(--white);
  line-height: 1.65;
}

h1, h2, h3 {
  font-family: 'Poppins', system-ui, sans-serif;
  color: var(--navy);
  line-height: 1.15;
  margin: 0 0 0.5em;
  letter-spacing: -0.01em;
}

p { margin: 0 0 1em; }

a { color: var(--blue-ink); text-decoration: none; }
a:hover { text-decoration: underline; }

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

/* Keyboard users get a way past the nav; everyone else never sees it. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--navy);
  color: var(--white);
  padding: 10px 18px;
  border-radius: 0 0 var(--radius) 0;
  font-weight: 600;
}
.skip-link:focus { left: 0; text-decoration: none; }

/* ---- scroll reveal ----------------------------------------------------
   Sections drift up a few pixels as they enter the viewport. The .js class
   is set by an inline script in the header, so WITHOUT JavaScript nothing is
   ever hidden — the reveal is an enhancement, not a dependency. Reduced
   motion gets everything marked .is-in immediately (footer script) and
   brand.css zeroes the transition, so the drift never happens for them. */
.js .reveal {
  opacity: 0;
  transform: translateY(18px);
}
.js .reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity .6s var(--wws-ease), transform .6s var(--wws-ease);
}
/* Stagger for card grids: second and third cards follow the first in. */
.js .reveal.is-in.reveal-d1 { transition-delay: .08s; }
.js .reveal.is-in.reveal-d2 { transition-delay: .16s; }

/* Buttons */
.btn {
  display: inline-block;
  font-family: 'Poppins', sans-serif;
  font-weight: 500;
  font-size: 16px;
  padding: 13px 28px;
  border-radius: var(--radius);
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform var(--wws-speed-fast) var(--wws-ease),
              background var(--wws-speed) var(--wws-ease),
              box-shadow var(--wws-speed) var(--wws-ease),
              border-color var(--wws-speed) var(--wws-ease);
  text-align: center;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn-primary {
  background: var(--wws-grad-blue);
  color: var(--white);
  box-shadow: var(--wws-shadow-sm);
}
.btn-primary:hover {
  transform: translateY(-1px);
  box-shadow: var(--wws-shadow-blue);
}
.btn-ghost { background: transparent; color: var(--navy); border-color: var(--wws-line-strong); }
.btn-ghost:hover { border-color: var(--blue); color: var(--blue-ink); }
.btn-sm { padding: 9px 18px; font-size: 15px; }
.btn-block { width: 100%; }

/* Header */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, .86);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  transition: box-shadow var(--wws-speed) var(--wws-ease);
}
/* Set by the footer script once the page moves — the bar earns its shadow
   only when there is content sliding underneath it. */
.site-header.is-scrolled { box-shadow: 0 6px 24px rgba(16, 36, 62, .08); }
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 74px;
  gap: 16px;
}
.brand { display: flex; align-items: center; gap: 12px; flex: none; }
.brand:hover { text-decoration: none; }
.brand-mark { display: block; border-radius: 10px; }
.brand-text { display: flex; flex-direction: column; line-height: 1.1; }
.brand-name { font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 19px; color: var(--navy); }
.brand-sub { font-family: 'Poppins', sans-serif; font-weight: 500; font-size: 10px; letter-spacing: 2px; text-transform: uppercase; color: var(--blue); }

.site-nav { display: flex; align-items: center; gap: 26px; }
.site-nav a:not(.btn) {
  position: relative;
  color: var(--navy);
  font-weight: 500;
  padding: 4px 0;
}
.site-nav a:not(.btn):hover { color: var(--blue-ink); text-decoration: none; }
/* The underline grows from the centre on hover, and stays put on the current
   page — "you are here" and "you could go here" are the same mark, one of
   them just isn't going anywhere. */
.site-nav a:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  border-radius: 2px;
  background: var(--blue);
  transform: scaleX(0);
  transition: transform var(--wws-speed) var(--wws-ease);
}
.site-nav a:not(.btn):hover::after { transform: scaleX(.6); }
.site-nav a.is-current { color: var(--navy); font-weight: 600; }
.site-nav a.is-current::after { transform: scaleX(1); }

/* The menu button. Hidden on desktop; the media block at the bottom swaps the
   inline nav for this + a drop-down, the same pattern the portals use. */
.nav-toggle { display: none; }

/* ---- heroes -------------------------------------------------------------
   The homepage gets the full-height version with the constellation art; the
   inner pages get .hero-compact — same navy, same type, less ceremony. */
.hero {
  position: relative;
  background: var(--wws-grad-navy);
  color: var(--white);
  padding: 108px 0 116px;
  overflow: hidden;
  isolation: isolate;
}
/* Two soft blue glows so the navy reads as lit rather than flat. Behind the
   text (z-index -1) so selection and reading are never through a wash. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(720px 480px at 82% 18%, rgba(45, 125, 246, .28), transparent 68%),
    radial-gradient(560px 420px at 8% 92%, rgba(127, 168, 220, .14), transparent 66%);
}
.hero-inner { position: relative; max-width: 680px; }
/* The constellation — the logo's node-and-line language let loose across the
   right of the hero. Decorative, aria-hidden, and absent on phones where it
   would sit behind the text. */
.hero-art {
  position: absolute;
  top: 50%;
  right: max(-80px, calc((100vw - var(--maxw)) / 2 - 140px));
  transform: translateY(-50%);
  width: min(520px, 44vw);
  opacity: .9;
  pointer-events: none;
}
.hero-art svg { display: block; width: 100%; height: auto; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: 'Poppins', sans-serif;
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--blue-soft);
  margin: 0 0 18px;
}
/* The little node in front of the eyebrow — the logo's full stop. */
.eyebrow::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--blue);
  box-shadow: 0 0 0 4px rgba(45, 125, 246, .22);
}
.hero h1 {
  color: var(--white);
  font-size: clamp(40px, 6vw, 64px);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 20px;
}
/* Gradient only where it stays readable: a big bold word on navy. The solid
   colour is the fallback for anything that can't clip a background to text. */
.hero .accent { color: #6FA6F8; }
@supports (-webkit-background-clip: text) or (background-clip: text) {
  .hero .accent {
    background: linear-gradient(115deg, #8CB8FA 0%, #4A90F7 60%, #2D7DF6 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}
.hero-lead {
  font-size: clamp(17px, 2.4vw, 20px);
  color: #C7D6E8;
  max-width: 620px;
  margin-bottom: 34px;
}
.hero-actions { display: flex; flex-wrap: wrap; gap: 14px; }
.hero .btn-ghost { color: var(--white); border-color: rgba(255, 255, 255, .32); }
.hero .btn-ghost:hover { border-color: var(--white); color: var(--white); }
.hero .btn-primary { box-shadow: var(--wws-shadow-blue); }

/* The three quiet promises under the hero buttons. Facts only — each one is
   backed somewhere on the site (pricing page, why page, privacy page). */
.hero-trust {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
  margin: 36px 0 0;
  padding: 22px 0 0;
  border-top: 1px solid rgba(255, 255, 255, .14);
}
.hero-trust li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 14.5px;
  font-weight: 500;
  color: #C7D6E8;
}
.hero-trust svg { flex: none; display: block; }

.hero-compact { padding: 64px 0 68px; }
.hero-compact h1 { font-size: clamp(32px, 4.6vw, 46px); }
.hero-compact .hero-lead { margin-bottom: 0; }

/* Sections */
.section { padding: 92px 0; }
.section-alt {
  background:
    radial-gradient(640px 420px at 90% 0%, rgba(45, 125, 246, .05), transparent 62%),
    var(--mist);
}
.section-head { max-width: 640px; margin: 0 auto 52px; text-align: center; }
.section-head .eyebrow { color: var(--blue-ink); justify-content: center; }
.section-head .eyebrow::before { box-shadow: 0 0 0 4px rgba(45, 125, 246, .14); }
.section-head h2 { font-size: clamp(28px, 4vw, 40px); font-weight: 600; }
.section-head p { color: var(--slate); font-size: 18px; margin: 0; }

/* Service cards */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 24px;
}
/* Two cards. Left to auto-fit they'd take half the container each and dwarf the
   three above them — the monthly prices are the smaller commitment and should
   look like it. */
.cards-pair {
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  max-width: 760px;
  margin: 0 auto;
}
.card {
  position: relative;
  background: var(--white);
  background-image: var(--wws-grad-sheen);
  border: 1px solid var(--border);
  border-radius: var(--wws-radius-xl);
  padding: 34px 30px;
  box-shadow: var(--wws-shadow-sm);
  overflow: hidden;
  transition: transform var(--wws-speed) var(--wws-ease),
              box-shadow var(--wws-speed) var(--wws-ease),
              border-color var(--wws-speed) var(--wws-ease);
}
/* The hairline of signal blue along a card's top edge, revealed on hover —
   the same "live connection" idea as the lit node in the logo. */
.card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--wws-grad-blue);
  opacity: 0;
  transition: opacity var(--wws-speed) var(--wws-ease);
}
.card:hover {
  transform: translateY(-5px);
  box-shadow: var(--wws-shadow-md), 0 18px 40px rgba(16, 36, 62, .10);
  border-color: #CFE0F6;
}
.card:hover::before { opacity: 1; }
.card-icon {
  width: 56px; height: 56px;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(160deg, var(--blue-tint), rgba(232, 240, 252, .35));
  border: 1px solid rgba(45, 125, 246, .18);
  border-radius: 16px;
  margin-bottom: 20px;
}
.card h3 { font-size: 21px; font-weight: 600; }
.card p { color: var(--slate); margin: 0; }

/* Pricing */
.price-tag {
  font-size: 36px;
  font-weight: 700;
  font-family: 'Poppins', system-ui, sans-serif;
  color: var(--navy);
  line-height: 1.1;
  margin: 6px 0 12px;
}
.price-tag span { font-size: 16px; font-weight: 500; font-family: 'Inter', sans-serif; color: var(--slate); }
/* "+ VAT (£48 inc.)" under a price, once registered — empty markup until then.
   Its own line under the headline figure rather than trailing it, so a 36px
   price tag doesn't wrap mid-number on a phone. The .price-tag span rule above
   would otherwise catch it, hence resetting the size here. */
.price-tag .price-vat-note {
  display: block;
  font-size: 14px;
  font-weight: 500;
  color: var(--slate);
  margin-top: 4px;
}
/* In the price list rows it stays inline — those figures are small already. */
.price-vat-note { font-size: 13px; font-weight: 500; color: var(--slate); margin-left: 4px; }
.price-note {
  margin-top: 12px;
  font-size: 15px;
  font-weight: 600;
  color: var(--blue-ink);
}
/* A qualifier on a price — the dearer tier, or why there isn't one. Quiet on
   purpose: it's the small print that stops the headline figure being a
   half-truth, not a selling point competing with it. */
.price-note-quiet {
  margin-top: 10px;
  font-size: 14px;
  color: var(--slate);
}
/* Splits the pricing section into what you pay once and what you pay monthly. */
.price-group-head {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: 14px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--blue-ink);
  justify-content: center;
  margin: 0 0 22px;
}
/* Short rules either side, so the label reads as a divider between the two
   halves of the money rather than a lost heading. */
.price-group-head::before,
.price-group-head::after {
  content: "";
  height: 1px;
  width: 56px;
  background: var(--wws-line-strong);
}
.cards + .price-group-head { margin-top: 48px; }
/* No permanently highlighted card. Every card lifts on hover and none of them
   is picked out in blue by default — a card that is always highlighted stops
   reading as a highlight and just looks like the odd one out. */

/* A card that is a whole link (the "What I do" cards on the homepage). */
.card-linked {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
}
.card-linked h3, .card-linked p { color: inherit; }
.card-more {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: auto;
  padding-top: 16px;
  font-weight: 600;
  font-size: 15px;
  color: var(--blue-ink);
}
/* The arrow leans in on hover instead of the text growing an underline —
   quieter, and it reads as "go" rather than "link". */
.card-more span { transition: transform var(--wws-speed) var(--wws-ease); }
.card-linked:hover .card-more span { transform: translateX(4px); }

/* ---- the quote builder (build.php) ------------------------------------- */
.builder { max-width: 780px; margin: 0 auto; }
.bstep {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--wws-radius-lg);
  padding: 24px 26px;
  margin-bottom: 18px;
  box-shadow: var(--wws-shadow-sm);
}
.bstep h3 {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 4px; font-size: 19px; color: var(--navy);
}
.bstep-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; flex: 0 0 26px;
  border-radius: 50%; background: var(--wws-grad-blue); color: #fff;
  font-size: 14px; font-weight: 600;
}
.bstep-note { color: var(--slate); font-size: 15px; line-height: 1.55; margin: 0 0 14px; }
.bopts { display: grid; gap: 10px; margin-top: 14px; }

/* One selectable product. The whole box is the label, so the hit area is the
   card rather than a 16px circle — this gets used on phones. */
.bopt {
  display: flex; gap: 12px; align-items: flex-start;
  border: 1.5px solid var(--border); border-radius: var(--radius);
  padding: 14px 16px; cursor: pointer;
  transition: border-color var(--wws-speed-fast) var(--wws-ease),
              background var(--wws-speed-fast) var(--wws-ease),
              box-shadow var(--wws-speed-fast) var(--wws-ease);
}
.bopt:hover { border-color: var(--blue-soft); box-shadow: var(--wws-shadow-sm); }
/* Direct child only: the tick itself. Left as `.bopt input` this also sized
   the "How many?" box inside the card to 18px square. */
.bopt > input { margin-top: 3px; flex: 0 0 auto; width: 18px; height: 18px; accent-color: var(--blue); }
.bopt:has(input:checked) { border-color: var(--blue); background: #f7faff; box-shadow: 0 0 0 3px rgba(45, 125, 246, .10); }
.bopt-body { flex: 1 1 auto; min-width: 0; }
.bopt-head { display: flex; justify-content: space-between; gap: 14px; align-items: baseline; }
.bopt-name { font-weight: 600; color: var(--navy); }
.bopt-price {
  font-family: "Poppins", system-ui, sans-serif; font-weight: 700;
  color: var(--navy); white-space: nowrap;
}
.bopt-price small { font-size: 12px; font-weight: 500; color: var(--slate); }
.bopt-desc { display: block; margin-top: 4px; color: var(--slate); font-size: 14.5px; line-height: 1.55; }
.bopt-qty { display: block; margin-top: 10px; font-size: 14px; color: var(--slate); }
.bopt-qty input { width: 72px; margin-left: 6px; padding: 5px 8px; border: 1px solid var(--border); border-radius: 8px; }
/* Unavailable because of a rule — greyed with the reason, not hidden, so it's
   clear the option exists and what would unlock it. */
.bopt.is-off { opacity: .5; cursor: not-allowed; background: var(--mist); box-shadow: none; }
.bopt-why { display: block; margin-top: 6px; font-size: 13px; font-weight: 600; color: var(--blue-ink); }
/* "Something else" — a website with no price on it yet, so its price slot says
   who'll be putting one there rather than a figure. The box below it only
   opens once it's picked; [hidden] needs the override because the rule under
   it sets a display. */
.bopt-own .bopt-price { font-weight: 600; font-size: 14px; color: var(--slate); }
.bstep-own { display: block; margin-top: 12px; }
.bstep-own[hidden] { display: none; }
.bstep-own label { display: block; font-weight: 600; color: var(--navy); margin-bottom: 6px; }
.bstep-own textarea {
  width: 100%; box-sizing: border-box; font: inherit; padding: 11px 13px; margin-bottom: 10px;
  border: 1.5px solid var(--border); border-radius: var(--radius); background: #fff; color: var(--navy);
}
.bstep-own textarea:focus { outline: none; border-color: var(--blue); }
/* Sits where a price would be on the running total, saying plainly that there
   isn't one — never a £0, which would read as free. */
.bown-tbc { color: var(--slate); font-weight: 500; white-space: nowrap; }

.btotal { border-color: var(--blue); box-shadow: var(--wws-shadow-lg); }
.btotal-lines { list-style: none; margin: 10px 0 0; padding: 0; }
.btotal-lines li {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 15px;
}
.btotal-lines li:last-child { border-bottom: 0; }
.btotal-lines li.empty { color: var(--slate); justify-content: flex-start; }
.btotal-lines small { color: var(--slate); font-weight: 500; }
.btotal-sums { display: flex; gap: 28px; flex-wrap: wrap; margin-top: 16px; }
.btotal-sums div { display: flex; flex-direction: column; }
/* That `display: flex` beats the browser's own `[hidden] { display: none }`, so
   without this the full-price and discount figures sit there reading £0 when
   nobody has typed a code — a struck-through £0 next to a £0 saving looks like
   a broken offer. The two lines only ever appear when a discount is real. */
.btotal-sums div[hidden] { display: none; }
.btotal-sums span { font-size: 13px; text-transform: uppercase; letter-spacing: .06em; color: var(--slate); }
.btotal-sums strong { font-family: "Poppins", system-ui, sans-serif; font-size: 28px; color: var(--navy); }
/* The full price and what came off sit smaller than the figure they'd actually
   pay — all three are shown, but the one that matters is the one they pay. */
#sumFullWrap strong { font-size: 20px; color: var(--slate); text-decoration: line-through; }
#sumOffWrap strong { font-size: 20px; color: var(--green); }

/* The promotion code box. Whether a code exists and what it's worth are decided
   on the server — this is just where it gets typed. */
.bcoupon { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.bcoupon label { display: block; font-size: 14px; font-weight: 600; color: var(--navy); margin-bottom: 6px; }
.bcoupon-row { display: flex; gap: 8px; flex-wrap: wrap; }
.bcoupon-row input {
  flex: 1 1 180px; min-width: 0; font: inherit; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: 9px; text-transform: uppercase;
}
.bcoupon-row button {
  font: inherit; font-weight: 600; cursor: pointer; padding: 10px 20px;
  border: 1px solid var(--blue); border-radius: 9px; background: #fff; color: var(--blue-ink);
  transition: background var(--wws-speed-fast) var(--wws-ease), color var(--wws-speed-fast) var(--wws-ease);
}
.bcoupon-row button:hover { background: var(--blue); color: #fff; }
.bcoupon-note { font-size: 13.5px; line-height: 1.5; margin: 8px 0 0; }
.bcoupon-note.is-good { color: var(--green); font-weight: 600; }
.bcoupon-note.is-bad { color: var(--red); font-weight: 600; }

.bfields { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin: 14px 0 18px; }
.bfields .field-wide { grid-column: 1 / -1; }
@media (max-width: 620px) {
  .bfields { grid-template-columns: 1fr; }
  .bopt-head { flex-direction: column; gap: 2px; }
  .btotal { box-shadow: var(--wws-shadow-sm); }
}

/* On a desktop the running total leaves the flow and becomes a rail on the
   right, pinned under the header — the price stays in view the whole way down
   without sitting on top of anything. It used to stick to the viewport BOTTOM,
   which parked the entire card over the lower half of the screen. */
@media (min-width: 1000px) {
  .builder {
    max-width: none;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    column-gap: 32px;
    /* Vertical rhythm stays on .bstep's own margin. The row gap must be zero:
       the rail below spans far more rows than the form has, and a gap would
       charge for every empty one. */
    row-gap: 0;
    align-items: start;
  }
  .builder > * { grid-column: 1; }
  .builder > .btotal {
    grid-column: 2;
    /* More rows than the form will ever have, so the rail's grid area runs the
       form's full height and the panel can stick anywhere inside it. */
    grid-row: 1 / span 40;
    align-self: start;
    position: sticky;
    top: 90px; /* the 74px header, plus room to breathe */
    max-height: calc(100vh - 106px);
    overflow-y: auto;
    margin-bottom: 0;
  }
  /* Four sums in a 360px rail: smaller figures, tighter gaps, still two rows. */
  .builder > .btotal .btotal-sums { gap: 14px 22px; }
  .builder > .btotal .btotal-sums strong { font-size: 24px; }
}

/* The full published price list, under the three headline cards. Every product
   in the catalog that's flagged public appears here — the whole point is that
   nothing is held back for a phone call. Rendered by pricing.php. */
.price-list {
  max-width: 860px;
  margin: 48px auto 0;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--wws-radius-xl);
  padding: 34px clamp(20px, 4vw, 44px) 26px;
  box-shadow: var(--wws-shadow-sm);
}
.price-list-head {
  font-size: 22px;
  color: var(--navy);
  text-align: center;
  margin: 0 0 6px;
}
.price-group { margin-top: 28px; }
.price-group h4 {
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--blue-ink);
  margin: 0 0 4px;
}
.price-group-note {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  color: var(--slate);
  margin-left: 8px;
}
.price-list dl { margin: 0; }
.price-row {
  display: flex;
  align-items: baseline;
  gap: 18px;
  padding: 15px 10px;
  margin: 0 -10px;
  border-bottom: 1px solid var(--border);
  border-radius: var(--wws-radius-sm);
  transition: background var(--wws-speed-fast) var(--wws-ease);
}
/* A faint lift under the pointer keeps your place in a long list. */
.price-row:hover { background: var(--mist); }
.price-row:last-child { border-bottom: 0; }
.price-row dt { flex: 1 1 auto; margin: 0; }
.price-row dd {
  margin: 0;
  flex: 0 0 auto;
  font-family: "Poppins", system-ui, sans-serif;
  font-weight: 700;
  font-size: 20px;
  color: var(--navy);
  white-space: nowrap;
}
.price-name {
  display: block;
  font-weight: 600;
  color: var(--navy);
}
.price-desc {
  display: block;
  margin-top: 3px;
  color: var(--slate);
  font-size: 15px;
  line-height: 1.55;
}
.price-per {
  font-size: 14px;
  font-weight: 500;
  color: var(--slate);
  margin-left: 2px;
}
@media (max-width: 560px) {
  .price-row { flex-direction: column; gap: 4px; }
  .price-row dd { font-size: 18px; }
}

.price-extras {
  list-style: none;
  margin: 40px auto 0;
  padding: 0;
  max-width: 760px;
  display: grid;
  gap: 14px;
}
.price-extras li {
  color: var(--slate);
  font-size: 16px;
  line-height: 1.6;
  padding-left: 24px;
  position: relative;
}
.price-extras li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 9px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--blue);
  box-shadow: 0 0 0 3px rgba(45, 125, 246, .14);
}
.price-extras strong { color: var(--navy); }
.price-vat {
  max-width: 760px;
  margin: 22px auto 0;
  color: var(--slate);
  font-size: 15px;
  text-align: center;
}

/* Why grid */
.why-grid {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 24px;
}
.why-grid li {
  position: relative;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--wws-radius-lg);
  padding: 28px;
  box-shadow: var(--wws-shadow-sm);
  transition: transform var(--wws-speed) var(--wws-ease),
              box-shadow var(--wws-speed) var(--wws-ease),
              border-color var(--wws-speed) var(--wws-ease);
}
.why-grid li:hover {
  transform: translateY(-3px);
  box-shadow: var(--wws-shadow-md);
  border-color: #CFE0F6;
}
.why-grid h3 { font-size: 19px; font-weight: 600; }
.why-grid p { color: var(--slate); margin: 0; }
/* On why.php the grid is followed straight by the framed articles. Both are
   bordered boxes now, so without this they sit edge to edge. */
.why-grid + .prose { margin-top: 32px; }

/* ---- areas served -------------------------------------------------------
   Plain facts for people (and search engines) wondering "does he cover us?".
   Chips, not links — there are no area pages to link to, and pretending
   otherwise is how sites end up with ten thin pages saying the same thing. */
.areas { text-align: center; max-width: 720px; margin: 0 auto; }
.areas-list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin: 26px 0 0;
  padding: 0;
}
.areas-list li {
  font-family: 'Poppins', sans-serif;
  font-weight: 500;
  font-size: 14.5px;
  color: var(--navy);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--wws-radius-pill);
  padding: 8px 18px;
  box-shadow: var(--wws-shadow-sm);
}
.areas-note { color: var(--slate); font-size: 15px; margin: 18px 0 0; }

/* ---- FAQ ----------------------------------------------------------------
   Native <details>, so it works with no script and every answer is on the
   page for anyone (or any search engine) reading without clicking. */
.faq { max-width: 780px; margin: 0 auto; display: grid; gap: 12px; }
.faq details {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--wws-radius-lg);
  box-shadow: var(--wws-shadow-sm);
  padding: 0 24px;
  transition: border-color var(--wws-speed) var(--wws-ease);
}
.faq details[open] { border-color: #CFE0F6; }
.faq summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 0;
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
  font-size: 16.5px;
  color: var(--navy);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  flex: none;
  width: 12px;
  height: 12px;
  background:
    linear-gradient(var(--blue-ink), var(--blue-ink)) center / 12px 2px no-repeat,
    linear-gradient(var(--blue-ink), var(--blue-ink)) center / 2px 12px no-repeat;
  transition: transform var(--wws-speed) var(--wws-ease);
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq .faq-a { padding: 0 0 20px; color: var(--slate); line-height: 1.7; }
.faq .faq-a p { margin: 0 0 10px; }
.faq .faq-a p:last-child { margin: 0; }

/* ---- work / case studies ------------------------------------------------
   A stacked list of full-width cards, NOT a grid of tiles. With one case
   study a tile grid leaves a lonely third of a row; with two it leaves a gap.
   Stacked, the section looks finished at one and stays finished at three.

   The card is navy on a white section — the only dark thing between the hero
   and the footer. That is what stops the single piece of proof on the page
   from reading as just another row of boxes, and it's why this needs no new
   colour: it's the hero's own gradient. */
.work-list { display: grid; gap: 56px; }
.work-item { margin: 0; }
.work-card {
  display: grid;
  background: var(--wws-grad-navy);
  border-radius: var(--wws-radius-xl);
  overflow: hidden;
  box-shadow: var(--wws-shadow-md), 0 22px 48px rgba(16, 36, 62, .16);
}
/* The left half is the screenshot and nothing else. Phone first: a fixed shape
   so the card doesn't jump about as the picture loads. The desktop rule at the
   bottom hands the height over to the text column beside it. */
.work-shot {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--navy-deep);
}
.work-shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Filling a column as tall as the text opposite costs the screenshot some of
     its width. WHICH part it loses is set per case study (--shot-focus, from
     index.php), because the good bit of the next one won't be in the same
     corner. The body copy is kept deliberately tight for the same reason —
     see the note on 'summary' in index.php. */
  object-position: var(--shot-focus, top center);
}
/* Only ever seen if the screenshot didn't get uploaded. */
.work-shot-none {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 24px;
  text-align: center;
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
  color: var(--blue-soft);
}
.work-badge {
  position: absolute;
  top: 16px;
  left: 16px;
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--navy);
  background: rgba(255, 255, 255, .92);
  border-radius: var(--wws-radius-pill);
  padding: 7px 14px;
  box-shadow: var(--wws-shadow-sm);
}
/* This column sets the height of the whole card, and the card is the only tall
   thing on a white page — let it run and it reads as a slab. Everything in here
   is a notch tighter than the same element elsewhere on the site for that one
   reason, so keep an eye on the card's proportions if you change any of it. */
.work-body { padding: 30px 26px 32px; }
.work-body .eyebrow { margin-bottom: 12px; }
.work-body h3 {
  color: var(--white);
  font-size: clamp(23px, 3.1vw, 27px);
  font-weight: 600;
  margin-bottom: 10px;
}
.work-body p { color: #C7D6E8; }
.work-body > p { font-size: 15.5px; line-height: 1.6; margin-bottom: 12px; }
/* The "it's a virtual world" line. Marked out with a rule so it reads as an
   aside rather than a caveat someone tried to slip past you. */
.work-plain {
  font-size: 14.5px;
  line-height: 1.55;
  color: #A9BFD8;
  border-left: 3px solid rgba(127, 168, 220, .45);
  padding-left: 14px;
  margin: 0 0 18px;
}
/* Sized to sit on ONE row at three chips — see the note on 'tags' in
   index.php before adding a fourth. */
.work-tags {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  margin: 0 0 20px;
  padding: 0;
}
.work-tags li {
  font-family: 'Poppins', sans-serif;
  font-weight: 500;
  font-size: 13px;
  color: #DCE9FA;
  background: rgba(127, 168, 220, .14);
  border: 1px solid rgba(127, 168, 220, .28);
  border-radius: var(--wws-radius-pill);
  padding: 6px 14px;
}
/* Same treatment the hero gives a ghost button on navy. */
.work-body .btn-ghost {
  color: var(--white);
  border-color: rgba(255, 255, 255, .34);
  padding: 11px 24px;
  font-size: 15.5px;
}
.work-body .btn-ghost:hover { border-color: var(--white); color: var(--white); }
/* The client's own words, under their own case study. Centred and unboxed —
   it belongs to the card above it, and putting it in a second box would set
   the two competing instead of reading as one thing. */
.work-quote {
  max-width: 720px;
  margin: 30px auto 0;
  padding: 0 8px;
  text-align: center;
}
.work-quote blockquote { margin: 0 0 16px; }
.work-quote blockquote p {
  margin: 0;
  color: var(--navy);
  font-family: 'Poppins', sans-serif;
  font-weight: 500;
  font-size: clamp(18px, 2.4vw, 21px);
  line-height: 1.45;
}
.work-quote figcaption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 2px 12px;
}
.work-quote .testimonial-name { font-size: 15.5px; }
.work-quote-more { font-size: 14.5px; }
.work-note {
  max-width: 680px;
  margin: 44px auto 0;
  text-align: center;
  color: var(--slate);
  font-size: 15px;
}

/* 1000px, not the 860px the rest of the site switches at: side by side, the
   text column is half the card, and under about 470px of it the paragraph runs
   to five lines and the chips wrap to two rows. That makes the card half as
   tall again as it is wide and crops the screenshot to a strip. Below this it
   stacks instead — the phone layout, which has the whole width for the text. */
@media (min-width: 1000px) {
  /* Near enough half and half, tipped a touch towards the picture. The two
     pull against each other: a wider text column wraps to fewer lines, which
     makes the card shorter, which lets more of the screenshot's width survive
     the crop — but a wider picture column is more screenshot to begin with.
     This is where the two balance out. */
  .work-card { grid-template-columns: minmax(0, 1.02fr) minmax(0, 1fr); }
  .work-shot { aspect-ratio: auto; }
  .work-body { padding: 34px 38px 36px; }
}

/* Testimonials */
.testimonials {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 24px;
  align-items: start;
  max-width: 880px;
  margin: 0 auto;
}
.section-testimonials {
  background:
    radial-gradient(620px 420px at 12% 15%, rgba(45, 125, 246, .16), transparent 65%),
    radial-gradient(540px 400px at 88% 85%, rgba(127, 168, 220, .22), transparent 65%),
    var(--mist);
}
.testimonial {
  background: rgba(255, 255, 255, .55);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, .75);
  border-radius: var(--wws-radius-xl);
  padding: 36px 32px;
  margin: 0;
  box-shadow: 0 10px 30px rgba(16, 36, 62, .08);
  transition: transform var(--wws-speed) var(--wws-ease),
              box-shadow var(--wws-speed) var(--wws-ease),
              border-color var(--wws-speed) var(--wws-ease);
}
.testimonial:hover {
  transform: translateY(-4px);
  box-shadow: 0 16px 38px rgba(16, 36, 62, .12);
  border-color: rgba(255, 255, 255, .95);
}
.testimonial-quote-icon {
  width: 52px; height: 52px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(45, 125, 246, .12);
  border: 1px solid rgba(255, 255, 255, .6);
  border-radius: 14px;
  margin-bottom: 20px;
}
.testimonial blockquote { margin: 0 0 20px; }
.testimonial blockquote p { color: var(--slate); font-size: 16.5px; }
.testimonial blockquote p:last-child { margin-bottom: 0; }
.testimonial figcaption {
  border-top: 1px solid rgba(16, 36, 62, .12);
  padding-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.testimonial-name {
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
  font-size: 17px;
  color: var(--navy);
}
.testimonial-role { font-size: 14px; color: var(--slate); }

/* CTA band */
.cta-band { text-align: center; max-width: 620px; }
.cta-band h2 { font-size: clamp(26px, 4vw, 34px); font-weight: 600; }
.cta-band p { color: var(--slate); font-size: 18px; margin-bottom: 26px; }

/* Contact */
.contact-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
  align-items: start;
}
.contact-copy h2 { font-size: clamp(28px, 4vw, 36px); font-weight: 600; }
.contact-copy p { color: var(--slate); font-size: 18px; }
.contact-details { list-style: none; margin: 24px 0 0; padding: 0; }
.contact-details li { margin-bottom: 10px; font-weight: 500; }

.contact-form {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--wws-radius-xl);
  padding: 30px;
  box-shadow: var(--wws-shadow-md);
}
.field { margin-bottom: 18px; }
.field label {
  display: block;
  font-family: 'Poppins', sans-serif;
  font-weight: 500;
  font-size: 14px;
  color: var(--navy);
  margin-bottom: 7px;
}
.field .optional { font-weight: 400; color: var(--slate); }
.field input, .field textarea, .field select {
  width: 100%;
  font-family: 'Inter', sans-serif;
  font-size: 16px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--mist);
  color: var(--ink);
  box-sizing: border-box;
  transition: border-color var(--wws-speed-fast) var(--wws-ease),
              box-shadow var(--wws-speed-fast) var(--wws-ease),
              background var(--wws-speed-fast) var(--wws-ease);
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none;
  border-color: var(--blue);
  background: var(--white);
  box-shadow: var(--wws-shadow-focus);
}
.field textarea { resize: vertical; }

/* A dropdown has to lose its native skin to match the boxes above it —
   left alone, the operating system draws a squat grey control with square
   corners and its own font, which is exactly what it looked like. Losing the
   skin also loses the arrow, so one is drawn back on as a background image
   (inline, so it needs no extra file and can't 404). The right-hand padding
   keeps a long option from running underneath it. */
.field select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' viewBox='0 0 14 9' fill='none'%3E%3Cpath d='M1 1l6 6 6-6' stroke='%2352677E' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  cursor: pointer;
  /* A select and an input work their default line box out differently, so
     without this the dropdown sits a couple of pixels taller than the boxes
     above it. 20px is what an input's text occupies here, which makes the two
     exactly equal. */
  line-height: 20px;
}
/* Firefox keeps a dotted focus ring inside the control on top of ours. */
.field select:-moz-focusring { color: transparent; text-shadow: 0 0 0 var(--ink); }

.form-status { margin: 14px 0 0; font-size: 15px; font-weight: 500; min-height: 1.2em; }
.form-status.is-success { color: var(--green); }
.form-status.is-error { color: var(--red); }

.form-success {
  background: var(--white);
  border: 1px solid #BCE7D3;
  border-radius: var(--wws-radius-xl);
  padding: 40px 28px;
  text-align: center;
  box-shadow: var(--wws-shadow-md);
}
.form-success-icon {
  width: 64px; height: 64px;
  margin: 0 auto 18px;
  display: flex; align-items: center; justify-content: center;
  background: var(--wws-green-tint);
  border-radius: 50%;
}
.form-success h3 { font-size: 22px; font-weight: 600; margin-bottom: 8px; }
.form-success p { color: var(--slate); margin: 0; font-size: 16px; }

/* ---- footer -------------------------------------------------------------
   Grew from one line to a proper end of page: what I do, where to go next,
   and where I work — the last one is also the answer Google needs. */
.site-footer {
  background:
    radial-gradient(680px 420px at 88% 0%, rgba(45, 125, 246, .16), transparent 65%),
    var(--wws-grad-navy);
  color: #AEC2D9;
  padding: 64px 0 0;
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1.4fr;
  gap: 40px;
  padding-bottom: 44px;
}
.footer-about { max-width: 340px; }
.footer-logo { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.footer-logo svg { display: block; }
.footer-brand { font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 18px; color: var(--white); display: block; line-height: 1.2; }
.footer-tag { font-family: 'Poppins', sans-serif; font-weight: 500; font-size: 10px; letter-spacing: 2px; text-transform: uppercase; color: var(--blue-soft); }
.footer-about p { font-size: 14.5px; line-height: 1.7; margin: 0; }
.footer-head {
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
  font-size: 13px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--white);
  margin: 4px 0 16px;
}
.footer-nav { display: grid; gap: 10px; }
.footer-nav a { color: inherit; opacity: .85; text-decoration: none; font-size: 15px; width: fit-content; }
.footer-nav a:hover { opacity: 1; color: var(--white); text-decoration: underline; }
.footer-areas { font-size: 14.5px; line-height: 1.8; margin: 0; }
.footer-areas strong { color: var(--white); font-weight: 600; }
.footer-bottom {
  border-top: 1px solid rgba(255, 255, 255, .12);
  padding: 20px 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 20px;
  font-size: 14px;
}
.footer-bottom a { color: inherit; opacity: .85; }
.footer-bottom a:hover { opacity: 1; color: var(--white); }
/* The company particulars — a full row of their own under the © line. */
.footer-legal { flex-basis: 100%; font-size: 13px; opacity: .7; line-height: 1.7; }

/* ---- shared page furniture (partials/header.php, partials/footer.php) ---- */

/* A centred button under a section, e.g. "More on how I work". */
.section-more { text-align: center; margin: 32px 0 0; }

/* ---- long-form pages (services, why, privacy) ----
   Each article sits in its own rounded frame, the same panel language as the
   pricing page — one topic, one card. Was a run of hairline-separated blocks,
   which read as one endless page. */
.prose { max-width: 820px; margin: 0 auto; display: grid; gap: 18px; }
.svc {
  background: var(--white);
  background-image: var(--wws-grad-sheen);
  border: 1px solid var(--border);
  border-radius: var(--wws-radius-xl);
  padding: 30px 32px;
  box-shadow: var(--wws-shadow-sm);
}
.svc > :last-child { margin-bottom: 0; }
.svc .ticks:last-child { margin-bottom: 0; }
.svc h3 { font-size: 22px; color: var(--navy); margin: 0 0 6px; }
.svc p { color: var(--slate); line-height: 1.7; margin: 0 0 12px; }
.svc strong { color: var(--navy); }
.svc-price {
  font-family: "Poppins", system-ui, sans-serif;
  font-weight: 700;
  font-size: 26px;
  color: var(--navy);
  margin: 0 0 10px !important;
}
.svc-price span { font-size: 15px; font-weight: 500; color: var(--slate); }

.ticks { list-style: none; margin: 0 0 14px; padding: 0; display: grid; gap: 10px; }
.ticks li {
  position: relative;
  padding-left: 30px;
  color: var(--slate);
  line-height: 1.6;
}
/* A proper tick, drawn inline so nothing can 404, inside a soft blue chip. */
.ticks li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--blue-tint)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231D5FBF' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E")
    center / 11px no-repeat;
}
.ticks strong { color: var(--navy); }

.cta-row {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 36px;
}

/* Responsive */
@media (max-width: 900px) {
  .hero-art { display: none; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

/* The phone nav: the links collapse behind a menu button into a drop-down
   panel, the same pattern the client area and referral hub already use. The
   old behaviour was to simply hide every link, which left a phone visitor
   with no way to reach the pricing page at all. */
@media (max-width: 720px) {
  .nav-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex: none;
    padding: 0;
    background: none;
    border: 1px solid var(--border);
    border-radius: 10px;
    color: var(--navy);
    cursor: pointer;
  }
  .nav-toggle svg { display: block; }
  .site-nav {
    display: none;
    position: absolute;
    top: 74px;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    background: var(--white);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--wws-shadow-lg);
    padding: 10px 16px 16px;
  }
  .site-header.nav-open .site-nav { display: flex; }
  .site-nav a:not(.btn) { padding: 13px 10px; font-size: 16px; }
  .site-nav a:not(.btn)::after { display: none; }
  .site-nav a.is-current { background: var(--blue-tint); border-radius: 10px; }
  .site-nav .btn { margin-top: 10px; }
}

@media (max-width: 640px) {
  .hero { padding: 76px 0 84px; }
  .hero-trust { flex-direction: column; gap: 12px; }
  .section { padding: 64px 0; }
  .contact-inner { grid-template-columns: 1fr; gap: 32px; }
  .footer-grid { grid-template-columns: 1fr; gap: 32px; }
  .price-list { padding: 26px 18px 18px; }
  .svc { padding: 24px 20px; }
}
