/* ==========================================================================
   Cherub Design
   One stylesheet. No framework, no build step, no JavaScript.

   The site sells fast, clear, tested websites, so it is one: short lines,
   large type, generous space, almost no decoration. Confidence comes from
   restraint rather than from argument — the previous version tried to win
   with volume of copy and lost.

   Layout primitive:  .bay (vertical space) → .col (measure) or .wide (full)

   Colour contrast, measured against WCAG 2.2 AA (4.5:1 text, 3:1 non-text).
   UPDATE THESE FIGURES IF YOU CHANGE A COLOUR.

   The accent is a violet, chosen for itself rather than derived from anything.
   It replaced a violet, and was picked by holding the violet's saturation and
   value constant and rotating the hue — so it carries the same weight on the
   page and the same measured contrast, and nothing else in the design had to
   move to accommodate it.

   Light
     ink      #16171a on paper  #fbfaf8 .... 17.18:1
     ink-2    #55565c on paper  #fbfaf8 ....  7.01:1
     violet   #732299 on paper  #fbfaf8 ....  8.33:1
     paper    #fbfaf8 on violet #732299 ....  8.33:1   (button label)
     violet   #732299 on shade  #f0eee9 ....  7.49:1
     ink      #16171a on shade  #f0eee9 .... 15.46:1
     ink-2    #55565c on shade  #f0eee9 ....  6.31:1
     rule     #8f9095 on paper  #fbfaf8 ....  3.05:1   (non-text, needs 3:1)

   Dark
     ink      #e9e8e6 on paper  #131315 .... 15.15:1
     ink-2    #9c9ba0 on paper  #131315 ....  6.72:1
     violet   #d190f0 on paper  #131315 ....  7.92:1
     paper    #131315 on violet #d190f0 ....  7.92:1   (button label)
     violet   #d190f0 on shade  #1a1a1d ....  7.41:1
     rule     #67686e on paper  #131315 ....  3.20:1   (non-text, needs 3:1)
   ========================================================================== */

:root {
  --paper: #fbfaf8;
  --shade: #f0eee9;
  --ink: #16171a;
  --ink-2: #55565c;
  --rule: #8f9095;
  --hair: #e2e0da;
  --violet: #732299;
  --on-violet: #fbfaf8;

  --display: "Instrument Serif", Georgia, "Times New Roman", serif;
  --text: "Schibsted Grotesk", "Helvetica Neue", Arial, sans-serif;

  --t-xs: 0.8125rem;
  --t-sm: 0.9375rem;
  --t-0: 1.0625rem;
  --t-md: 1.25rem;
  --t-lg: 1.5rem;
  --t-xl: clamp(1.75rem, 1.2rem + 2.2vw, 2.5rem);
  --t-2xl: clamp(2.25rem, 1.4rem + 3.4vw, 3.5rem);
  --t-3xl: clamp(2.75rem, 1.5rem + 5vw, 5rem);

  --gut: clamp(1.5rem, 5vw, 3rem);
  --wide: 72rem;
  --col: 34rem;
  /* Measure in ch, not rem. A rem cap only holds for one font size: 44rem was
     a comfortable 66 characters at 17px and a punishing 94 at 15px, which is
     where most of this site's running text actually sits. ch tracks the font,
     so one number is right everywhere. */
  --measure: 64ch;
  --bay: clamp(3.5rem, 8vw, 6.5rem);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #131315;
    --shade: #1a1a1d;
    --ink: #e9e8e6;
    --ink-2: #9c9ba0;
    --rule: #67686e;
    --hair: #26262a;
    --violet: #d190f0;
    --on-violet: #131315;
  }
}

:root[data-theme="dark"] {
  --paper: #131315;
  --shade: #1a1a1d;
  --ink: #e9e8e6;
  --ink-2: #9c9ba0;
  --rule: #67686e;
  --hair: #26262a;
  --violet: #d190f0;
  --on-violet: #131315;
}

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--text);
  font-size: var(--t-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; display: block; }
p { margin: 0; }

a { color: var(--violet); text-underline-offset: 0.2em; }
a:hover { text-decoration-thickness: 2px; }

