/* ==========================================================================
   Hair & photography: the only stylesheet.
   Built to design-reference/SITE-SPEC.md (tokens 3.1, components 4.x).

   1 Fonts          5 Header and nav     9  Hair wall        13 Contact and form
   2 Tokens         6 Pills and links    10 Photography      14 Footer
   3 Base           7 Images             11 Rows             15 Lightbox
   4 Motion         8 Home               12 Booking band

   Design language borrowed from four reference sites (see design-reference/):
   Yacob Bonifacio's quiet bar and numbering, Ethan Jones's type pair and
   hairline rows, Lady on Film's split, circle portrait and pills, Hooli's
   paired photo wall. None of their photos, copy, logos or code are used.
   No inline styles anywhere: the Content-Security-Policy blocks them.
   ========================================================================== */

/* 1 Fonts: Alegreya and Alegreya Sans, self-hosted (SIL Open Font License,
     fonts/OFL-*.txt). Each file only downloads when a page uses characters
     from its range; latin-ext covers macrons (ā ē ī ō ū). */
@font-face {
  font-family: "Alegreya";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/alegreya-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Alegreya";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/alegreya-latin-ext-400-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Alegreya";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/alegreya-latin-400-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Alegreya";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/alegreya-latin-ext-400-italic.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Alegreya Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/alegreya-sans-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Alegreya Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/alegreya-sans-latin-ext-400-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* 2 Tokens (spec 3.1) --------------------------------------------------------- */
:root {
  color-scheme: light;

  /* Colour: white pages, near-black ink, one warm grey, one warm mat.
     Her photos are the only colour. Contrast: ink on white 18.88:1, on mat
     16.25:1; ink-soft on white 6.82:1, on mat 5.87:1. --line is never text. */
  --bg: #ffffff;
  --ink: #111111;
  --ink-soft: #5c5b54;
  --mat: #efeee9;
  --line: #d9d8cf;

  /* Families: display = what she says; ui = what you click, scan or compare */
  --font-display: "Alegreya", Georgia, "Times New Roman", serif;
  --font-ui: "Alegreya Sans", "Segoe UI", system-ui, -apple-system, Roboto, sans-serif;

  /* Fluid type: minimum at 360px wide, maximum at 1440px wide */
  --text-h1: clamp(2.5rem, 2.083rem + 1.852vw, 3.75rem);         /* 40 to 60 */
  --text-h2: clamp(1.75rem, 1.5rem + 1.111vw, 2.5rem);           /* 28 to 40 */
  --text-contact: clamp(1.375rem, 1.125rem + 1.111vw, 2.125rem); /* 22 to 34 */
  --text-lead: clamp(1.3125rem, 1.208rem + 0.463vw, 1.625rem);   /* 21 to 26 */
  --text-name: clamp(1.25rem, 1.167rem + 0.37vw, 1.5rem);        /* 20 to 24 */
  --text-row: clamp(1.25rem, 1.208rem + 0.185vw, 1.375rem);      /* 20 to 22 */
  --text-body: clamp(1.125rem, 1.104rem + 0.093vw, 1.1875rem);   /* 18 to 19 */
  --text-menu: clamp(1.75rem, 1rem + 4vw, 2.25rem);              /* 28 to 36 */
  --text-price: 1.0625rem; /* 17 */
  --text-input: 1.0625rem; /* 17 */
  --text-ui: 1rem;         /* 16 */
  --text-small: 0.9375rem; /* 15 */
  --text-role: 0.875rem;   /* 14, the only uppercase */

  --lh-display: 1.05;
  --lh-heading: 1.15;
  --lh-lead: 1.4;
  --lh-body: 1.6;
  --lh-ui: 1.3;
  --lh-small: 1.45;
  --track-display: -0.01em;
  --track-ui: 0.02em;
  --track-role: 0.08em;
  /* About 65 characters a line in Alegreya (62ch ran to about 80). */
  --measure: 28em;

  /* Space */
  --margin: clamp(20px, 4vw, 48px);
  --section: clamp(48px, 6.6vmax, 112px);
  --gap-split: clamp(32px, 5vw, 72px);
  --gutter: 12px;
  --gap-spread: clamp(16px, 2.2vw, 32px);
  --gap-wall-row: clamp(24px, 3vw, 40px);
  --gap-pair: clamp(12px, 3.4vw, 48px);
  --gap-photo-row: clamp(32px, 4.5vw, 64px);
  --caption-gap: 8px;
  --row-min: 64px;

  /* Widths and bars */
  --max-page: 1440px;
  --max-photo: 1200px;
  --header-h: 60px;
  --tap: 44px;

  /* Lines and shapes */
  --hairline: 1px solid var(--line);
  --rule: 1px solid var(--ink);
  --field-border: 1px solid var(--ink);
  --field-border-error: 2px solid var(--ink);
  --focus-ring: 2px solid var(--ink);
  --focus-offset: 3px;
  --radius-pill: 999px;
  --radius-textarea: 20px;
  --radius-portrait: 50%;

  /* Motion: quiet, ease-out, never looping */
  --dur-fast: 150ms;
  --dur-lightbox: 180ms;
  --dur-menu: 200ms;
  --dur-image: 300ms;
  --dur-entrance: 400ms;
  --ease-out: cubic-bezier(0.215, 0.61, 0.355, 1);
}
@media (min-width: 48em) {
  :root {
    --gutter: 16px;
    --header-h: 72px;
  }
}

/* 3 Base ------------------------------------------------------------------------ */
*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  /* Anchors and keyboard focus never land under the sticky bar.
     --bar-h is the bar's measured height (script.js); --header-h the design value. */
  scroll-padding-top: calc(var(--bar-h, var(--header-h)) + 16px);
  text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 400 var(--text-body) / var(--lh-body) var(--font-display);
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}
h1,
h2,
h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  text-wrap: balance;
}
/* Old-style figures read oddly at heading size ("01 Portraits"). */
h1,
h2 {
  font-variant-numeric: lining-nums;
}
h1 {
  font-size: var(--text-h1);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
}
h2 {
  font-size: var(--text-h2);
  line-height: var(--lh-heading);
}
p {
  margin: 0;
  text-wrap: pretty;
}
figure {
  margin: 0;
}
b,
strong {
  font-weight: 400;
}
img {
  display: block;
  max-width: 100%;
  height: auto;
}
a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  transition: text-decoration-thickness var(--dur-fast) var(--ease-out);
}
/* Hover effects only where a pointer can hover: on touch screens a tap would
   leave them stuck on (a tapped pill stayed inverted after returning). */
