/* =====================================================================
   Daniella Gilbertson | site.css
   One shared stylesheet for every page. Direction "A + grafts", one-page layout (2026-10-23).

   The Home page is one page (index.html) that is also the blueprint for a hand-built Wix
   page: from 1000px every size and space is a fixed px value inside a 980px content width
   (the Wix Editor grid), and the photographic effects are baked into image files.

   CONTENTS
    0. Fonts (self-hosted + metric-matched fallbacks)
    1. Tokens
    2. Reset and base
    3. Accessibility utilities (skip link, .vh, focus)
    4. Layout: .wrap (980px content), .grid, sections and bands
    5. Typography scale
    6. Marks, icons, dove
    7. Buttons and links
    8. Quotes and attribution
    9. Site header
   10. Mobile navigation
   11. Site footer + contact definition list
   12. One page: shared section pieces (.h2, .split)
   13. Opening (#top)
   14. About (#about)
   15. Testimonials (#testimonials): carousel controls + slide track
   16. Client logos (in the testimonials section)
   17. Closing quotes band (fade slideshow)
   18. Contact (#contact)
   19. Inner pages: page header, plate, sand panel, prose (Privacy, 404)
   20. Forms
   21. Page: Privacy & GDPR
   22. Reduced motion and print

   Breakpoints (mobile first): 420, 560, 700 (md), 1000 (lg: full nav, desktop layout).
   ===================================================================== */


/* =====================================================================
   0. FONTS
   ===================================================================== */
@font-face {
  font-family: "Newsreader";
  src: url("../fonts/newsreader-roman-latin.woff2") format("woff2");
  font-weight: 300 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  src: url("../fonts/newsreader-italic-latin.woff2") format("woff2");
  font-weight: 300 500;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("../fonts/hanken-grotesk-latin.woff2") format("woff2");
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
}
/* Fallbacks tuned to the real fonts (measured in Chrome) to limit layout shift during swap. */
@font-face {
  font-family: "Newsreader Fallback";
  src: local("Georgia");
  font-weight: 300;
  font-style: normal;
  size-adjust: 97.2%;
  ascent-override: 76.1%;
  descent-override: 27.8%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Newsreader Fallback";
  src: local("Georgia");
  font-weight: 400 500;
  font-style: normal;
  size-adjust: 100.6%;
  ascent-override: 73.6%;
  descent-override: 26.8%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Newsreader Fallback";
  src: local("Georgia Italic"), local("Georgia-Italic");
  font-weight: 300 500;
  font-style: italic;
  size-adjust: 90.6%;
  ascent-override: 81.7%;
  descent-override: 29.8%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Hanken Grotesk Fallback";
  src: local("Arial"), local("ArialMT");
  size-adjust: 100.5%;
  ascent-override: 99.5%;
  descent-override: 29.9%;
  line-gap-override: 0%;
}


/* =====================================================================
   1. TOKENS
   ===================================================================== */
:root {
  /* Colour */
  --paper: #F5F0E7;          /* main ground, header, footer, mobile menu */
  --paper-2: #ECE4D6;        /* sand bands and panels */
  --field: #FBF8F2;          /* form field fill only */
  --ink: #1B2420;            /* headings and body */
  --ink-soft: #4E5651;       /* secondary text, labels */
  --green: #1F3A35;          /* dark bands, primary buttons */
  --green-deep: #18302B;     /* photo grades, pressed state */
  --on-dark: #F4EEE4;        /* text on green and photos */
  --on-dark-soft: #C9C4B8;   /* secondary text on green */
  --accent: #D97A2B;         /* DECORATIVE ONLY: hairlines, dashes, ticks, never text */
  --accent-ink: #A24E16;     /* small accent text + focus ring on light grounds */
  --accent-light: #EFA25F;   /* accent text + focus ring on green / photos */
  --rule: rgba(27, 36, 32, .16);
  --rule-dark: rgba(244, 238, 228, .22);
  --rule-photo: rgba(244, 238, 228, .62);      /* carousel button edges over a photo scrim */
  --rule-photo-soft: rgba(244, 238, 228, .3);  /* progress track over a photo scrim */
  --field-border: #787E79;   /* 3.3:1 on the sand panel, 3.9:1 on the field fill */
  --error: #9E3A26;
  --selection: #F2D3B3;

  /* Families */
  --serif: "Newsreader", "Newsreader Fallback", Georgia, "Times New Roman", serif;
  --sans: "Hanken Grotesk", "Hanken Grotesk Fallback", Arial, Helvetica, sans-serif;

  /* Type scale */
  --fs-display-l: clamp(2.25rem, 1.2rem + 3.3vw, 4.5rem);
  --fs-quote: clamp(1.375rem, 1rem + 1.2vw, 2rem);
  --fs-lead: 1.1875rem;      /* 19px phones, 20px from 700, 22px from 1000 */
  --fs-h3: clamp(1.5rem, 1.3rem + .6vw, 1.875rem);
  --fs-body: 1.0625rem;      /* 17px; 18px from 1000px */
  --fs-credential: .9375rem;
  --fs-label: .75rem;
  --fs-tagline: .6875rem;    /* 11px: the floor for any text */
  --fs-meta: .875rem;
  --fs-ui: .9375rem;


  /* Layout */
  --wrap-max: calc(980px + 2 * var(--gutter)); /* content never wider than the 980px Wix grid */
  --gutter: clamp(20px, 5vw, 72px);
  --col-gap: clamp(16px, 2vw, 28px);
  --space: 72px;             /* section padding: 72 phones, 88 from 700, 104 from 1000 */
  --space-sm: clamp(48px, 5vw, 80px);
  --header-h: 76px;
  --measure: 36rem;          /* body copy */
  --measure-lead: 31em;      /* leads */
  --measure-quote: 30em;     /* testimonials */

  /* Motion */
  --ease: cubic-bezier(.25, .1, .25, 1);
  --dur: .25s;
}
@media (min-width: 700px) {
  :root { --space: 88px; --fs-lead: 1.25rem; }
}
@media (min-width: 1000px) {
  :root { --space: 104px; --fs-lead: 1.375rem; --col-gap: 28px; }
}
@media (max-width: 999px) {
  :root { --header-h: 68px; }
}


/* =====================================================================
   2. RESET AND BASE
   ===================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html {
  color-scheme: light;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: calc(var(--header-h) + 16px);
}
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
html.nav-locked { overflow: hidden; }

body {
  margin: 0;
  min-width: 320px;
  overflow-x: clip;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.65;
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
@media (min-width: 1000px) {
  body { font-size: 1.125rem; }
}

h1, h2, h3, h4, p, ul, ol, dl, dd, figure, blockquote, address { margin: 0; }
h1, h2, h3, h4 { font-weight: inherit; font-size: inherit; text-wrap: balance; }
p, li, dd { text-wrap: pretty; }
ul, ol { padding: 0; list-style: none; }
address { font-style: normal; }
/* The hidden attribute always wins over a component's display value (.form, .form-success ...). */
[hidden] { display: none !important; }
img, svg, picture, video { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }
strong, b { font-weight: 600; }
::selection { background: var(--selection); color: var(--ink); }


