@import url('fonts.css');

/* ==========================================================================
   PiggyBank Loans — design system
   PB Loans Limited · FRN 704303

   Tokens follow the design brief section 11. Two deliberate departures are
   documented at "Accessible colour" below: the brief's primary button spec and
   hero gradient both fail WCAG 2.2 AA for normal-size text, so an accessible
   variant of the brand pink is used wherever text sits on colour.

   THE PROMINENCE RULE — read before changing any font size.
   CONC 3.5 requires the representative APR to have greater prominence than any
   other rate or cost figure in the promotion. This build satisfies it by
   construction: no heading or display-size element may contain a pound amount
   or a rate (enforced by scripts/check-consistency.mjs), every cost figure is
   capped at --fs-cost-max, and inside the representative example band the APR
   is the only emboldened figure. If you put a price in a headline, you have
   broken the rule even though the CSS still passes.
   ========================================================================== */

:root {
  /* Brand palette — design brief section 3 */
  --colour-primary: #EA3F82;
  --colour-primary-dark: #E72474;
  --colour-pink-soft: #F67CAC;
  --colour-pink-pale: #FDC1D8;
  --colour-purple: #55218C;
  --colour-ink: #271238;
  --colour-text: #667085;
  --colour-surface: #FFF8FB;
  --colour-white: #FFFFFF;

  /* Accessible colour.
     White on --colour-primary is 3.81:1 — below the 4.5:1 AA needs for normal
     text. These darkened variants carry all text-on-colour. The brand pink is
     retained for large display type, icons and decorative fills, where 3:1
     applies. */
  --colour-primary-strong: #D22C6E;   /* white on this: 4.86:1 */
  --colour-primary-hover: #B81F5C;    /* white on this: 6.24:1 */
  --colour-link: #B81F5C;             /* on white: 6.24:1 */

  /* Hero gradient, contrast-safe and deliberately deeper than the CTA button.
     The brief's gradient starts at #EA3F82, where white text is only 3.81:1.
     This variant is darker at every stop, which does two jobs: white copy
     clears AA across the whole sweep, and the lighter --btn gradient reads as
     a distinct raised object rather than dissolving into the background.
     #B02A5F 6.34:1 · #7B2A85 8.50:1 · #3D1A66 15.2:1 */
  --gradient-hero: linear-gradient(135deg, #B02A5F 0%, #7B2A85 48%, #3D1A66 100%);
  /* Decorative only — never place text on this */
  --gradient-brand: linear-gradient(135deg, #EA3F82 0%, #B936A5 48%, #55218C 100%);

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 20px;
  --radius-xl: 28px;
  --radius-pill: 999px;

  --container-width: 1200px;
  --container-narrow: 760px;
  --section-space: clamp(56px, 8vw, 112px);

  --shadow-card: 0 12px 32px rgba(39, 18, 56, .08);
  --shadow-raised: 0 18px 44px rgba(39, 18, 56, .14);
  --border-hairline: 1px solid rgba(39, 18, 56, .08);

  --font-sans: 'Plus Jakarta Sans', ui-sans-serif, system-ui, -apple-system,
    'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  --icon-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h15M13 6l6 6-6 6'/%3E%3C/svg%3E");

  /* Type scale. See THE PROMINENCE RULE above. */
  --fs-h1: clamp(2rem, 7.5vw, 3.25rem);
  --fs-h2: clamp(1.5rem, 4.2vw, 2.25rem);
  --fs-h3: clamp(1.125rem, 2.6vw, 1.375rem);
  --fs-body: 1.0625rem;
  --fs-lead: clamp(1.0625rem, 2.2vw, 1.25rem);
  --fs-small: 0.9375rem;
  --fs-tiny: 0.8125rem;
  /* Hard ceiling for any figure expressing a price. Nothing that renders a
     pound amount or a rate may exceed this. */
  --fs-cost-max: 1.5rem;
}

/* --------------------------------------------------------------- reset */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--colour-text);
  background: var(--colour-surface);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  color: var(--colour-ink);
  line-height: 1.15;
  margin: 0 0 .5em;
  font-weight: 800;
  letter-spacing: -.02em;
  text-wrap: balance;
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); font-weight: 700; letter-spacing: -.01em; }

p { margin: 0 0 1.1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: var(--colour-link); text-underline-offset: .18em; }
a:hover { color: var(--colour-ink); }

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