a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible {
  outline: 3px solid var(--violet);
  outline-offset: 3px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

.skip {
  position: absolute; left: .75rem; top: -4rem; z-index: 60;
  background: var(--violet); color: var(--on-violet);
  padding: .7rem 1.1rem; font-weight: 600; text-decoration: none;
}
.skip:focus { top: .75rem; }


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

.wrap { width: min(100% - (var(--gut) * 2), var(--wide)); margin-inline: auto; }

.bay { padding-block: var(--bay); }
.bay--sm { padding-block: clamp(2.25rem, 5vw, 3.5rem); }
.bay--shade { background: var(--shade); }
.bay + .bay:not(.bay--shade) { padding-top: 0; }

.col--mid { max-width: var(--measure); }

/* A linked-to section otherwise lands flush against the top of the window with
   its heading half under the browser chrome. */
[id] { scroll-margin-top: 2rem; }

/* ----------------------------------------------------------------- type -- */

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.015em;
  text-wrap: balance;
  margin: 0;
  color: var(--ink);
}

h1 { font-size: var(--t-3xl); }
h2 { font-size: var(--t-2xl); }
h3 { font-size: var(--t-lg); letter-spacing: -0.01em; }

h1 em, h2 em { font-style: italic; color: var(--violet); }

h2.eyebrow, .eyebrow {
  font-family: var(--text);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
  line-height: 1.4;
  margin: 0 0 1.25rem;
}

.lede {
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--ink-2);
  max-width: 36rem;
}

.body { display: grid; gap: 1.1rem; max-width: var(--measure); }
/* :not([class]) rather than naming the exceptions. A rule shaped
   '.parent element' is (0,1,1) and quietly outranks any component class
   (0,1,0) living inside it — which is how the case-study figures ended up
   rendering at body size instead of display size, their whole point lost.
   Scoping to unclassed elements means anything that styles itself, wins. */
.body p:not([class]) { color: var(--ink-2); }
.body--mid { max-width: var(--measure); }

.note { font-size: var(--t-sm); color: var(--ink-2); max-width: var(--measure); }

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

.top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem 2rem;
  padding-block: 1.5rem;
}

.mark {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  text-decoration: none;
  color: var(--ink);
  font-family: var(--display);
  font-size: var(--t-md);
  letter-spacing: -0.01em;
}

.mark svg { width: 1.6rem; height: 1.6rem; flex: 0 0 auto; color: var(--violet); }

.top nav { margin-left: auto; }

.top ul {
  display: flex; flex-wrap: wrap; gap: .25rem 1.5rem;
  list-style: none; margin: 0; padding: 0;
}

/* :not([class]) rather than naming the exceptions. A rule shaped
   '.parent element' is (0,1,1) and quietly outranks any component class
   (0,1,0) living inside it — which is how the case-study figures ended up
   rendering at body size instead of display size, their whole point lost.
   Scoping to unclassed elements means anything that styles itself, wins. */
.top a:not([class]) {
  font-size: var(--t-sm);
  color: var(--ink-2);
  text-decoration: none;
  padding-block: .3rem;
}

.top a:hover { color: var(--ink); }
.top a[aria-current="page"] { color: var(--ink); text-decoration: underline; text-underline-offset: .35em; }

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

.hero { padding-block: clamp(3rem, 9vw, 7rem) clamp(2.5rem, 6vw, 4.5rem); }

.hero h1 { max-width: 16ch; }

.hero .lede { margin-top: 1.75rem; }

/* The price is the one fact in this line somebody will want to follow up, so
   it goes where the detail is rather than making them find Pricing themselves. */
.hero__meta a { color: inherit; text-decoration-color: var(--rule); text-underline-offset: .25em; }
.hero__meta a:hover { color: var(--violet); text-decoration-color: currentColor; }

.hero__meta {
  margin-top: 2.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--hair);
  display: flex;
  flex-wrap: wrap;
  gap: .4rem 2.5rem;
  font-size: var(--t-sm);
  color: var(--ink-2);
}

/* --------------------------------------------------------------- button -- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .8rem 1.4rem;
  font-family: var(--text);
  font-size: var(--t-0);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: 2px;
  cursor: pointer;
}

.btn--go { background: var(--violet); color: var(--on-violet); border-color: var(--violet); }
.btn--go:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }

.btn--quiet { background: transparent; color: var(--ink); border-color: var(--rule); }
.btn--quiet:hover { border-color: var(--ink); }

.btns { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 2rem; }

/* ----------------------------------------------------------------- work -- */