/* =====================================================================
   3. ACCESSIBILITY UTILITIES
   ===================================================================== */
/* Visually hidden but read by screen readers. */
.vh {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip {
  position: absolute;
  left: var(--gutter);
  top: -200px;
  z-index: 100;
  padding: 12px 18px;
  background: var(--ink);
  color: var(--paper);
  font-size: var(--fs-ui);
  font-weight: 500;
  text-decoration: none;
  border-radius: 2px;
}
.skip:focus { top: 12px; }

main:focus { outline: none; }

:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 4px;
}
:is(.band-green, .closing) :focus-visible { outline-color: var(--accent-light); }


/* =====================================================================
   4. LAYOUT
   ===================================================================== */
.wrap {
  width: 100%;
  max-width: var(--wrap-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* 12 columns at every width (footer, inner-page headers, Privacy). Children span the full row
   unless a component places them. */
.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
}
.grid > * { grid-column: 1 / -1; min-width: 0; }

@media (max-width: 999px) {
  .lg-only { display: none !important; }
}


/* Section padding and grounds */
.section { padding-block: var(--space); }

.band-sand { background: var(--paper-2); }
.band-green { background: var(--green); color: var(--on-dark); }


/* =====================================================================
   5. TYPOGRAPHY SCALE
   ===================================================================== */
/* Page titles on Privacy and 404. */
.display-l {
  font-family: var(--serif);
  font-weight: 300;
  font-size: var(--fs-display-l);
  line-height: 1.03;
  letter-spacing: -.022em;
  text-wrap: balance;
}
.display-l em { font-style: italic; font-weight: inherit; }

.lead {
  font-family: var(--serif);
  font-weight: 400;
  font-size: var(--fs-lead);
  line-height: 1.5;
  max-width: var(--measure-lead);
  text-wrap: wrap;           /* plain wrapping, as in a Wix text box (no-break spaces guard the last words) */
}
.h3 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: var(--fs-h3);
  line-height: 1.18;
  letter-spacing: -.01em;
}

.quote-testimonial {
  font-family: var(--serif);
  font-style: normal;
  font-weight: 400;
  font-size: var(--fs-quote);
  line-height: 1.42;
  max-width: var(--measure-quote);
}

.label {
  font-family: var(--sans);
  font-weight: 600;
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.label--accent { color: var(--accent-ink); }
.band-green .label { color: var(--on-dark); }
.band-green .label--accent { color: var(--accent-light); }
.meta { font-size: var(--fs-meta); line-height: 1.5; color: var(--ink-soft); }

/* Keeps a hyphenated compound whole at a line end (self-awareness, PCI-DSS ...). */
.nowrap { white-space: nowrap; }


/* =====================================================================
   6. MARKS, ICONS, DOVE
   ===================================================================== */
/* 56 x 1px accent hairline that opens a block (section headings, inner-page headers). */
.mark {
  display: block;
  width: 56px;
  height: 1px;
  background: var(--accent);
  margin-bottom: 28px;
}
@media (min-width: 1000px) { .mark { margin-bottom: 36px; } }
.icon {
  width: 22px;
  height: 22px;
  flex: none;
  color: var(--ink-soft);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.42;        /* viewBox units: 1.3 x 24 / size, so every size draws 1.3px */
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Dove used as a section mark (on light grounds use logo-dove.png, on sand/green logo-dove-clean-180.png). */
.dove-mark { width: 56px; height: auto; }


/* =====================================================================
   7. BUTTONS AND LINKS
   ===================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  min-height: 54px;
  padding: 0 28px;
  background: var(--green);
  color: var(--paper);
  border: 1px solid var(--green);
  border-radius: 2px;
  font-family: var(--sans);
  font-size: var(--fs-ui);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: .02em;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.btn:hover { background: var(--ink); border-color: var(--ink); }
.btn:active { background: var(--green-deep); border-color: var(--green-deep); }
.btn .arr {
  width: 22px;
  height: 10px;
  flex: none;
  transition: transform var(--dur) var(--ease);
}
.btn:hover .arr { transform: translateX(4px); }
.btn--sm { min-height: 44px; padding: 0 20px; font-size: .875rem; }
.btn--block { display: flex; width: 100%; justify-content: space-between; }


/* Body links inside running text. */
.prose a:not(.btn) {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--accent-ink);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: text-decoration-color var(--dur) var(--ease);
}
.prose a:not(.btn):hover { text-decoration-color: currentColor; }


/* =====================================================================
   8. QUOTES AND ATTRIBUTION
   ===================================================================== */
/* Attribution: accent em dash, then the name in label style.
   <figcaption class="cite"><span class="cite__dash" aria-hidden="true">—</span> Name</figcaption> */
.cite {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 24px;
  font-family: var(--sans);
  font-style: normal;
  font-weight: 600;
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.cite__dash { color: var(--accent); font-weight: 400; letter-spacing: 0; }
.band-green .cite,
.band-green .cite__dash { color: var(--accent-light); }

/* Opening quote mark that hangs outside the text edge. Only from 1000px, where a column gap
   sits to the left; below that the text edge is the page gutter, which the mark never enters. */
@media (min-width: 1000px) { .hang { margin-left: -.4em; } }


/* =====================================================================
   9. SITE HEADER (identical on all pages)
   ===================================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid var(--rule);
}
/* The translucent backdrop lives on a pseudo-element so the header never becomes
   the containing block of the fixed mobile menu. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(245, 240, 231, .95);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
.site-header.is-open::before { background: var(--paper); }

.header-inner {
  display: flex;
  align-items: center;
  gap: clamp(16px, 2.4vw, 36px);
  min-height: var(--header-h);
}

.brand {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
  min-height: 44px;
  margin-right: auto;
  color: var(--ink);
  text-decoration: none;
}
.brand__mark { width: 50px; height: auto; flex: none; }
.brand__text { display: flex; flex-direction: column; min-width: 0; }
.brand__name {
  font-family: var(--serif);
  font-weight: 400;
  font-size: 1.4rem;
  line-height: 1.1;
  letter-spacing: -.005em;
  white-space: nowrap;
}
.brand__tags {
  margin-top: 5px;
  font-family: var(--sans);
  font-weight: 600;
  font-size: var(--fs-tagline);
  line-height: 1.3;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  white-space: nowrap;
}
.brand__tags > span + span::before {
  content: "";
  display: inline-block;
  width: 3px;
  height: 3px;
  margin: 0 .7em 0 .55em;
  border-radius: 50%;
  background: var(--accent);
  vertical-align: .3em;
}

/* Desktop navigation */
.primary-nav__list { display: flex; align-items: center; gap: clamp(20px, 2.2vw, 34px); }
.primary-nav__list a {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: 4px;       /* widens the target of short labels to 44px+ ... */
  margin-inline: -4px;       /* ... without moving them */
  color: var(--ink);
  font-size: var(--fs-ui);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}
.primary-nav__list a::after {
  content: "";
  position: absolute;
  left: 4px;
  right: 4px;
  bottom: 8px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .3s var(--ease);
}
.primary-nav__list a:hover::after { transform: scaleX(1); }
.primary-nav__list a[aria-current="page"]::after { transform: scaleX(1); background: var(--accent); }
@media (forced-colors: active) {
  /* The underline is a drawn background, which forced colours would erase. */
  .primary-nav__list a::after,
  .primary-nav__list a[aria-current="page"]::after { forced-color-adjust: none; background: LinkText; }
}
.primary-nav__extra { display: none; }

.header-actions { display: flex; align-items: center; gap: 4px; }
.header-contact {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  color: var(--ink);
}
.header-contact .icon { width: 22px; height: 22px; color: inherit; } /* inherit: forced colours can recolour it */

.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  margin-right: -12px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 2px;
  color: var(--ink);
  cursor: pointer;
}
.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  display: block;
  width: 24px;
  height: 1.5px;
  background: currentColor;
  transition: transform .3s var(--ease), background-color .2s var(--ease);
}
.nav-toggle__bars { position: relative; }
.nav-toggle__bars::before,
.nav-toggle__bars::after { content: ""; position: absolute; left: 0; }
.nav-toggle__bars::before { top: -7px; }
.nav-toggle__bars::after { top: 7px; }
.is-open .nav-toggle__bars { background: transparent; }
.is-open .nav-toggle__bars::before { transform: translateY(7px) rotate(45deg); }
.is-open .nav-toggle__bars::after { transform: translateY(-7px) rotate(-45deg); }
/* High contrast: forced colours reset backgrounds, which would erase the drawn bars and X. */
@media (forced-colors: active) {
  .nav-toggle__bars,
  .nav-toggle__bars::before,
  .nav-toggle__bars::after { forced-color-adjust: none; background: ButtonText; }
  .is-open .nav-toggle__bars { background: transparent; }
}