@media (hover: hover) {
  a:hover {
    text-decoration-thickness: 2px;
  }
}
input,
button,
textarea {
  font: inherit;
  color: inherit;
}
:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}
main:focus {
  outline: none;
}
::selection {
  background: var(--ink);
  color: var(--bg);
}
.wrap {
  max-width: var(--max-page);
  margin-inline: auto;
  padding-inline: var(--margin);
}
.measure {
  max-width: var(--measure);
}
.split {
  display: grid;
  gap: var(--gap-split);
}
.split > * {
  min-width: 0;
}
@media (min-width: 64em) {
  .split {
    grid-template-columns: 5fr 7fr;
  }
}
.section {
  padding-block: var(--section);
}
.section + .section {
  padding-top: 0;
}
.vh {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.skip-link {
  position: absolute;
  z-index: 100;
  top: 8px;
  left: 8px;
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 18px;
  border: var(--rule);
  border-radius: var(--radius-pill);
  background: var(--bg);
  font: 400 var(--text-ui) / 1.2 var(--font-ui);
  text-decoration: none;
  transform: translateY(-200%);
}
.skip-link:focus {
  transform: none;
}

/* Shared text styles */
.lead {
  font: 400 var(--text-lead) / var(--lh-lead) var(--font-display);
  text-wrap: balance;
}
.facts,
.note,
.meta {
  font: 400 var(--text-small) / var(--lh-small) var(--font-ui);
  color: var(--ink-soft);
}
.label,
.group-label {
  margin: 0;
  font: 400 var(--text-small) / 1.4 var(--font-ui);
  letter-spacing: var(--track-ui);
  color: var(--ink);
}
.group-label {
  padding-bottom: 8px;
  border-bottom: var(--rule);
}
.role {
  font: 400 var(--text-role) / 1.4 var(--font-ui);
  letter-spacing: var(--track-role);
  text-transform: uppercase;
}
.prose > p + p {
  margin-top: 24px;
}
.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 28px;
}
.text-link {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  min-height: var(--tap);
  font: 400 var(--text-ui) / var(--lh-ui) var(--font-ui);
  letter-spacing: var(--track-ui);
}