.jobs { display: grid; gap: clamp(2rem, 5vw, 3.5rem); }

@media (min-width: 46rem) { .jobs { grid-template-columns: 1fr 1fr; } }

.job { display: grid; gap: 1rem; align-content: start; }

.job__shot {
  aspect-ratio: 3 / 2;
  overflow: hidden;
  border-radius: 2px;
  background: var(--shade);
}

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

.job__kind {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* :not([class]) rather than naming the exceptions. A rule shaped
   '.parent element' is (0,1,1) and quietly outranks any component class
   (0,1,0) living inside it — which is how the case-study figures ended up
   rendering at body size instead of display size, their whole point lost.
   Scoping to unclassed elements means anything that styles itself, wins. */
.job p:not([class]) { color: var(--ink-2); font-size: var(--t-sm); }

/* A single number, stated plainly. No before/after tables. */
.figure {
  font-family: var(--display);
  font-size: var(--t-xl);
  line-height: 1;
  color: var(--ink);
}

.figure span {
  display: block;
  font-family: var(--text);
  font-size: var(--t-sm);
  color: var(--ink-2);
  margin-top: .35rem;
}

/* ---------------------------------------------------------------- lists -- */

/* Ruled rows. Used for what's included, services, prices, everything. */
.rows { list-style: none; margin: 0; padding: 0; }

.rows > li {
  padding-block: 1.15rem;
  border-top: 1px solid var(--hair);
  display: grid;
  gap: .3rem;
}

.rows > li:last-child { border-bottom: 1px solid var(--hair); }

.rows h3 { font-size: var(--t-md); }
/* :not([class]) for the same reason as .job p and .body p — this one was
   beating .price, so every figure on the pricing page rendered at body size
   and in body grey instead of 20px violet. Four times now. */
.rows p:not([class]) { color: var(--ink-2); font-size: var(--t-sm); max-width: var(--measure); }

.rows__top {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .2rem 1.5rem;
}

.price {
  font-family: var(--display);
  font-size: var(--t-md);
  color: var(--violet);
  white-space: nowrap;
}

.price span {
  font-family: var(--text);
  font-size: var(--t-xs);
  color: var(--ink-2);
  margin-left: .4rem;
}

/* Plain bullets — no tick glyphs, no coloured markers */
.plain { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; }

.plain li { max-width: var(--measure);
  padding-left: 1.1rem;
  position: relative;
  color: var(--ink-2);
  font-size: var(--t-sm);
  line-height: 1.5;
}

.plain li::before {
  content: "";
  position: absolute;
  left: 0; top: .62em;
  width: .35rem; height: 1px;
  background: var(--rule);
}

.plain strong { color: var(--ink); font-weight: 600; }

.two { display: grid; gap: 1.5rem 3rem; }
@media (min-width: 40rem) { .two { grid-template-columns: 1fr 1fr; } }

/* --------------------------------------------------------------- facts --- */

.facts { display: grid; gap: 1.25rem 3rem; margin: 0; }

@media (min-width: 40rem) { .facts { grid-template-columns: repeat(4, 1fr); } }

.facts div { display: grid; gap: .2rem; }

.facts dt {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.facts dd { margin: 0; font-family: var(--display); font-size: var(--t-md); color: var(--ink); }

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

.form { display: grid; gap: 1.1rem; max-width: 34rem; }
.field { display: grid; gap: .3rem; }

.field label { font-size: var(--t-sm); font-weight: 600; color: var(--ink); }
.field .hint { font-size: var(--t-xs); color: var(--ink-2); }

.field input, .field select, .field textarea {
  font-family: var(--text);
  font-size: var(--t-0);
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: .65rem .75rem;
  width: 100%;
}

.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--violet); }
.field textarea { resize: vertical; min-height: 7rem; }

.flag {
  border-left: 2px solid var(--violet);
  padding: .1rem 0 .1rem 1.1rem;
  display: grid;
  gap: .4rem;
  max-width: 34rem;
}

.flag p { font-size: var(--t-sm); color: var(--ink-2); }
.flag strong { color: var(--ink); }

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