@media (min-width: 1000px) and (max-width: 1099px) {
  /* Keep the full nav comfortable just above the breakpoint: stack the tagline. */
  .brand__tags { display: flex; flex-direction: column; gap: 2px; }
  .brand__tags > span + span::before { display: none; }
}
@media (max-width: 999px) {
  .brand__mark { width: 44px; }
  .brand__name { font-size: 1.25rem; }
}
@media (max-width: 699px) {
  .header-cta { display: none; }
  .header-contact { display: inline-flex; }
}
@media (max-width: 560px) {
  .brand { gap: 12px; }
  .brand__tags { display: flex; flex-direction: column; gap: 1px; margin-top: 5px; }
  .brand__tags > span + span::before { display: none; }
}
@media (max-width: 420px) {
  .brand { gap: 10px; }
  .brand__mark { width: 40px; }
  .brand__name { font-size: 1.1875rem; }
  .brand__tags { letter-spacing: .1em; }
  /* May wrap only when a reader's own text spacing (WCAG 1.4.12) makes it too wide, rather
     than running under the call link; at default spacing everything still fits on one line. */
  .brand__name,
  .brand__tags { white-space: normal; }
}
@media (max-width: 359px) {
  .header-inner { column-gap: 8px; } /* room for the tagline, so it never needs to wrap by default */
  .brand { gap: 7px; }
  .brand__mark { width: 32px; }
  .brand__name { font-size: 1.125rem; }
  .brand__tags { letter-spacing: .04em; }
  .header-actions { gap: 0; }
  .nav-toggle { margin-right: -14px; }
}


/* =====================================================================
   10. MOBILE NAVIGATION (under 1000px, JS on)
   ===================================================================== */
@media (max-width: 999px) {
  .js .nav-toggle { display: inline-flex; }
  .js .primary-nav {
    position: fixed;
    top: calc(var(--header-h) + 1px);
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 49;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 8px var(--gutter) 48px;
    background: var(--paper);
    opacity: 0;
    visibility: hidden;
    transition: opacity .2s var(--ease), visibility 0s linear .2s;
  }
  .js .is-open .primary-nav {
    opacity: 1;
    visibility: visible;
    transition: opacity .2s var(--ease), visibility 0s;
  }
  .js .primary-nav__list,
  .js .primary-nav__extra { max-width: 36rem; }
  .js .primary-nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  .js .primary-nav__list li { border-bottom: 1px solid var(--rule); }
  .js .primary-nav__list a {
    display: flex;
    margin: 0;
    padding: 16px 0;
    font-family: var(--serif);
    font-size: 1.75rem;
    font-weight: 400;
    line-height: 1.2;
    letter-spacing: -.005em;
    white-space: normal;
  }
  .js .primary-nav__list a::after { display: none; }
  /* Current page: colour plus an underline, so it never relies on colour alone. */
  .js .primary-nav__list a[aria-current="page"] {
    color: var(--accent-ink);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 7px;
  }
  .js .primary-nav__extra { display: block; margin-top: 32px; }
  .primary-nav__contact { display: flex; flex-direction: column; margin-top: 20px; }
  .primary-nav__contact a {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    min-height: 44px;
    color: var(--ink-soft);
    font-size: 1rem;
    text-decoration: none;
  }
  .primary-nav__contact a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 4px; }

  /* Without JS the links sit in a row under the brand. The brand row keeps the header height
     (not the whole wrapped block), so the brand stays vertically centred in it. */
  .no-js .header-inner { flex-wrap: wrap; row-gap: 0; min-height: 0; }
  .no-js .brand,
  .no-js .header-actions { min-height: var(--header-h); }
  .no-js .primary-nav { order: 3; flex-basis: 100%; border-top: 1px solid var(--rule); }
  .no-js .primary-nav__list { flex-wrap: wrap; gap: 0 22px; }
}


/* =====================================================================
   11. SITE FOOTER + CONTACT DEFINITION LIST
   ===================================================================== */
.site-footer {
  padding-top: clamp(56px, 6vw, 88px);
  padding-bottom: 32px;
  background: var(--paper);
}
.footer-grid { row-gap: 44px; }
.footer-brand__mark { width: 64px; height: auto; }
.footer-brand__name {
  margin-top: 20px;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.9rem, 1.5rem + 1.2vw, 2.6rem);
  line-height: 1.05;
  letter-spacing: -.015em;
}
.footer-brand__tags { display: flex; flex-direction: column; margin-top: 12px; line-height: 1.9; }
.footer-heading { margin-bottom: 10px; }
.footer-nav a {
  display: inline-flex;
  align-items: center;
  min-width: 44px;
  min-height: 44px;
  color: var(--ink);
  font-size: 1rem;
  line-height: 1.4;
  text-decoration: none;
}
.footer-nav a:hover,
.contact-dl a:hover { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 5px; }
/* Current page: a persistent accent underline, as in the header nav. */
.footer-nav a[aria-current="page"] {
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 5px;
}
.footer-bottom {
  margin-top: clamp(44px, 5vw, 72px);
  padding-top: 24px;
  border-top: 1px solid var(--rule);
}
@media (min-width: 560px) {
  .footer-nav { grid-column: 1 / span 6; }
  .footer-contact { grid-column: 7 / span 6; }
}
@media (min-width: 1000px) {
  .site-footer { padding-top: 88px; }
  .footer-brand__name { font-size: 2.5rem; }       /* 40px */
  .footer-bottom { margin-top: 72px; }
  .footer-brand { grid-column: 1 / span 5; }
  .footer-nav { grid-column: 7 / span 3; }
  .footer-contact { grid-column: 10 / span 3; }
}