/* Page intros: stacked on one left edge (hair, photography, contact, 404) */
.intro {
  padding-top: var(--section);
}
.intro > * + * {
  margin-top: 20px;
}
.intro .actions {
  margin-top: 28px;
}

/* 4 Motion (spec 3.3) ----------------------------------------------------------- */
@keyframes settle {
  from {
    opacity: 0.6;
    transform: scale(0.96);
  }
}
@keyframes fade-in {
  from {
    opacity: 0;
  }
}
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

/* 5 Header and nav (spec 4.1) --------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--bg);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-fast) var(--ease-out);
}
html.is-scrolled .site-header {
  border-bottom-color: var(--line);
}
.bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 28px;
  min-height: var(--header-h);
}
.wordmark {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  margin-right: auto;
  padding-block: 6px;
  font: 400 var(--text-name) / 1.15 var(--font-display);
  text-decoration: none;
}
.nav-list,
.nav-contact {
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0 28px;
}
.nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font: 400 var(--text-ui) / var(--lh-ui) var(--font-ui);
  letter-spacing: var(--track-ui);
  text-decoration-line: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  transition: text-decoration-color var(--dur-fast) var(--ease-out);
}
.nav a[aria-current="page"] {
  text-decoration-color: currentColor;
}
@media (hover: hover) {
  .nav a:hover {
    text-decoration-color: currentColor;
  }
}
.nav-contact {
  display: none;
}
.menu-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  min-width: var(--tap);
  min-height: var(--tap);
  padding: 0 4px;
  border: 0;
  background: none;
  font: 400 var(--text-ui) / 1.2 var(--font-ui);
  letter-spacing: var(--track-ui);
  text-transform: lowercase;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
}
@media (min-width: 48em) and (max-width: 63.99em) {
  .nav-list {
    gap: 0 20px;
  }
}
/* Windows High Contrast and other forced-colour modes repaint the underline
   colours, so mark the current page with a heavier underline only. */
@media (forced-colors: active) {
  .nav a {
    text-decoration-line: none;
  }
  .nav a[aria-current="page"] {
    text-decoration-line: underline;
    text-decoration-thickness: 3px;
  }
}
/* Without JavaScript the phone bar is taller (the words wrap under her name),
   so it scrolls away with the page instead of sticking. */
@media (max-width: 47.99em) {
  html:not(.js) .site-header {
    position: static;
  }
}
/* Phones: her name, the pill and "menu" in the bar; the page words open as a
   full white sheet under it. Without JavaScript the words wrap under her name. */