/* `display: contents` removes picture's own box so the <img> inside becomes
   the direct flex/grid child. Without this, picture is a non-replaced block
   box that some engines stretch to fill a flex main-axis instead of shrinking
   to the img's content size — which silently defeats `justify-content:
   center` on any flex parent (the box being "centered" already spans the
   full container, so there is nothing left to center). */
picture { display: contents; }

ul, ol { margin: 0 0 1.1em; padding-left: 1.25em; }
li { margin-bottom: .4em; }

strong, b { font-weight: 700; color: var(--colour-ink); }

hr { border: 0; border-top: var(--border-hairline); margin: 2.5rem 0; }

:target { scroll-margin-top: 96px; }

/* Focus: visible on every interactive element, on light and dark grounds. */
:focus-visible {
  outline: 3px solid var(--colour-purple);
  outline-offset: 3px;
  border-radius: 4px;
}
.on-dark :focus-visible,
.site-header--hero :focus-visible {
  outline-color: #FFD84D;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--colour-ink);
  color: #fff;
  padding: 12px 20px;
  z-index: 200;
  border-radius: 0 0 var(--radius-md) 0;
  font-weight: 700;
}
.skip-link:focus { left: 0; color: #fff; }

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

/* --------------------------------------------------------------- layout */

.container {
  width: 100%;
  max-width: var(--container-width);
  margin-inline: auto;
  /* 24px rather than the more common 16-20px: on phones with rounded display
     corners, a right-aligned element (the header's Menu button) sitting at a
     tighter inset can read as clipped by the curve even with zero actual CSS
     overflow. */
  padding-inline: 24px;
}
@media (min-width: 700px) { .container { padding-inline: 32px; } }

.container--narrow { max-width: var(--container-narrow); }

.section { padding-block: var(--section-space); }
.section--tight { padding-block: clamp(40px, 5vw, 64px); }
.section--pale { background: var(--colour-white); }
.section--blush { background: linear-gradient(180deg, #FFF1F7 0%, var(--colour-surface) 100%); }

.section-intro { max-width: 62ch; margin-bottom: clamp(28px, 4vw, 48px); }
.section-intro > p { font-size: var(--fs-lead); }

.eyebrow {
  display: inline-block;
  font-size: var(--fs-tiny);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--colour-purple);
  margin-bottom: .75rem;
}

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

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(255, 248, 251, .92);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: var(--border-hairline);
  transition: background-color .25s ease, border-color .25s ease, box-shadow .25s ease;
}

/* Overlay header — progressive enhancement, applied by site.js.
   At the top of the page the header is transparent over the hero gradient
   with white text; once scrolled it gains the solid surface. Without JS the
   header stays in its solid sticky form above. */
.overlay-nav .site-header {
  position: fixed;
  inset-inline: 0;
  top: 0;
}
.overlay-nav main > .hero:first-child { padding-top: 72px; }
.overlay-nav .site-header:not(.is-scrolled) {
  background: transparent;
  backdrop-filter: none;
  border-bottom-color: transparent;
}
.overlay-nav .site-header:not(.is-scrolled) .brand,
.overlay-nav .site-header:not(.is-scrolled) .nav__link,
.overlay-nav .site-header:not(.is-scrolled) .nav-toggle {
  color: #fff;
}
/* the icon is an <img>, so recolour it to white with a filter */
.overlay-nav .site-header:not(.is-scrolled) .brand__icon { filter: brightness(0) invert(1); }
.overlay-nav .site-header:not(.is-scrolled) .brand__mark { color: #FDC1D8; }
.overlay-nav .site-header:not(.is-scrolled) .nav__link:hover { color: #FDC1D8; }
.overlay-nav .site-header:not(.is-scrolled) .nav__link[aria-current="page"] {
  color: #fff;
  box-shadow: inset 0 -2px 0 #FDC1D8;
}
.overlay-nav .site-header:not(.is-scrolled) .nav-toggle { border-color: rgba(255, 255, 255, .45); }
.overlay-nav .site-header:not(.is-scrolled) .btn--header {
  background: #fff;
  color: var(--colour-primary-strong);
}
.overlay-nav .site-header.is-scrolled { box-shadow: 0 6px 24px rgba(39, 18, 56, .07); }
/* Drawer opens over the gradient too — give it its solid panel regardless */
.overlay-nav .nav-drawer { background: var(--colour-white); }

.site-header__inner {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 72px;
}

/* Below 420px the wordmark, CTA and menu button no longer fit on one row, so
   the CTA moves into the drawer and the bar keeps brand + menu only. */
@media (max-width: 420px) {
  .site-header__inner { gap: 10px; min-height: 64px; }
  .site-header__inner > .btn--header { display: none; }
  .brand { font-size: 1.0625rem; }
  .brand__icon { width: 32px; }
}
.nav-drawer__cta { display: none; }
@media (max-width: 420px) {
  .nav-drawer__cta { display: block; margin-top: 16px; }
  .nav-drawer__cta .btn { width: 100%; }
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  font-weight: 800;
  font-size: 1.25rem;
  letter-spacing: -.03em;
  color: var(--colour-ink);
  margin-right: auto;
  flex-shrink: 0;
}
.brand:hover { color: var(--colour-ink); }
.brand__icon { width: 38px; color: var(--colour-primary); flex-shrink: 0; }
.brand__mark { color: var(--colour-primary-strong); }

.nav { display: none; }
.nav__list {
  display: flex;
  align-items: center;
  gap: clamp(4px, 1.4vw, 20px);
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav__link {
  display: block;
  padding: 8px 6px;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--colour-ink);
  text-decoration: none;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}
.nav__link:hover { color: var(--colour-primary-strong); }
.nav__link[aria-current="page"] {
  color: var(--colour-primary-strong);
  box-shadow: inset 0 -2px 0 var(--colour-primary-strong);
}

.nav-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 8px 14px;
  font: inherit;
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--colour-ink);
  background: transparent;
  border: 1px solid rgba(39, 18, 56, .18);
  border-radius: var(--radius-md);
  cursor: pointer;
}
.nav-toggle__bars { width: 18px; height: 2px; background: currentColor; position: relative; }
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: ""; position: absolute; left: 0; width: 18px; height: 2px; background: currentColor;
}
.nav-toggle__bars::before { top: -6px; }
.nav-toggle__bars::after { top: 6px; }