/* Contact definition list: footer size by default, .contact-dl--lg on the Contact page.
   <dl class="contact-dl">
     <div class="contact-dl__row"><dt class="label">Phone</dt><dd><a href="tel:...">[icon] number</a></dd></div>
   </dl> */
.contact-dl__row + .contact-dl__row { margin-top: 10px; }
/* Footer size: quiet sentence-case term so it does not stutter against the column heading. */
.contact-dl dt { color: var(--ink-soft); font-size: var(--fs-meta); line-height: 1.4; }
.contact-dl a {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  color: var(--ink);
  font-size: 1rem;
  line-height: 1.3;
  text-decoration: none;
  overflow-wrap: anywhere;
}
.contact-dl a .icon { width: 18px; height: 18px; stroke-width: 1.73; }
.contact-dl--lg { border-bottom: 1px solid var(--rule); }
.contact-dl--lg .contact-dl__row { padding: 20px 0 14px; border-top: 1px solid var(--rule); }
.contact-dl--lg .contact-dl__row + .contact-dl__row { margin-top: 0; }
.contact-dl--lg dt {
  margin-bottom: 4px;
  font-family: var(--sans);
  font-weight: 600;
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.contact-dl--lg a { gap: 14px; font-family: var(--serif); font-size: 1.625rem; font-weight: 400; letter-spacing: -.005em; }
.contact-dl--lg a .icon { width: 24px; height: 24px; stroke-width: 1.3; }


/* =====================================================================
   12. ONE PAGE: SHARED SECTION PIECES
   Every value at 1000px and up is a fixed px value, so the page can be rebuilt by hand in
   the Wix Editor (980px grid) from the numbers in the Wix spec.
   ===================================================================== */
/* Section headings (How I can help, My approach, Working together, Let's start a conversation). */
.h2 {
  font-family: var(--serif);
  font-weight: 300;
  font-size: 2.125rem;       /* 34px phones */
  line-height: 1.1;
  letter-spacing: -.015em;
  text-wrap: balance;
}
@media (min-width: 700px) { .h2 { font-size: 2.5rem; } }     /* 40px */
@media (min-width: 1000px) { .h2 { font-size: 2.75rem; } }   /* 44px */

/* Heading left, short text right: How I can help, Working together. */
.split { display: grid; row-gap: 24px; }
.split__body > * + * { margin-top: 20px; }
.split__body .lead { max-width: 30em; }
/* Column lines at 1000px and up (x inside the 980px grid, all on the 12-col grid with 28px gaps):
   252 = col 4 (testimonials, logos), 420 = col 6 (split + About text, Contact intro ends 84px
   before 504), 504 = col 7 (opening panel, Contact form, footer Quick Links). */
@media (min-width: 1000px) {
  .split { grid-template-columns: 336px minmax(0, 1fr); column-gap: 84px; align-items: start; }   /* text at x420 */
  /* The first line of the text sits level with the heading (mark 1px + 36px above it). */
  .split__body { padding-top: 36px; }
}


/* =====================================================================
   13. OPENING (#top)
   Text column + lone-tree panel. The panel image already carries the grade that makes the
   quote readable (assets/img/sky-tree-hero-wix-*.jpg, made by the bake_wix_images.py tool).
   Phones: text, then the 4:5 panel. 700-999: text, then a 3:2 panel. 1000+: text | 476x595 panel at x504.
   ===================================================================== */
.opening { padding-top: 32px; padding-bottom: var(--space); }
.opening__grid { display: grid; row-gap: 40px; }
.opening__title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.875rem, 10vw, 2.75rem);   /* 32px at 320, 39px at 390 (scales like Wix mobile) */
  line-height: 1.06;
  letter-spacing: -.022em;
  text-wrap: balance;
}
.opening__title em { display: block; font-style: italic; }
.opening__lead { margin-top: 24px; color: var(--ink); }
.opening__body { margin-top: 16px; max-width: 30em; }
.opening__cta { margin-top: 32px; }

.opening__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  aspect-ratio: 4 / 5;
  margin: 0;
  padding: min(6.15vw, 24px);  /* phones scale like the Wix 320px mobile canvas: 20px at 320, 24px at 390 */
  overflow: hidden;
  background: var(--green-deep);
  color: var(--on-dark);
}
.opening__panel picture,
.opening__panel img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.opening__panel img { object-fit: cover; }
.opening__quote,
.opening__panel .cite { position: relative; }
.opening__quote p {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(.9375rem, 4.87vw, 1.1875rem);  /* phones: 15.6px at 320, 19px at 390 */
  line-height: 1.3;
  letter-spacing: -.01em;
  max-width: 17em;     /* even 2-3 line rag at every width, never one line across the 3:2 panel */
  text-wrap: balance;
}
.opening__quote .hang { margin-left: -.38em; }
.opening__panel .cite { margin-top: 16px; color: var(--on-dark); }
.opening__panel .cite__dash { color: var(--accent-light); }

@media (min-width: 700px) {
  .opening { padding-top: 48px; }
  .opening__title { font-size: 3rem; }             /* 48px */
  .opening__panel { aspect-ratio: 3 / 2; padding: 40px; }
  .opening__quote p { font-size: 1.5rem; }         /* 24px */
  .opening__panel .cite { margin-top: 20px; }
}
/* Tablets: break the first sentence as on desktop ("...space to reflect / can help you see a way forward."). */
@media (min-width: 700px) and (max-width: 999px) {
  .opening__lead { max-width: 21em; }
}
@media (min-width: 1000px) {
  .opening { padding-bottom: var(--space); }
  .opening__grid {
    /* 456 | 48 | 476 in the 980px grid: panel at x504 (col 7). The text column stays 456 wide so
       the first sentence still breaks "...space to reflect / can help you see a way forward." */
    grid-template-columns: minmax(0, 1fr) 48.5714%;
    column-gap: 4.898%;
    align-items: center;
  }
  .opening__title { font-size: min(3.25rem, 4.6vw); }   /* 52px from 1130px wide */
  .opening__lead { margin-top: 28px; }
  .opening__cta { margin-top: 36px; }
  .opening__panel { aspect-ratio: 4 / 5; padding: 36px; }
}


/* =====================================================================
   14. ABOUT (#about): My approach + portrait + qualifications
   The arch and its offset orange outline are baked into daniella-portrait-arch.png/.webp.
   ===================================================================== */