.foot {
  border-top: 1px solid var(--hair);
  padding-block: 2rem 1.75rem;
  font-size: var(--t-sm);
  color: var(--ink-2);
}

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

.foot__row {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem 2rem;
  justify-content: space-between;
  align-items: baseline;
}

.foot ul { display: flex; flex-wrap: wrap; gap: .4rem 1.5rem; list-style: none; margin: 0; padding: 0; }

.foot__last { margin-top: 1.25rem; font-size: var(--t-xs); }

/* -------------------------------------------------------------- spacing -- */

.u-mt { margin-top: 1.5rem; }
.u-mt-lg { margin-top: 2.5rem; }
.u-mb-lg { margin-bottom: 2.5rem; }

.job__shot--wide { aspect-ratio: 16 / 10; margin-block: 2rem; }

/* ------------------------------------------------- high contrast mode -- */

/* Windows High Contrast Mode replaces every colour and drops most backgrounds.
   Anything whose shape came from a background fill loses that shape, so the
   things that were buttons stop looking like buttons. System colour keywords
   are the only ones honoured here — everything else is overridden. */
@media (forced-colors: active) {
  a, button { forced-color-adjust: none; color: LinkText; }
  a:focus-visible, button:focus-visible { outline: 3px solid Highlight; }

  /* Give every button a real border, since its fill has gone. */
  .btn, .go, .go--line, .btn--go, .btn--quiet, .map__load,
  .sessions__book, .sessions__add, .bar__toggle, .bar__cta {
    forced-color-adjust: none;
    color: ButtonText;
    background: ButtonFace;
    border: 1px solid ButtonText;
  }

  /* Decorative fills that carried meaning become outlines instead. */
  .sessions__badge, .map, .shot--framed { border: 1px solid CanvasText; }

  img { forced-color-adjust: none; }
}

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

/* Printing a timetable for the fridge, or an address to take with you, is a
   real thing people do with these sites. Navigation and buttons are not
   useful on paper; the destination of a link is. */
@media print {
  @page { margin: 15mm; }

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

  .bar, .foot, .top, .endline, .skip, .touchline, .crossbar,
  .btns, .gos, .go, .btn, .sessions__book, .sessions__add,
  .bar__toggle, .bar__cta, .map, .map__load {
    display: none !important;
  }

  main { padding: 0; }
  a { color: #000; text-decoration: underline; }

  /* A printed link with no address is a dead end. */
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; word-break: break-all; }
  a[href^="mailto"]::after { content: " (" attr(href) ")"; font-size: 9pt; }

  h1, h2, h3, li, tr, .venue, .job { break-inside: avoid; page-break-inside: avoid; }
  h1, h2, h3 { break-after: avoid; }

  img { max-width: 100% !important; }
}

/* ------------------------------------------------------- client marks -- */

/* The clients' own logos, not photographs of their premises or their students.
   Using a picture of identifiable children to advertise a third business is a
   consent question nobody needed to have: those parents agreed to Academi
   using it, not to me marketing with it. A logo is the brand's own asset,
   given to be shown, and it identifies the work just as well.

   A mark is not a photograph, so it gets a plate and breathing room rather
   than being stretched to fill a frame. */
.job__mark {
  display: grid;
  place-items: center;
  background: var(--shade);
  border: 1px solid var(--hair);
  border-radius: 2px;
  aspect-ratio: 16 / 10;
  padding: clamp(1.5rem, 5vw, 2.5rem);
}

/* The responsive pass wraps every image in <picture>, so THAT is the grid item
   and the <img> inside it aligns left regardless of place-items. Same trap as
   the tutor portrait on Academi: size and centre the wrapper, not just the
   image. */
.job__mark picture { display: grid; place-items: center; width: 100%; height: 100%; }

.job__mark img {
  width: auto;
  height: auto;
  max-width: min(100%, 11rem);
  max-height: 100%;
  object-fit: contain;
}

.job__mark--wide { aspect-ratio: 21 / 9; }
.job__mark--wide img { max-width: min(100%, 14rem); }

/* The Rugby badge is a circle printed on a square of its own cream, which sits
   visibly on our plate as a slightly-wrong rectangle. Clipping to the circle
   the logo already is removes the seam without altering the mark. */
.job__mark img[src*="mark-rugby"] { border-radius: 50%; }