/* Icon-only below 480px. Dropping the "Menu" label shrinks the button and
   gives real clearance from the screen edge — on a phone with rounded
   display corners, a wide pill sitting close to a 20px inset can still read
   as clipped even with no actual CSS overflow. The label stays in the
   accessible name via aria-label on the button itself. */
@media (max-width: 480px) {
  .nav-toggle { padding: 0; width: 44px; justify-content: center; }
  .nav-toggle__label { display: none; }
}

/* Declared after .nav / .nav-toggle so it actually wins the cascade — an
   earlier copy of this block was overridden by the base display rules. */
@media (min-width: 980px) {
  .nav { display: block; }
  .nav-toggle { display: none !important; }
}

/* Mobile drawer. Hidden with [hidden] so it is unavailable to AT when closed. */
.nav-drawer {
  border-top: var(--border-hairline);
  background: var(--colour-white);
  padding: 12px 0 20px;
}
.nav-drawer[hidden] { display: none; }
.nav-drawer__list { list-style: none; margin: 0; padding: 0; }
.nav-drawer__list a {
  display: block;
  padding: 13px 4px;
  font-weight: 600;
  color: var(--colour-ink);
  text-decoration: none;
  border-bottom: var(--border-hairline);
}
.nav-drawer__list a[aria-current="page"] { color: var(--colour-primary-strong); }
@media (min-width: 980px) { .nav-drawer { display: none !important; } }

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 52px;
  padding: 14px 28px;
  font: inherit;
  font-size: var(--fs-body);
  font-weight: 700;
  line-height: 1.2;
  text-decoration: none;
  text-align: center;
  border: 2px solid transparent;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background .18s ease, color .18s ease, transform .18s ease,
    border-color .18s ease, box-shadow .18s ease;
}

/* Primary — gradient pill.
   Every stop clears 4.5:1 against white text: #D22C6E 4.86:1, #A32E93 6.23:1,
   #7C2BA8 7.62:1. The gradient is deliberately deeper than --gradient-hero so
   the button still reads as a distinct object sitting on the hero. */