.about__grid { display: grid; row-gap: 48px; }
.about__portrait { max-width: 280px; }
.about__portrait img { width: 100%; }
.about__lead { margin-top: 24px; color: var(--ink); }
.about__text { margin-top: 16px; max-width: 32em; }
.about__quals-title { margin-top: 40px; }
.quals { margin-top: 12px; max-width: 30em; }
.quals li {
  position: relative;
  padding: 11px 0 11px 30px;
  border-top: 1px solid var(--rule);
  color: var(--ink);
  font-size: var(--fs-credential);
  font-weight: 500;
  line-height: 1.45;
}
.quals li:last-child { border-bottom: 1px solid var(--rule); }
.quals li::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(11px + .725em);
  width: 16px;
  height: 1px;
  background: var(--accent);
}
@media (min-width: 700px) {
  .about__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); column-gap: 48px; align-items: center; }
  .about__portrait { max-width: 354px; }
}
@media (min-width: 1000px) {
  .about__grid { grid-template-columns: 336px minmax(0, 1fr); column-gap: 84px; }   /* text at x420 */
}


/* =====================================================================
   15. CAROUSELS: SHARED CONTROLS AND TESTIMONIALS (site.js section 3)
   Root [data-carousel style="--n:<slides>"]; track [data-carousel-track]; slides
   [data-carousel-slide]; buttons [data-carousel-prev]/[data-carousel-next]; counter
   [data-carousel-current]; progress fill [data-carousel-progress]; live region
   [data-carousel-status]. The track is a scroll-snap strip that glides; it is always as
   tall as the longest testimonial, so nothing below it moves between slides.
   ===================================================================== */
/* Shared controls: [prev] 01 / 09 [next], then the progress hairline.
   <div class="carousel-controls">
     <div class="carousel-controls__row">
       <button class="carousel-btn" data-carousel-prev ...>svg</button>
       <p class="carousel-count" aria-hidden="true"><b data-carousel-current>01</b> / 09</p>
       <button class="carousel-btn" data-carousel-next ...>svg</button>
     </div>
     <div class="carousel-progress" aria-hidden="true"><span class="carousel-progress__fill" data-carousel-progress></span></div>
   </div> */
.carousel-controls { display: none; width: max-content; }
.js .carousel-controls { display: block; }
.carousel-controls__row { display: flex; align-items: center; gap: 12px; }
.carousel-btn {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  background: transparent;
  color: var(--on-dark);
  border: 1px solid var(--rule-dark);
  border-radius: 2px;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.carousel-btn:hover { background: var(--on-dark); color: var(--green); border-color: var(--on-dark); }
.carousel-btn svg { width: 20px; height: 10px; }
/* Play / pause for an autoplaying carousel: set a little apart from the arrows. The root
   gets .is-paused from site.js, which swaps the pause bars for the play triangle. */
.carousel-toggle { margin-right: 12px; }
.carousel-toggle svg { width: 14px; height: 14px; }
.carousel-toggle__play,
.is-paused .carousel-toggle__pause { display: none; }
.is-paused .carousel-toggle__play { display: block; }
.carousel-count {
  min-width: 76px;
  text-align: center;
  color: var(--on-dark-soft);
  font-size: .8125rem;
  font-weight: 500;
  letter-spacing: .14em;
  font-variant-numeric: tabular-nums;
}
.carousel-count b { font-weight: 600; color: var(--on-dark); }
.carousel-progress {
  position: relative;
  height: 1px;
  margin-top: 18px;
  overflow: hidden;
  background: var(--rule-dark);
}
.carousel-progress__fill {
  position: absolute;
  inset: 0;
  background: var(--accent-light);
  transform: scaleX(calc(1 / var(--n, 9)));
  transform-origin: left center;
  transition: transform .45s var(--ease);
}
/* Over a photograph (closing band): the button edge is drawn at 3:1 or more against the
   scrim under it (--rule-dark, at .22, cannot reach 3:1 on any ground) and the counter is
   set in --on-dark throughout. */
.carousel-controls--photo .carousel-btn { border-color: var(--rule-photo); }
.carousel-controls--photo .carousel-btn:hover { border-color: var(--on-dark); }
.carousel-controls--photo .carousel-count { color: var(--on-dark); text-shadow: 0 1px 10px rgba(0, 0, 0, .35); }
.carousel-controls--photo .carousel-progress { background: var(--rule-photo-soft); }
/* A soft dark halo under the focus ring keeps it at 3:1 or more where it crosses the sun's glint. */
.carousel-controls--photo .carousel-btn:focus-visible { box-shadow: 0 0 0 8px rgba(14, 20, 17, .55); }
@media (forced-colors: active) {
  /* The fill is a drawn background, which forced colours would erase. */
  .carousel-progress__fill { forced-color-adjust: none; background: Highlight; }
}

/* --- Testimonials section ------------------------------------------- */
.testimonials { --hang-room: 0px; padding-block: var(--space); }
.t-grid { display: flex; flex-direction: column; gap: 32px; }
.t-aside { display: contents; }
.t-title { order: 1; color: var(--on-dark); }
.t-controls { order: 2; }
.t-main { order: 3; min-width: 0; }

.t-track {
  display: flex;
  align-items: flex-start;
  gap: 64px;
  margin-left: calc(-1 * var(--hang-room));
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  transition: opacity .18s var(--ease);
}
.t-track::-webkit-scrollbar { display: none; }
.t-track.is-animating { scroll-snap-type: none; }
.t-track.is-fading { opacity: 0; }
.t-track:focus-visible { outline-offset: 8px; }
.t-slide {
  flex: 0 0 100%;
  margin: 0;
  padding-left: var(--hang-room);
  scroll-snap-align: start;
}
.t-slide .quote-testimonial { color: var(--on-dark); }
.t-slide .cite { margin-top: 28px; }
@media (min-width: 1000px) { .t-slide .hang { margin-left: -.42em; } }
/* Under 1000px the controls sit above the track, so each quote is centred vertically in the
   fixed-height track (as tall as the longest quote): the spare space splits above and below
   rather than leaving a dead band under the short first slide. From 1000px the quote top stays
   level with the "What My Clients Say" label beside it. */
@media (max-width: 999px) {
  .t-track { align-items: stretch; }
  .t-slide { display: flex; flex-direction: column; justify-content: center; }
}

/* Without JS: every testimonial is listed. */
.no-js .t-track { display: block; overflow: visible; margin-left: 0; }
.no-js .t-slide { padding-left: 0; }
.no-js .t-slide + .t-slide { margin-top: 44px; padding-top: 44px; border-top: 1px solid var(--rule-dark); }

@media (min-width: 1000px) {
  .testimonials { --hang-room: .6em; }
  .t-track { font-size: 1.875rem; }                 /* 30px quotes */
  .t-slide .quote-testimonial { font-size: 1em; }
}
/* The one long testimonial (LA - London, 73 words) steps down to .86 of the others, so the
   track (as tall as its tallest slide) keeps the height it had and short quotes don't float. */
.t-slide--long .quote-testimonial { font-size: calc(var(--fs-quote) * .86); }
@media (min-width: 1000px) { .t-slide--long .quote-testimonial { font-size: .86em; } }   /* 25.8px */
@media (min-width: 1000px) {
  .t-grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--col-gap);
  }
  .t-aside {
    grid-column: 1 / span 3;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 32px;
  }
  .t-main { grid-column: 4 / -1; padding-top: 4px; }
}

/* =====================================================================
   16. CLIENT LOGOS (own light strip directly under the green testimonials)
   Full corporate colours (client-*-colour.png), no filter. The strip is
   paper so every brand colour (incl. NEX black, Disney navy) reads.
   ===================================================================== */