@media (max-width: 47.99em) {
  .bar {
    gap: 0 12px;
  }
  .nav {
    order: 3;
    flex-basis: 100%;
  }
  .nav-list {
    gap: 0 20px;
  }
  /* One row: her name takes the room left and wraps inside itself; the pill
     and the toggle never move. (.pill.pill--header outranks .pill below.) */
  .js .bar {
    flex-wrap: nowrap;
  }
  .js .wordmark {
    flex: 1 1 auto;
    min-width: 0;
  }
  .pill.pill--header {
    flex: none;
    padding: 0 16px;
  }
  .js .menu-toggle {
    flex: none;
    min-width: 3.5em;
    justify-content: flex-end;
  }
  /* "book hair ↗" reads "book ↗" on phones; screen readers still hear "hair". */
  .pill-more {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  .js .nav {
    order: 0;
    flex-basis: auto;
    position: fixed;
    inset: var(--bar-h, var(--header-h)) 0 0;
    z-index: 49;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 48px;
    padding: 40px var(--margin) 48px;
    overflow-y: auto;
    background: var(--bg);
    visibility: hidden;
    opacity: 0;
    transition: opacity var(--dur-menu) var(--ease-out), visibility 0s linear var(--dur-menu);
  }
  .js.menu-open .nav {
    visibility: visible;
    opacity: 1;
    transition: opacity var(--dur-menu) var(--ease-out);
  }
  html.menu-open,
  html.menu-open body {
    overflow: hidden;
  }
  .js .nav-list {
    flex-direction: column;
    align-items: center;
    gap: 24px;
  }
  .js .nav-list a {
    font-size: var(--text-menu);
    letter-spacing: 0;
  }
  .js .nav-contact {
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  .js .nav-contact a {
    font-size: 1.0625rem;
    text-decoration-color: currentColor;
  }
  .js .menu-toggle {
    display: inline-flex;
  }
}

/* 6 Pills, text links and arrows (spec 4.2) ------------------------------------- */
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4em;
  min-height: 48px;
  padding: 0 26px;
  border: 1px solid var(--ink);
  border-radius: var(--radius-pill);
  font: 400 var(--text-ui) / 1.2 var(--font-ui);
  letter-spacing: var(--track-ui);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
/* Solid commits (Setmore, send); outline moves you around the site. */
.pill--solid {
  background: var(--ink);
  color: var(--bg);
}
.pill--solid:focus-visible {
  background: var(--bg);
  color: var(--ink);
}
.pill--outline {
  background: transparent;
  color: var(--ink);
}
.pill--outline:focus-visible {
  background: var(--ink);
  color: var(--bg);
}
.pill--header {
  min-height: var(--tap);
  padding: 0 18px;
}
@media (hover: hover) {
  .pill--solid:hover {
    background: var(--bg);
    color: var(--ink);
  }
  .pill--outline:hover {
    background: var(--ink);
    color: var(--bg);
  }
  .door:hover .door__label {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.3em;
  }
  a.row:hover {
    background: var(--mat);
  }
  .site-footer a:hover {
    color: var(--ink);
  }
}

/* 7 Images (spec 4.3) ---------------------------------------------------------- */
.r-4x5 {
  --ratio: 4 / 5;
  --r: 0.8;
}
.r-2x3 {
  --ratio: 2 / 3;
  --r: 0.6667;
}
.r-3x2 {
  --ratio: 3 / 2;
  --r: 1.5;
}
.r-1x1 {
  --ratio: 1;
  --r: 1;
}
.frame-link {
  display: block;
  cursor: zoom-in;
}
/* A correct file fills its box exactly. A wrongly shaped one shows whole on
   the mat (never cropped): that's the cue to re-export it. */
.photo {
  width: 100%;
  height: auto;
  aspect-ratio: var(--ratio);
  object-fit: contain;
  background: var(--mat);
}
img.fade {
  transition: opacity var(--dur-image) var(--ease-out);
}
html.fade-ready img.fade:not(.is-loaded) {
  opacity: 0;
}
.caption {
  display: block;
  margin-top: var(--caption-gap);
  font: 400 var(--text-small) / var(--lh-small) var(--font-ui);
  color: var(--ink-soft);
}

/* 8 Home ---------------------------------------------------------------------------- */
.hello {
  padding-block: 24px var(--section);
}
.hello__portrait {
  width: clamp(200px, 60vw, 280px);
}
.portrait {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  border-radius: var(--radius-portrait);
  object-fit: cover;
  background: var(--mat);
  animation: settle var(--dur-entrance) var(--ease-out) both;
}
.hello__text > * + * {
  margin-top: 16px;
}
.hello__text .lead {
  margin-top: 20px;
}
.hello__text .actions {
  margin-top: 28px;
}
@media (min-width: 64em) {
  .hello {
    padding-block: clamp(32px, 10vh, 120px);
  }
  .hello .split {
    align-items: center;
  }
  .hello__portrait {
    width: min(100%, 420px);
  }
}

/* Phones on their side: the portrait sits beside the greeting, so the first
   screen isn't just a circle. */
@media (orientation: landscape) and (max-height: 32em) and (max-width: 63.99em) {
  .hello {
    padding-block: 16px var(--section);
  }
  .hello .split {
    grid-template-columns: auto 1fr;
    align-items: center;
  }
  .hello__portrait {
    width: min(34vw, 52vh);
    width: min(34vw, 52svh);
  }
}

/* A bit about me */
.side-photo {
  max-width: 280px;
}
.about-left > * + * {
  margin-top: 32px;
}
.about-right > * + * {
  margin-top: 24px;
}
.about-right .group-label {
  margin-top: 40px;
}
@media (min-width: 64em) {
  .side-photo {
    max-width: 400px;
  }
}

/* My work: the two doors, a centred pair sized to the screen */
.doors {
  display: flex;
  justify-content: center;
  gap: var(--gutter);
}
.door {
  display: block;
  width: min(calc((100% - var(--gutter)) / 2), calc(clamp(420px, 100vh - 210px, 820px) * 0.8));
  text-decoration: none;
}
@supports (height: 100svh) {
  .door {
    width: min(calc((100% - var(--gutter)) / 2), calc(clamp(420px, 100svh - 210px, 820px) * 0.8));
  }
}
.door__label {
  display: block;
  margin-top: var(--caption-gap);
  font: 400 var(--text-ui) / var(--lh-ui) var(--font-ui);
  letter-spacing: var(--track-ui);
}
.door__line {
  display: block;
  margin-top: 2px;
  font: 400 1.0625rem / 1.4 var(--font-display);
  color: var(--ink-soft);
}
.door:focus-visible .door__label {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
}

/* 9 Hair wall (spec 4.4): spreads of two same-look frames. One spread per row,
     two from 64em. Never three columns, no layout script. ------------------ */
.wall {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--gap-wall-row) var(--gap-spread);
}
@media (min-width: 64em) {
  .wall {
    grid-template-columns: 1fr 1fr;
  }
}
.pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gutter);
  align-items: start;
}