.btn--primary {
  background-image: linear-gradient(135deg, #D22C6E 0%, #A32E93 55%, #7C2BA8 100%);
  background-size: 160% 160%;
  background-position: 0% 50%;
  color: #fff;
  box-shadow: 0 10px 26px rgba(160, 40, 120, .34);
}
.btn--primary:hover {
  color: #fff;
  background-position: 100% 50%;
  transform: translateY(-2px);
  box-shadow: 0 14px 32px rgba(160, 40, 120, .44);
}
.btn--primary:active { transform: translateY(0); }

/* Secondary — outlined pill that fills solid white on hover. */
.btn--secondary {
  background: transparent;
  color: var(--colour-ink);
  border-color: rgba(39, 18, 56, .28);
}
.btn--secondary:hover {
  background: var(--colour-ink);
  border-color: var(--colour-ink);
  color: #fff;
  transform: translateY(-2px);
}

/* On dark grounds: white outline, filling to solid white with dark text. */
.on-dark .btn--secondary,
.hero .btn--secondary,
.cta-band .btn--secondary {
  color: #fff;
  border-color: rgba(255, 255, 255, .6);
  background: transparent;
}
.on-dark .btn--secondary:hover,
.hero .btn--secondary:hover,
.cta-band .btn--secondary:hover {
  background: #fff;
  border-color: #fff;
  color: var(--colour-ink);
  transform: translateY(-2px);
  box-shadow: 0 12px 28px rgba(39, 18, 56, .26);
}

.btn--ghost-light { background: #fff; color: var(--colour-ink); border-color: #fff; }
.btn--ghost-light:hover { background: #fff; color: var(--colour-primary-strong); transform: translateY(-2px); }

/* Trailing arrow, drawn as a masked SVG so it never depends on a font glyph
   (U+2192 is outside the latin subset we self-host). */
.btn--arrow::after {
  content: "";
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  background: currentColor;
  -webkit-mask: var(--icon-arrow) center / contain no-repeat;
  mask: var(--icon-arrow) center / contain no-repeat;
  transition: translate .18s ease;
}
.btn--arrow:hover::after { translate: 4px 0; }

.btn-row { display: flex; flex-wrap: wrap; gap: 14px; }
@media (max-width: 560px) {
  .btn-row { flex-direction: column; align-items: stretch; }
  .btn-row .btn { width: 100%; }
}

.btn--header {
  min-height: 44px;
  padding: 10px 20px;
  font-size: var(--fs-small);
  box-shadow: 0 6px 16px rgba(160, 40, 120, .3);
}
.btn--header:hover { transform: translateY(-1px); }

/* --------------------------------------------------------------- hero */

.hero {
  position: relative;
  background: var(--gradient-hero);
  color: #fff;
  overflow: hidden;
}
.hero::after {
  /* soft light bloom, purely decorative */
  content: "";
  position: absolute;
  inset: auto -10% -40% 40%;
  height: 70%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, .16), transparent);
  pointer-events: none;
}
.hero h1, .hero h2, .hero h3 { color: #fff; }
.hero__inner {
  position: relative;
  z-index: 1;
  display: grid;
  gap: clamp(24px, 5vw, 48px);
  padding-block: clamp(48px, 7vw, 88px);
  align-items: center;
}
@media (min-width: 900px) {
  .hero__inner { grid-template-columns: 48% 52%; min-height: 560px; }
}

/* Inner-page hero carrying a mascot: shorter than the homepage so the page's
   own content starts higher up. */
.hero--page .hero__inner { padding-block: clamp(40px, 5.5vw, 64px); }

/* Cap height as well as width, WITHOUT distorting aspect ratio. This must be
   max-width + max-height with width/height left auto — not an explicit
   `width` alongside `max-height`. When width is an explicit (non-auto) value,
   CSS clips height to max-height WITHOUT recomputing width to compensate,
   which non-uniformly stretched every image narrower than the 460:392 target
   ratio (coin, support, contact) to fill the full width while their height
   was capped — a real distortion bug, not a sizing preference: the coin pig
   was being stretched ~30% wider than its native proportions. Clipboard
   looked "correct" purely because its native ratio (847:721) is close to
   460:392, so the bug was invisible there.
   With width/height auto + both max-* bounds, the browser scales each image
   uniformly to fit both constraints (the smaller resulting scale wins) —
   standard "contain" behaviour. Reference is the clipboard pig's own natural
   size at these bounds (460x392, width-bound, untouched); every other
   mascot lands on the same 392px-tall footprint at its own true aspect
   ratio: coin 352x392, aboutus 428x392, support 367x392, complaints
   397x392, contact 360x392. */
.hero--page .hero__figure img { width: auto; max-height: 392px; }
@media (min-width: 900px) {
  .hero--page .hero__inner { grid-template-columns: 54% 46%; min-height: 400px; }
  .hero--page .hero__figure img { max-width: min(100%, 460px); }
}

/* `.hero--page .hero__figure img` is more specific than the generic mobile
   rules further down this file, so it needs its own mobile overrides or it
   would fall back to the universal max-width:100% reset.

   These must be max-HEIGHT-led, not width-led. On phones the mascot is
   always width-bound against the viewport, and each source crop carries a
   different amount of prop reaching sideways (coin held out from the body,
   support's floating heart+sparkle) versus the pig itself — matching outer
   canvas WIDTH across images does not match the pig's visual size, because a
   taller/narrower canvas (coin, support) forced to the same width as the
   wide clipboard canvas renders visibly taller. Confirmed empirically: at an
   identical 216px width, clipboard measured 184px tall, coin 240px, support
   230px — the two the client flagged as oversized. Binding by height instead
   (184px, clipboard's own already-correct mobile size) fixes this exactly
   the same way the desktop rule is height-bound: coin 165x184, support
   172x184, aboutus 201x184, complaints 186x184, contact 169x184. */
@media (max-width: 899px) {
  .hero--page .hero__figure img { max-height: 272px; max-width: 320px; }
}
@media (max-width: 560px) {
  .hero--page .hero__figure img { max-height: 184px; max-width: 250px; }
}

/* Heroes with no mascot — text spans the full width. */
.hero--simple .hero__inner { grid-template-columns: 1fr; }
@media (min-width: 900px) {
  .hero--simple .hero__inner { min-height: 0; }
}
.hero--simple .hero__lead { max-width: 62ch; }

.hero .eyebrow { color: var(--colour-pink-pale); }

/* Utilities, replacing per-page inline styles so spacing stays consistent. */
.btn-row--spaced { margin-top: 26px; }
.grid--split { align-items: start; gap: clamp(32px, 5vw, 64px); }

.hero__lead {
  font-size: var(--fs-lead);
  color: rgba(255, 255, 255, .93);
  max-width: 46ch;
}

.hero__badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px 7px 11px;
  margin-bottom: 20px;
  font-size: var(--fs-tiny);
  font-weight: 700;
  letter-spacing: .02em;
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: var(--radius-pill);
}
.hero__badge svg { width: 15px; flex-shrink: 0; }

.hero__points {
  list-style: none;
  margin: 28px 0 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
.hero__points li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: var(--fs-small);
  color: rgba(255, 255, 255, .93);
  margin: 0;
}
.hero__points svg { width: 18px; flex-shrink: 0; margin-top: 3px; }

.hero__caveat {
  margin-top: 18px;
  font-size: var(--fs-tiny);
  color: rgba(255, 255, 255, .78);
}

/* Mascot. Native asset is 486x542px, so display width is capped at 480px and
   it is never upscaled. Replace with the designer's 2000px file when supplied
   and this cap can be lifted. */
.hero__figure {
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  position: relative;
}
.hero__figure img {
  width: min(100%, 480px);
  height: auto;
  filter: drop-shadow(0 26px 34px rgba(39, 18, 56, .34));
}
.hero__figure::before {
  content: "";
  position: absolute;
  bottom: 4%;
  left: 50%;
  translate: -50% 0;
  width: min(70%, 320px);
  height: 26px;
  background: radial-gradient(closest-side, rgba(39, 18, 56, .34), transparent);
  filter: blur(3px);
}

/* Brief section 6: on mobile the mascot must not push the message down, so it
   is ordered after the headline, CTA and supporting copy. Text and buttons
   are centred to match the centred mascot below them — a left-edge headline
   sitting above a centred pig reads as misaligned. */
@media (max-width: 899px) {
  .hero__inner { grid-template-columns: 1fr; }
  .hero__content { text-align: center; }
  .hero__lead { margin-inline: auto; }
  .hero__badge { margin-inline: auto; }
  .hero__points { text-align: left; max-width: 320px; margin-inline: auto; }
  .btn-row { justify-content: center; }
  .hero__figure { order: 2; }
  .hero__figure img { width: min(72%, 320px); }
  .hero__points { order: 3; }
}

@media (max-width: 560px) {
  .hero__inner { padding-block: 36px 44px; gap: 18px; }
  .hero__figure img { width: min(66%, 250px); }
  .hero__lead { font-size: 1.0625rem; }
  .hero__points { margin-top: 20px; }
  .hero__caveat { margin-top: 14px; }
}

/* Very narrow devices: the stacked headline is the one thing that must not
   overflow, so it drops below the clamp floor here. */
@media (max-width: 360px) {
  .hero h1 { font-size: 1.75rem; }
  .container { padding-inline: 16px; }
  .btn { padding-inline: 20px; font-size: 1rem; }
}

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

.card {
  background: var(--colour-white);
  border: var(--border-hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: clamp(22px, 3vw, 30px);
  transition: transform .25s ease, box-shadow .25s ease;
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-raised);
}
.card h3 { margin-bottom: .4em; }
.card p:last-child { margin-bottom: 0; }

.grid { display: grid; gap: clamp(16px, 2.4vw, 24px); }
.grid--2 { grid-template-columns: 1fr; }
.grid--3 { grid-template-columns: 1fr; }
.grid--4 { grid-template-columns: 1fr; }

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

/* Numbered steps */
.steps { counter-reset: step; list-style: none; padding: 0; margin: 0; }
.steps > li { counter-increment: step; margin: 0; }
.step__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  margin-bottom: 14px;
  font-size: 1.0625rem;
  font-weight: 800;
  color: #fff;
  background: var(--colour-purple);
  border-radius: var(--radius-md);
}