.clients-strip {
  padding-block: 44px;
  border-bottom: 1px solid var(--rule);
}
.clients {
  display: grid;
  row-gap: 28px;
}
.logos {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 28px 40px;
}
.logos img { width: auto; height: var(--h, 28px); }
@media (max-width: 559px) {
  .clients__title { text-align: center; }
  .logos { max-width: 300px; margin-inline: auto; gap: 26px 36px; }
}
/* High contrast: set the colour logos on small white tiles so they never vanish. */
@media (forced-colors: active) {
  .logos li { forced-color-adjust: none; background: #fff; padding: 6px 10px; border-radius: 2px; }
}
@media (min-width: 560px) {
  .logos { justify-content: space-between; }
}
@media (min-width: 1000px) {
  .clients {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--col-gap);
    align-items: center;
  }
  .clients-strip { padding-block: 52px; }
  .clients__title { grid-column: 1 / span 3; }
  .logos { grid-column: 4 / -1; flex-wrap: nowrap; gap: 32px; }
}


/* =====================================================================
   17. CLOSING QUOTES (full-bleed sunset band, fade slideshow)
   The scrim is baked into sunset-closing-wix-*.jpg, so the text sits straight on the image.
   ===================================================================== */
.closing {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 440px;
  margin: 0;
  padding: 72px var(--gutter);
  overflow: hidden;
  background: var(--green-deep);
  color: var(--on-dark);
  text-align: center;
}
.closing picture,
.closing img {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
}
.closing img { object-fit: cover; object-position: 50% 50%; }
.closing__quote p {
  max-width: 18em;
  margin-inline: auto;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 350;
  font-size: 1.75rem;        /* 28px phones */
  line-height: 1.2;
  letter-spacing: -.012em;
  text-wrap: balance;
}
.closing .cite { justify-content: center; margin-top: 24px; color: var(--on-dark); }
.closing .cite__dash { color: var(--accent-light); }
@media (min-width: 700px) {
  .closing { min-height: 520px; padding-block: 96px; }
  .closing__quote p { font-size: 2.25rem; }        /* 36px */
}
@media (min-width: 1000px) {
  .closing { min-height: 560px; }
  .closing__quote p { max-width: 760px; font-size: 2.5rem; line-height: 1.18; }   /* 40px */
  .closing .cite { margin-top: 28px; }
}

/* --- Quote slideshow (fade mode, site.js section 3) ------------------
   <div class="quote-show closing__show" data-carousel data-carousel-mode="fade" data-carousel-label="Quotation" style="--n:10">
     <div class="quote-show__track" id="closing-quotes" data-carousel-track role="region" aria-roledescription="carousel" aria-label="Quotations" tabindex="0">
       <figure class="closing__quote quote-show__slide is-active" data-carousel-slide role="group" aria-roledescription="slide" aria-label="1 of 10">...</figure>
       ...
     </div>
     <div class="carousel-controls carousel-controls--photo">...</div>
     <p class="vh" aria-live="polite" data-carousel-status></p>
   </div>
   All slides sit in one grid cell, so the track always takes the height of the longest
   quote at the current width and nothing below it moves between quotes. The first slide
   carries .is-active in the markup, so the page is right before site.js runs. */
.quote-show__track { display: grid; }
/* Vertical strokes still scroll the page and pinch still zooms; site.js takes horizontal
   swipes. Without JS the strip below scrolls natively, so nothing is locked there. */
.js .quote-show__track { touch-action: pan-y pinch-zoom; }
.quote-show__slide { grid-area: 1 / 1; min-width: 0; margin: 0; }
/* 300ms fade in (after 40ms) over a 220ms fade out: a 340ms cross-fade in all. */
.js .quote-show__slide { transition: opacity .3s var(--ease) .04s, visibility 0s; }
.js .quote-show__slide:not(.is-active) {
  opacity: 0;
  visibility: hidden;
  transition: opacity .22s var(--ease), visibility 0s linear .22s;
}
.quote-show__track:focus-visible { outline-offset: 2px; box-shadow: 0 0 0 8px rgba(14, 20, 17, .62), inset 0 0 0 3px rgba(14, 20, 17, .62); }

/* Without JS: every quote is kept, as a native scroll-snap strip (swipe, trackpad, the
   thin scrollbar, or arrow keys once the strip has focus). */
.no-js .quote-show__track {
  display: flex;
  align-items: stretch;
  gap: 48px;
  padding-bottom: 14px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  scrollbar-color: rgba(244, 238, 228, .55) transparent;
}
.no-js .quote-show__slide { flex: 0 0 100%; scroll-snap-align: start; }

/* Closing band: the quote, then the controls centred under it. */
.closing__show {
  width: 100%;
  max-width: 60rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(40px, 4vw, 48px);
}
.closing__show .quote-show__track { width: 100%; align-items: center; }
/* The two long quotes (Ryan Holiday, Tagore's verse) set the shared quote area's height.
   Below 1000px they step down a size, so the short quotes don't float in a tall empty band. */
/* Verse (Tagore) keeps its lines; each line still wraps, balanced, on narrow screens. */
.closing__quote .ln { display: block; }
.closing__quote--long p { font-size: 1.5rem; }                                  /* 24px */
@media (min-width: 700px) { .closing__quote--long p { font-size: 2rem; } }       /* 32px */
@media (min-width: 1000px) { .closing__quote--long p { font-size: 2.5rem; } }    /* 40px, as the rest */


/* =====================================================================
   18. CONTACT (#contact)
   Phones / tablets: intro + details, then the form. 1000+: intro | form (420 | 84 | 476, form at x504).
   ===================================================================== */
.contact__grid { display: grid; row-gap: 56px; }
/* The form needs JS to send (the address isn't in the source), so without JS only the details show. */
.no-js .contact__form { display: none; }
.contact__lead { margin-top: 24px; color: var(--ink); }
.contact__details { margin-top: 36px; }
.contact__form-title { margin-bottom: 28px; }
/* Content-to-button rhythm: 36px above the submit button (24px grid gap + 12px). */
.contact-form__actions { margin-top: 12px; }
@media (min-width: 1000px) {
  .contact__grid { grid-template-columns: minmax(0, 1fr) 476px; column-gap: 84px; align-items: start; }
  .contact__form { padding-top: 40px; }            /* cap height level with the h2 beside it */
  .contact__form-title { font-size: 1.875rem; }    /* 30px */
}


/* =====================================================================
   19. INNER PAGES: PAGE HEADER, PLATE, SAND PANEL, PROSE (Privacy, 404)
   ===================================================================== */