/* 10 Photography (spec 4.5): same-ratio pairs and landscape singles, sized so
      a whole frame fits the screen, hanging from the left margin. ---------- */
.series + .series {
  margin-top: var(--section);
}
.series-head {
  margin-bottom: 32px;
}
.series-head > * + * {
  margin-top: 12px;
}
.photo-rows {
  display: grid;
  gap: var(--gap-photo-row);
}
.photo-row {
  --row-h: clamp(320px, calc(100vh - 160px), 860px);
}
@supports (height: 100svh) {
  .photo-row {
    --row-h: clamp(320px, calc(100svh - 160px), 860px);
  }
}
.photo-row--pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap-pair);
  align-items: start;
  max-width: min(100%, var(--max-photo), calc(2 * var(--row-h) * var(--r) + var(--gap-pair)));
}
.photo-row--single {
  max-width: min(100%, var(--max-photo), calc(var(--row-h) * var(--r)));
}
/* Phones: a series shows its photos straight after its heading, with the note
   and place underneath, so a phone's first screen isn't all words. The series
   index (a desktop shortcut) is dropped; on a phone you just scroll. */
@media (max-width: 47.99em) {
  .series-nav {
    display: none;
  }
  .series {
    display: flex;
    flex-direction: column;
  }
  .series-head {
    display: contents;
  }
  .series-head > h2 {
    order: 0;
    margin-bottom: 20px;
  }
  .series > .photo-rows {
    order: 1;
  }
  .series-head > p {
    order: 2;
  }
  .series-head > p:first-of-type {
    margin-top: 20px;
  }
  .series > .back-link {
    order: 3;
  }
}
.series-index {
  display: flex;
  flex-wrap: wrap;
  gap: 0 24px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.back-link {
  margin-top: 24px;
}

/* 11 Rows: prices, sessions and "what I bring" (spec 4.7) ---------------------- */
.rows {
  list-style: none;
  margin: 0;
  padding: 0;
}
.rows > li {
  border-bottom: var(--hairline);
}
.row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 4px 24px;
  min-height: var(--row-min);
  padding-block: 16px;
}
a.row {
  margin-inline: -12px;
  padding-inline: 12px;
  color: inherit;
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-out);
}
.row-main {
  display: grid;
  gap: 2px;
}
.row-title {
  font: 400 var(--text-row) / 1.25 var(--font-display);
}
.row-detail {
  font: 400 var(--text-small) / var(--lh-small) var(--font-ui);
  color: var(--ink-soft);
}
.row-end {
  font: 400 var(--text-ui) / 1.3 var(--font-ui);
  white-space: nowrap;
}
.row-end .price {
  font-size: var(--text-price);
  font-variant-numeric: lining-nums tabular-nums;
}
.row-num {
  font: 400 var(--text-ui) / 1.3 var(--font-ui);
  color: var(--ink-soft);
}
.row-line {
  font: 400 1.0625rem / 1.45 var(--font-display);
  color: var(--ink-soft);
}
.group + .group {
  margin-top: 48px;
}
.list-note {
  margin-top: 24px;
  max-width: var(--measure);
}
.list-note > * + * {
  margin-top: 4px;
}