/* --------------------------------------------------------------- tables */

.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-radius: var(--radius-lg);
  border: var(--border-hairline);
  background: var(--colour-white);
  box-shadow: var(--shadow-card);
}

table { border-collapse: collapse; width: 100%; min-width: 640px; }
caption {
  text-align: left;
  padding: 18px 20px 0;
  font-size: var(--fs-small);
  color: var(--colour-text);
}
th, td {
  padding: 13px 16px;
  text-align: left;
  border-bottom: 1px solid rgba(39, 18, 56, .07);
  font-size: var(--fs-small);
}
thead th {
  font-size: var(--fs-tiny);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--colour-purple);
  background: #FDF3F8;
  white-space: nowrap;
}
tbody tr:last-child td { border-bottom: 0; }
tbody tr:nth-child(even) { background: #FFFBFD; }

/* The emphasised "total repayable" column. Capped by --fs-cost-max so it can
   never approach the APR. */
td.is-total, th.is-total { color: var(--colour-ink); font-weight: 800; }
td.is-total { font-size: min(1.0625rem, var(--fs-cost-max)); }

.table-key { display: grid; gap: 10px; margin: 20px 0 0; padding: 0; list-style: none; }
.table-key li { margin: 0; font-size: var(--fs-small); }

/* Definition-style product table */
.spec-table th { width: 46%; color: var(--colour-ink); text-transform: none; letter-spacing: 0; font-size: var(--fs-small); background: transparent; }
.spec-table { min-width: 480px; }

/* --------------------------------------------------------------- FAQ */

.faq { display: grid; gap: 12px; }
.faq details {
  background: var(--colour-white);
  border: var(--border-hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 17px 20px;
  min-height: 48px;
  font-weight: 700;
  color: var(--colour-ink);
  cursor: pointer;
  list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  flex-shrink: 0;
  width: 11px; height: 11px;
  border-right: 2.5px solid var(--colour-primary-strong);
  border-bottom: 2.5px solid var(--colour-primary-strong);
  rotate: 45deg;
  transition: rotate .18s ease;
}
.faq details[open] summary::after { rotate: -135deg; }
.faq .faq__body { padding: 0 20px 18px; }

/* --------------------------------------------------------------- callouts */

.callout {
  border-left: 4px solid var(--colour-purple);
  background: #F7F1FC;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  padding: 18px 22px;
  margin: 1.5rem 0;
}
.callout--warning { border-left-color: var(--colour-primary-strong); background: #FFF1F6; }
.callout h3 { margin-bottom: .3em; }

/* Risk warning — content pack section 8.2 */
.risk-warning {
  background: var(--colour-ink);
  color: rgba(255, 255, 255, .92);
}
.risk-warning p {
  margin: 0;
  padding-block: 15px;
  font-size: var(--fs-small);
}
.risk-warning strong { color: #fff; }
.risk-warning a { color: #FFD84D; }
.risk-warning a:hover { color: #fff; }

/* --------------------------------------------------------------- CTA band */

.cta-band {
  background: var(--gradient-hero);
  color: #fff;
  text-align: center;
}
.cta-band h2 { color: #fff; }
.cta-band p { color: rgba(255, 255, 255, .93); max-width: 52ch; margin-inline: auto; }
.cta-band .btn-row { justify-content: center; margin-top: 26px; }

/* ==========================================================================
   REPRESENTATIVE EXAMPLE BAND — content pack section 6
   Renders on every page, immediately above the footer. Never inside an
   accordion, tab or scroll reveal. Must survive print.

   One sentence, one font size. Within the band the APR is the only bold
   figure, and no heading anywhere on the site may carry a cost figure, so the
   APR remains the most prominent cost figure on the page. The compliance
   sign-off should confirm this presentation meets CONC 3.5 — see
   CONTENT-TO-CONFIRM.md.
   ========================================================================== */

.rep-example {
  background: var(--colour-purple);
  color: #fff;
  border-top: 4px solid var(--colour-primary);
}

.rep-example__inner { padding-block: clamp(22px, 3vw, 34px); }

.rep-example p {
  margin: 0;
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: #fff;
  max-width: 92ch;
}
.rep-example__label { font-weight: 800; color: #FDC1D8; }
.rep-example__apr { font-weight: 800; color: #fff; white-space: nowrap; }

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

.site-footer {
  background: var(--colour-ink);
  color: rgba(255, 255, 255, .74);
  font-size: var(--fs-small);
}
.site-footer a { color: rgba(255, 255, 255, .82); text-decoration: none; }
.site-footer a:hover { color: #fff; text-decoration: underline; }

.footer__grid {
  display: grid;
  gap: clamp(28px, 4vw, 44px);
  padding-block: clamp(40px, 5vw, 64px);
  grid-template-columns: 1fr;
}
@media (min-width: 640px) { .footer__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 940px) { .footer__grid { grid-template-columns: 1.3fr 1fr 1fr 1.2fr; } }

.footer__heading {
  font-size: var(--fs-tiny);
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #fff;
  margin: 0 0 14px;
}
.footer__list { list-style: none; margin: 0; padding: 0; }
.footer__list li { margin-bottom: 9px; }

.footer__brand { display: inline-flex; align-items: center; gap: 10px; color: #fff; font-weight: 800; font-size: 1.125rem; text-decoration: none; margin-bottom: 14px; }
.footer__brand:hover { text-decoration: none; }
.footer__brand svg { width: 34px; color: var(--colour-pink-soft); }

.footer__legal {
  border-top: 1px solid rgba(255, 255, 255, .14);
  padding-block: 28px 40px;
  font-size: var(--fs-tiny);
  line-height: 1.7;
  color: rgba(255, 255, 255, .62);
}
.footer__legal p { margin-bottom: .9em; max-width: 92ch; }
.footer__legal p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------- cookie banner
   Non-blocking bottom banner — never traps focus or covers the whole page,
   since there is currently nothing on this site that requires consent before
   it runs. Accept and Reject are equal size and equal visual weight: a
   reject option that's harder to find or use than accept is exactly what UK
   ICO guidance treats as non-compliant. */
.cookie-banner {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 150;
  background: var(--colour-ink);
  color: #fff;
  box-shadow: 0 -10px 28px rgba(0, 0, 0, .2);
  padding-bottom: env(safe-area-inset-bottom, 0);
}
.cookie-banner[hidden] { display: none; }

.cookie-banner__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-block: 18px;
}

.cookie-banner__text {
  margin: 0;
  max-width: 62ch;
  font-size: var(--fs-small);
  color: rgba(255, 255, 255, .92);
}
.cookie-banner__text a { color: #FFD84D; }
.cookie-banner__text a:hover { color: #fff; }

.cookie-banner__actions { display: flex; gap: 12px; flex-wrap: wrap; }
.cookie-banner__btn { min-height: 44px; padding-block: 11px; }

.cookie-banner .btn--secondary { color: #fff; border-color: rgba(255, 255, 255, .5); }
.cookie-banner .btn--secondary:hover { background: #fff; color: var(--colour-ink); border-color: #fff; }

@media (max-width: 640px) {
  .cookie-banner__inner { flex-direction: column; align-items: stretch; text-align: center; }
  .cookie-banner__actions { justify-content: center; }
  .cookie-banner__btn { flex: 1 1 auto; }
}

/* --------------------------------------------------------------- forms */

.form { display: grid; gap: 20px; max-width: 620px; }

.field { display: grid; gap: 7px; }
.field > label {
  font-weight: 700;
  color: var(--colour-ink);
  font-size: var(--fs-small);
}
.field__hint { font-size: var(--fs-tiny); color: var(--colour-text); }

.field input,
.field select,
.field textarea {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  font: inherit;
  font-size: var(--fs-body);
  color: var(--colour-ink);
  background: var(--colour-white);
  border: 1.5px solid rgba(39, 18, 56, .22);
  border-radius: var(--radius-md);
}
.field textarea { min-height: 150px; resize: vertical; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: rgba(39, 18, 56, .4); }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--colour-purple); }

.field--check { grid-template-columns: auto 1fr; align-items: start; gap: 12px; }
.field--check input { width: 22px; min-height: 22px; height: 22px; margin-top: 2px; }
.field--check label { font-weight: 500; color: var(--colour-text); }

.field__error {
  font-size: var(--fs-small);
  font-weight: 700;
  color: #B3123C;
}
.field input[aria-invalid="true"],
.field textarea[aria-invalid="true"],
.field select[aria-invalid="true"] { border-color: #B3123C; }

/* Honeypot — off-screen rather than display:none so bots still fill it. */
.hp-field {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px; overflow: hidden;
}

.form-status { border-radius: var(--radius-md); padding: 16px 18px; font-weight: 600; }
.form-status--ok { background: #E9F7EF; color: #10502F; border: 1px solid #A8DCC0; }
.form-status--error { background: #FDECEF; color: #8A0F30; border: 1px solid #F3B6C2; }
.form-status[hidden] { display: none; }

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

.prose { max-width: 72ch; }
.prose h2 { margin-top: 2.2em; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { margin-top: 1.8em; }
.prose ul { padding-left: 1.2em; }

.token {
  background: #FFF0B3;
  color: #6B4C00;
  font-weight: 700;
  padding: 1px 7px;
  border-radius: 5px;
  border: 1px dashed #C9A227;
  font-size: .95em;
  white-space: nowrap;
}

.contact-list { list-style: none; padding: 0; margin: 0 0 1.5em; display: grid; gap: 12px; }
.contact-list li {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  align-items: baseline;
}
.contact-list strong { min-width: 8.5em; }
/* The value can be a long comma-separated string (phone + hours); it must be
   able to shrink and wrap rather than force the row wider than the viewport —
   a flex item's default min-width is content-based ("auto"), which is what
   was pushing this past 375px on Complaints/Contact at 320-390px. */
.contact-list li > span { min-width: 0; flex: 1 1 14em; }

/* --------------------------------------------------------------- motion */

/* Scroll reveal — the .reveal class is added by site.js, so content is fully
   visible without JavaScript. */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .55s ease, transform .55s ease;
}
.reveal.in-view { opacity: 1; transform: none; }

/* The pig gently bobs. Killed by the reduced-motion block below. */
@keyframes mascot-float {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50% { transform: translateY(-12px) rotate(-1.2deg); }
}
.hero__figure img { animation: mascot-float 5.5s ease-in-out infinite; }

@keyframes shadow-breathe {
  0%, 100% { opacity: 1; scale: 1; }
  50% { opacity: .72; scale: .92 1; }
}
.hero__figure::before { animation: shadow-breathe 5.5s ease-in-out infinite; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .btn--primary:hover { transform: none; }
}

/* --------------------------------------------------------------- print */

@media print {
  .site-header, .nav-drawer, .cta-band, .skip-link, .hero__figure { display: none !important; }

  body { background: #fff; color: #000; font-size: 11pt; }
  .hero { background: #fff !important; color: #000; }
  .hero h1, .hero h2, .hero__lead, .hero__points li { color: #000 !important; }

  /* The representative example must survive print — content pack 6.2. */
  .rep-example {
    background: #fff !important;
    color: #000 !important;
    border: 2pt solid #000;
    page-break-inside: avoid;
    break-inside: avoid;
    margin-top: 12pt;
  }
  .rep-example p, .rep-example__label, .rep-example__apr { color: #000 !important; }

  .site-footer { background: #fff !important; color: #000; }
  .site-footer a, .footer__legal { color: #000 !important; }
  .risk-warning { background: #fff !important; color: #000 !important; border: 1pt solid #000; }
  .risk-warning a { color: #000 !important; }

  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; }
  .table-scroll { overflow: visible; box-shadow: none; }
  .faq details { break-inside: avoid; }
  .faq details:not([open]) .faq__body { display: block; }   /* print answers too */
}

/* --------------------------------------------------------------- guard

   Regression guard for THE PROMINENCE INVARIANT.

   These are the computed sizes at the extremes. If you change --fs-apr or
   --fs-h1, recheck them and re-run `npm run check`:

     viewport   --fs-h1                --fs-apr               APR larger?
     320px      max(32, 24)   = 32px   max(44, 35.2) = 44px   yes
     420px      max(32, 31.5) = 32px   max(44, 46.2) = 46px   yes
     768px      max(32, 57.6) = 52px*  max(44, 84.5) = 84px   yes
     1280px     capped        = 52px   capped        = 88px   yes
     * capped by the 3.25rem ceiling

   Nothing else on the site may render a cost figure above --fs-cost-max.
   ------------------------------------------------------------------------ */