/* Shared inner-page header.
   <header class="page-head">
     <div class="wrap">
       <div class="grid page-head__inner">
         <div class="page-head__main">
           <span class="mark" aria-hidden="true"></span>
           <h1 class="display-l">Contact <em>Me</em></h1>
           (optional) <p class="label label--accent page-head__label">...</p>
           (optional) <div class="page-head__intro">...lead + body...</div>
           (optional) <div class="page-head__actions"><a class="btn" ...>...</a></div>
         </div>
         (optional, 1000px+) <div class="page-head__plate plate plate--1x1 plate--tint">picture</div>
       </div>
     </div>
   </header>
   The plate is hidden under 1000px and sits above the fold on desktop, so it is never lazy-loaded.
   Both <source> elements carry media="(min-width: 1000px)" and the <img> fallback is a 1x1
   transparent GIF data URI: desktop fetches the plate straight away, narrower screens fetch nothing.
   With a plate (What My Clients Say, 404) the heading block is centred on the square plate, so
   the header reads as one composed band rather than a heading at the foot of an empty column;
   without one (Contact, Privacy) the block simply sits under the top padding, as before. */
.page-head { padding-top: clamp(48px, 6vw, 96px); }
.page-head__inner {
  row-gap: 40px;
  align-items: center;
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid var(--rule);
}
.page-head__label { margin-top: clamp(16px, 2vw, 24px); }

.page-head__actions { margin-top: clamp(32px, 3.4vw, 40px); }
.page-head__plate { display: none; }
@media (min-width: 1000px) {
  .page-head__main { grid-column: 1 / span 7; }
  /* Square (cols 9-12), and on short laptop screens the plate gives up height so the first
     line of content still shows above the fold (1366x768: on What My Clients Say the client
     logo strip shows in full). */
  .page-head__plate {
    display: block;
    grid-column: 9 / span 4;
    width: 100%;               /* a definite width, so a capped height crops instead of narrowing */
    max-height: max(360px, calc(100vh - 360px));
    max-height: max(360px, calc(100svh - 360px));
  }
}

/* Closes the last block of an inner page with a hairline inside the wrap, mirroring the
   page header's closing hairline, so the paper footer always has a clean edge. */
.page-end {
  padding-bottom: var(--space);
  border-bottom: 1px solid var(--rule);
}

/* Plate: an image inside the grid, square corners.
   <div class="plate plate--4x5"><picture>...<img ...></picture></div> */
.plate { position: relative; overflow: hidden; margin: 0; background: var(--green-deep); }
.plate picture { display: block; width: 100%; height: 100%; }
.plate img { width: 100%; height: 100%; object-fit: cover; }

.plate--1x1 { aspect-ratio: 1 / 1; }


/* Sand panel (contact form panel, ICO address). */
.panel-sand { padding: clamp(28px, 4vw, 56px); background: var(--paper-2); }

.panel-sand--compact { padding: 28px; }

/* Long-form text (Privacy). h2s take the h3 style with a rule above.
   37rem sets about 70 characters a line at 18px. */
.prose { max-width: 37rem; line-height: 1.7; }
.prose > * + * { margin-top: 1.15em; }
.prose h2 {
  margin-top: 44px;
  padding-top: 32px;
  border-top: 1px solid var(--rule);
  font-family: var(--serif);
  font-weight: 400;
  font-size: var(--fs-h3);
  line-height: 1.18;
  letter-spacing: -.01em;
}
@media (min-width: 700px) {
  .prose h2 { margin-top: 56px; padding-top: 40px; }
}
/* Directly under the page header, whose closing hairline already opens the text. */
.prose > h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.prose h2 + * { margin-top: 20px; }
.prose ul { --dash: 16px; --indent: 32px; --lh: 1.7; }
@media (max-width: 419px) {
  .prose ul { --indent: 28px; } /* small phones: the long items get more of the line */
}
.prose ul > li { position: relative; padding-left: var(--indent); }
.prose ul > li + li { margin-top: 10px; }
.prose ul > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(var(--lh) * .5em);
  width: var(--dash);
  height: 1px;
  background: var(--accent);
}


/* =====================================================================
   20. FORMS
   <form class="form"> > .field-row? > .field > label.field__label + .input + p.field__error
   ===================================================================== */