/* 12 Booking band (spec 4.8) ------------------------------------------------------ */
.band {
  background: var(--mat);
  padding-block: var(--section);
}
.band-head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}
.band-head p {
  margin-top: 8px;
}
@media (min-width: 48em) {
  .band-head {
    flex-direction: row;
    align-items: center;
    gap: 24px;
  }
}
.avatar {
  flex: none;
  width: 80px;
  height: 80px;
  border-radius: var(--radius-portrait);
  object-fit: cover;
  background: var(--bg);
}
.band-halves {
  display: grid;
  gap: 40px;
  margin-top: 48px;
}
@media (min-width: 64em) {
  .band-halves {
    grid-template-columns: 1fr 1fr;
    gap: var(--gap-split);
  }
}
.band-half > * + * {
  margin-top: 12px;
}
.band-half > p {
  max-width: 46ch;
  font-size: 1.125rem;
}
.band-half .pill {
  margin-top: 20px;
}
.aside {
  font: 400 var(--text-small) / var(--lh-small) var(--font-ui);
}
.aside a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
}

/* 13 Contact lines and form (spec 4.9) ------------------------------------------- */
.contact-lines {
  display: grid;
  gap: 28px;
}
.cl-label {
  font: 400 var(--text-small) / 1.4 var(--font-ui);
  color: var(--ink-soft);
}
.cl-value {
  margin-top: 4px;
  font: 400 var(--text-contact) / 1.25 var(--font-display);
  font-variant-numeric: lining-nums;
  overflow-wrap: anywhere;
}
.cl-value a {
  text-underline-offset: 4px;
}
.cl-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0 20px;
}
.cl-actions a {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  min-width: var(--tap);
  min-height: var(--tap);
  font: 400 var(--text-ui) / 1.2 var(--font-ui);
  letter-spacing: var(--track-ui);
}
.find-me {
  margin-top: 48px;
}
.find-me > * + * {
  margin-top: 8px;
}

.form {
  position: relative;
  display: grid;
  gap: 24px;
  max-width: 36rem;
}
/* The #enquire-* fragment targets sit at the top of the form without taking
   up grid rows. */