/* First / Last Name pair up from 560px (the form column is 476px wide from 1000px). */
.form { display: grid; gap: 24px; }
.field-row { display: grid; gap: 24px; }
@media (min-width: 560px) {
  .field-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.field { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.field__label { color: var(--ink); font-size: 1rem; font-weight: 500; line-height: 1.4; }
.field__hint { color: var(--ink-soft); font-size: .875rem; font-weight: 400; }
.input,
.textarea {
  width: 100%;
  min-height: 54px;
  padding: 0 16px;
  background: var(--field);
  border: 1px solid var(--field-border);
  border-radius: 2px;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.4;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.textarea { min-height: 180px; padding: 14px 16px; resize: vertical; }
.input::placeholder,
.textarea::placeholder { color: var(--ink-soft); opacity: 1; }
.input:focus,
.textarea:focus,
.input:focus-visible,
.textarea:focus-visible {
  outline: none;
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(31, 58, 53, .2);
}
.input[aria-invalid="true"],
.textarea[aria-invalid="true"] { border-color: var(--error); }
/* A firmer 2px red edge while an invalid field is not focused (focus keeps the green ring). */
.input[aria-invalid="true"]:not(:focus),
.textarea[aria-invalid="true"]:not(:focus) { box-shadow: inset 0 0 0 1px var(--error); }
.field__error { color: var(--error); font-size: .875rem; line-height: 1.45; }

/* Custom checkbox with a visible label. <label class="checkbox"><input type="checkbox"> <span>text</span></label> */
.checkbox {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  column-gap: 14px;
  align-items: start;
  color: var(--ink);
  font-size: 1rem;
  line-height: 1.5;
  cursor: pointer;
}
.checkbox input {
  appearance: none;
  -webkit-appearance: none;
  display: grid;
  place-content: center;
  width: 22px;
  height: 22px;
  margin: 1px 0 0;
  background: var(--field);
  border: 1.5px solid var(--field-border);
  border-radius: 2px;
  cursor: pointer;
}
.checkbox input::before {
  content: "";
  width: 11px;
  height: 6px;
  border-left: 2px solid var(--paper);
  border-bottom: 2px solid var(--paper);
  transform: translateY(-1.5px) rotate(-45deg);
  opacity: 0;
}
.checkbox input:checked { background: var(--green); border-color: var(--green); }
.checkbox input:checked::before { opacity: 1; }
.checkbox input:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 3px; }
.checkbox input[aria-invalid="true"] { border-color: var(--error); }
.checkbox a { color: var(--ink); text-decoration: underline; text-decoration-color: var(--accent-ink); text-underline-offset: 4px; }
/* The consent error lines up with the label text, not the box (22px box + 14px gap). */
.checkbox + .field__error { padding-left: 36px; }

/* While a message is being sent to a form service (contact.js sets aria-busy). */
.form[aria-busy="true"] .btn { opacity: .72; cursor: progress; }
@media (max-width: 699px) {
  .form .btn[type="submit"] { display: flex; width: 100%; justify-content: space-between; }
}

/* Send-failure message; its email and phone links keep the error colour. */
.form-status { color: var(--error); font-size: .875rem; line-height: 1.45; }
.form-status a { color: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }

/* Success panel that replaces the form. */
.form-success { display: flex; flex-direction: column; align-items: flex-start; gap: 20px; padding-top: 4px; }
.form-success:focus { outline: none; }
.form-success__text { font-family: var(--serif); font-weight: 400; font-size: 1.5rem; line-height: 1.35; }
.form-success__note { max-width: 30em; color: var(--ink-soft); }


/* =====================================================================
   21. PAGE: PRIVACY & GDPR (privacy-gdpr.html)
   Contents rail (cols 1-3, 1000px and up) + article (.prose, from col 5).
   ===================================================================== */
.privacy { padding-top: var(--space-sm); }
.privacy__grid { align-items: start; }

@media (min-width: 1000px) {
  .privacy-toc { grid-column: 1 / span 3; }
  .privacy__article { grid-column: 5 / -1; }
}
/* 1000-1199: three columns are too narrow for the long questions, so the rail takes four
   and the article (still a comfortable measure) starts at col 6. */
@media (min-width: 1000px) and (max-width: 1199px) {
  .privacy-toc { grid-column: 1 / span 4; }
  .privacy__article { grid-column: 6 / -1; }
}

/* Contents rail (.lg-only hides it under 1000px). */
@media (min-width: 1000px) {
  .privacy-toc {
    position: sticky;
    top: calc(var(--header-h) + 40px);
    align-self: start;
    /* Scrolls inside itself on short screens so the last link is always reachable.
       The padding / negative margin pair leaves room for the focus ring. */
    max-height: calc(100vh - var(--header-h) - 64px);
    max-height: calc(100svh - var(--header-h) - 64px);
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    padding: 8px 10px;
    margin: -8px -10px;
  }
}
.privacy-toc__list { border-left: 1px solid var(--rule); }
.privacy-toc__link {
  position: relative;
  display: block;
  padding: 11px 0 11px 20px;
  color: var(--ink-soft);
  font-family: var(--sans);
  font-size: var(--fs-ui);
  font-weight: 500;
  line-height: 1.4667;       /* 22px: one-line links are 44px tall */
  text-decoration: none;
  text-wrap: balance;
  transition: color var(--dur) var(--ease);
}
.privacy-toc__link::before {
  content: "";
  position: absolute;
  top: 9px;
  bottom: 9px;
  left: -1px;
  width: 2px;
  background: var(--accent);
  transform: scaleY(0);
  transition: transform var(--dur) var(--ease);
}
.privacy-toc__link:hover,
.privacy-toc__link.is-current { color: var(--ink); }
.privacy-toc__link.is-current::before { transform: scaleY(1); }

/* A little more air between the long, multi-line rights items (shared prose: 10px). */
.prose .privacy-rights > li + li { margin-top: 16px; }

/* ICO address: sized to its content, like an address card, rather than a full-width slab.
   <address class="panel-sand panel-sand--compact privacy-ico"> */
.prose > .privacy-ico { margin-top: 28px; }
.privacy-ico { width: fit-content; min-width: min(100%, 22rem); max-width: 100%; }
.privacy-ico__lines {
  font-family: var(--serif);
  font-weight: 400;
  font-size: 1.25rem;
  line-height: 1.45;
  letter-spacing: -.005em;
}
.privacy-ico__helpline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 14px;
  margin-top: 20px;
  padding-top: 14px;
  border-top: 1px solid var(--rule);
}
.privacy-ico__label {
  font-family: var(--sans);
  font-weight: 600;
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.privacy-ico__helpline a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-block: -6px;        /* full 44px target without padding out the panel */
  font-family: var(--serif);
  font-size: 1.25rem;
  font-weight: 400;
  white-space: nowrap;
}
@media (max-width: 419px) {
  /* Keeps "Information Commissioner's Office" on one line down to 360px. */
  .privacy-ico__lines,
  .privacy-ico__helpline a { font-size: 1.125rem; }
}


/* =====================================================================
   21b. GENTLE REVEAL ON SCROLL
   site.js adds .reveal-ready and data-reveal only when motion is allowed,
   so without JS (or with reduced motion) everything is simply visible.
   ===================================================================== */
.reveal-ready [data-reveal] {
  transition:
    opacity .9s cubic-bezier(.22, .61, .36, 1),
    transform 1.1s cubic-bezier(.22, .61, .36, 1);
  transition-delay: var(--reveal-delay, 0ms);
}
.reveal-ready [data-reveal="up"] { opacity: 0; transform: translate3d(0, 18px, 0); }
.reveal-ready [data-reveal="zoom"] {
  opacity: 0;
  transform: scale(1.06);
  transition-duration: 1.3s, 2s;
}
.reveal-ready [data-reveal].is-revealed { opacity: 1; transform: none; }
/* The opening plays on arrival with keyframes (no observer), ending on the element's own styles. */
.reveal-ready [data-reveal="load-up"] {
  animation:
    reveal-fade .9s cubic-bezier(.22, .61, .36, 1) var(--reveal-delay, 0ms) both,
    reveal-rise 1.1s cubic-bezier(.22, .61, .36, 1) var(--reveal-delay, 0ms) both;
}
.reveal-ready [data-reveal="load-zoom"] {
  animation:
    reveal-fade 1.3s cubic-bezier(.22, .61, .36, 1) both,
    reveal-settle 2s cubic-bezier(.22, .61, .36, 1) both;
}
@keyframes reveal-fade { from { opacity: 0; } }
@keyframes reveal-rise { from { transform: translate3d(0, 18px, 0); } }
@keyframes reveal-settle { from { transform: scale(1.06); } }


/* =====================================================================
   22. REDUCED MOTION AND PRINT
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
  /* The rule above keeps transition delays; the quote change must be instant. */
  .js .quote-show__slide,
  .js .quote-show__slide:not(.is-active) { transition: none !important; }
}

@media print {
  .reveal-ready [data-reveal] { opacity: 1 !important; transform: none !important; animation: none !important; }
  .site-header { position: static; }
  .site-header::before { display: none; }
  .nav-toggle, .header-contact, .header-cta, .carousel-controls, .skip, .primary-nav__extra, .privacy-toc, .opening__cta { display: none !important; }
  .band-green, .band-sand { background: none; color: var(--ink); }
  .closing { min-height: 0; color: var(--ink); background: none; }
  .closing picture { display: none; }
  .opening__panel { aspect-ratio: auto; color: var(--ink); background: none; padding: 0; }
  .opening__panel picture { display: none; }
  /* Green bands print on paper, so their light-on-dark details turn dark as well. */
  :is(.band-green, .closing, .opening__panel) :is(.quote-testimonial, .cite, .label) { color: var(--ink-soft); }
  :is(.band-green, .closing, .opening__panel) .cite__dash { color: var(--accent); }
  .logos { display: none; }
  .t-track { display: block; overflow: visible; }
  .t-slide + .t-slide { margin-top: 24px; }
  .t-slide[aria-hidden="true"] { display: block; }
  /* The quote slideshow prints every quote, one under another. */
  .quote-show__track,
  .no-js .quote-show__track { display: block; overflow: visible; }
  .quote-show__slide { opacity: 1 !important; visibility: visible !important; transition: none !important; }
  .quote-show__slide + .quote-show__slide { margin-top: 24px; }
  .privacy__article { grid-column: 1 / -1; }
}