.anchor-targets {
  position: absolute;
  top: 0;
  left: 0;
}
.anchor-targets > span {
  display: block;
}
.form-title {
  margin-bottom: -4px;
}
.field {
  display: grid;
  gap: 8px;
}
.field > label,
.form legend {
  padding: 0;
  font: 400 var(--text-small) / 1.4 var(--font-ui);
  color: var(--ink);
}
.hint {
  font: 400 var(--text-small) / var(--lh-small) var(--font-ui);
  color: var(--ink-soft);
}
.form input[type="text"],
.form input[type="email"],
.form input[type="tel"],
.form textarea {
  width: 100%;
  min-height: 48px;
  padding: 12px 18px;
  border: var(--field-border);
  border-radius: var(--radius-pill);
  background: var(--bg);
  font: 400 var(--text-input) / 1.4 var(--font-ui);
}
.form textarea {
  min-height: 9.5rem;
  border-radius: var(--radius-textarea);
  resize: vertical;
}
/* Errors without colour: a 2px border and a plain sentence. */
.form input:user-invalid,
.form textarea:user-invalid {
  border: var(--field-border-error);
  padding: 11px 17px;
}
.field-error {
  display: none;
  font: 400 var(--text-small) / var(--lh-small) var(--font-ui);
  color: var(--ink);
}
.form :is(input, textarea):user-invalid + .field-error,
.form fieldset:has(:user-invalid) > .field-error {
  display: block;
}
.form fieldset {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}
.choices {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.choices > legend {
  margin-bottom: 8px;
}
.choices > label {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: var(--tap);
  padding: 0 18px;
  border: 1px solid var(--ink);
  border-radius: var(--radius-pill);
  font: 400 var(--text-ui) / 1.2 var(--font-ui);
  letter-spacing: var(--track-ui);
  cursor: pointer;
}
.choices input {
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--ink);
}
.choices > label:has(:focus-visible) {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}
.choices input:focus-visible {
  outline: none;
}
.choices > .field-error {
  flex-basis: 100%;
}
.photo-questions {
  display: grid;
  gap: 20px;
}
.photo-questions[hidden] {
  display: none;
}
.photo-questions > legend {
  margin-bottom: 4px;
}
.hp {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
/* Always rendered (empty takes no space) so screen readers hear updates. */
.form-status {
  font: 400 var(--text-small) / var(--lh-small) var(--font-ui);
  color: var(--ink);
}
.form-alt {
  font: 400 var(--text-small) / var(--lh-small) var(--font-ui);
  color: var(--ink-soft);
}
.form-alt a {
  color: var(--ink);
  overflow-wrap: anywhere;
}

/* 14 Footer (spec 4.10) ------------------------------------------------------------ */
.site-footer {
  border-top: var(--hairline);
  padding-block: 40px 48px;
}
/* Where the mat band ends the page, its own edge is enough. */
main:has(> .band:last-child) + .site-footer {
  border-top-color: transparent;
}
.site-footer p,
.footer-links {
  font: 400 var(--text-small) / 1.6 var(--font-ui);
  color: var(--ink-soft);
}
.site-footer a {
  color: var(--ink-soft);
}
.footer-links {
  list-style: none;
  margin: 8px 0;
  padding: 0;
}
/* Phones: each item is its own row, and each link is a 44px-tall target. */
@media (max-width: 47.99em) {
  .footer-links a {
    display: inline-block;
    padding: 10px 3px;
  }
}
@media (min-width: 48em) {
  .footer-links {
    display: flex;
    flex-wrap: wrap;
  }
  .footer-links li + li::before {
    content: "·";
    margin-inline: 0.6em;
  }
}

/* 15 Lightbox (spec 4.6) ------------------------------------------------------------ */
html.lightbox-open {
  overflow: hidden;
}
.lightbox {
  width: 100vw;
  max-width: none;
  height: 100vh;
  height: 100svh;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--bg);
  color: var(--ink);
}
.lightbox[open] {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  animation: fade-in var(--dur-lightbox) var(--ease-out);
}
.lightbox::backdrop {
  background: var(--bg);
}
.lb-top,
.lb-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 20px;
  padding: 8px var(--margin);
}
.lb-stage {
  display: grid;
  place-items: center;
  min-height: 0;
  padding: 0 var(--margin);
  touch-action: pan-y pinch-zoom;
}
.lb-img {
  width: auto;
  height: auto;
  max-width: 90vw;
  max-height: calc(100vh - 140px);
  max-height: calc(100svh - 140px);
  object-fit: contain;
  background: var(--mat);
}
.lb-btn {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 4px;
  border: 0;
  background: none;
  font: 400 var(--text-ui) / 1.2 var(--font-ui);
  letter-spacing: var(--track-ui);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  cursor: pointer;
}
.lb-caption {
  flex: 1 1 auto;
  text-align: center;
  font: 400 var(--text-small) / var(--lh-small) var(--font-ui);
  color: var(--ink-soft);
}
.lb-top .pill {
  min-height: var(--tap);
  padding: 0 18px;
}
@media (max-width: 47.99em) {
  .lb-caption {
    order: -1;
    flex-basis: 100%;
  }
}
