/* Petal & Code -- homepage.
 *
 * This stylesheet is deliberately self-contained and used by index.html
 * alone. The homepage runs on a different identity from the rest of the
 * site (Greenhouse: greens, pink and gold, Fraunces for display,
 * Instrument Sans for text, IBM Plex Mono for labels) and the other twenty-four pages still run on the original
 * one (plum and cream, Playfair and Karla, in base.css / marketing.css /
 * portal.css). Keeping the two apart in separate files is what makes
 * that possible without a single shared rule leaking across and
 * restyling a page nobody looked at. Nothing here is imported anywhere
 * else, and index.html loads nothing else.
 */

/* ---------------------------------------------------------------- Fonts */

/* Two faces doing two jobs. Fraunces carries every display moment --
   it is a variable serif with an optical-size axis, a softness axis and
   a WONK axis that swaps in cocked, irregular letterforms, and it is
   the reason the page stops looking like every other studio site built
   on a chunky grotesque. Instrument Sans does all the reading. */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('../assets/fonts/fraunces-var.woff2') format('woff2');
}

@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../assets/fonts/instrumentsans-var.woff2') format('woff2');
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/plexmono-400.woff2') format('woff2');
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/plexmono-500.woff2') format('woff2');
}

/* --------------------------------------------------------------- Tokens */

:root {
  /* Surfaces. */
  --cream: #faf6ef;
  --beige: #efe8db;
  --dark: #22301f;

  /* Two greens, and the distinction between them matters.
     --leaf is the mockup's #5d7c4e. It sits almost exactly halfway up
     the luminance range, which means it cannot carry text at 4.5:1 in
     either direction -- solid cream on it measures 4.37:1 and the pink
     measures 2.79:1. So --leaf is for decorative surfaces only: the
     hero panel, loose petals, small accents, nothing anyone has to
     read.
     --leaf-deep is the same hue at 94%. That is a 6% shift -- next to
     the hero panel you cannot see it -- and it is what lets solid cream
     body copy clear 4.5:1 (4.82:1). Every green surface with words on
     it uses this one, and the copy on it is solid cream rather than a
     softened alpha: there is no headroom on a mid green for both.
     An earlier attempt took it to 80% so that softened copy would pass;
     it did, but at that depth the third service card and the fourth
     (--dark) read as the same colour. */
  --leaf: #5d7c4e;
  --leaf-deep: #577549;
  /* One more step down, for accent text on the beige bands. --leaf-deep
     was picked to carry cream on top of it, not to be read on a light
     ground -- it measures 4.26:1 on --beige and 4.14:1 on the alternate
     band. This one clears 4.5 on both. */
  --leaf-ink: #526e45;

  --pink: #f2b8c6;

  /* Syntax colours for the hero mark. The first set was drawn from the
     brand tints straight, and the base pink measured 1.57:1 against the
     cream with the punctuation at 1.27:1 -- the code dissolved into the
     background at the size it renders. These are the same hues carried
     down until the bulk clears 2.7:1 and the faintest token clears 2:1,
     which is as far as they go before the flower turns dusty rather
     than pink. Four are pinks so the mark still reads as one flower
     from across the room; the gold is the centre's, used only on
     comments, which are rare enough to fleck rather than tint. */
  --code-val: #d17f99;
  --code-prop: #c06a87;
  --code-sel: #98476a;
  --code-punc: #e09cb2;
  --code-note: #b0741a;
  /* A second, slightly deeper pink. Alternating the two around the
     daisy is most of what stops it reading as clip-art. */
  --pink-2: #e7a3b6;
  /* The hero mark is drawn in type rather than filled, so the two pinks
     above -- picked to read as flat shapes -- come out as a whisper at
     3px. These are the same hues carried down until the code holds the
     silhouette on its own: 2.63 and 2.34 against cream, against 1.57
     for the fill pinks. */
  --gold: #e2a13d;

  /* These six were literals scattered through the sheet. Named here so
     a repaint is one edit rather than a search: the pink hover state,
     the raised paper the proof card and the form panels sit on, the
     alternating offer band, the checked-checkbox tint, the error red
     (5.9:1 on cream) and the dark button hover. */
  --pink-hover: #eda7b8;
  --panel-cream: #fffdf8;
  --band-alt: #efe4d8;
  --leaf-tint: #f1f3ec;
  --error: #8c2f22;
  --dark-hover: #182317;
  /* The primary button on any light ground: the studio's own gold, the
     one in the flower's centre and on the second service card. Warm
     suits "free consultation" better than a correct green does, and it
     gives the palette one job each -- pink is the brand, gold is the
     action, green is the ground.

     Dark ink on it, not cream. That reads at 6.22:1 and passes at any
     size; cream on the same gold is 3.10:1 and does not.

     The gold's own weakness is the shape rather than the label: against
     cream the fill is 2.07:1 and against the closing card 1.83:1, so
     with no edge the button melts into the page. The border is what
     fixes that -- deep enough to clear the 3:1 that WCAG 1.4.11 asks of
     a control's boundary (3.56:1 on cream, 3.15:1 on the closing card)
     while still reading as a darker edge of the same gold rather than
     an outline in a different colour. */
  --btn-primary: #e2a13d;
  --btn-primary-hover: #d3922e;
  --btn-primary-ink: #22301f;
  /* No rim, at Rosie's direction. The amber fill reaches 2.07:1 against
     cream, so WCAG 1.4.11 -- which asks 3:1 of a control's boundary --
     is not met by the fill alone and the rim was what met it. The label
     is still 6.22:1 on the amber, so the words are never in doubt; what
     is lost is the edge being findable for someone who cannot separate
     the amber from the cream behind it. Kept as a token set to
     transparent rather than deleted, so the button's box does not
     change size and the rim is one value away if it is ever wanted
     back. */
  --btn-primary-edge: transparent;

  /* Text. The alphas here are all a notch above the ones in the design
     file, which were set by eye and land between 3.4:1 and 4.4:1. Each
     is the lowest value that reaches 4.5:1 on its own background, so
     the weights stay as close to the drawing as the standard allows. */
  --ink: var(--dark);
  --ink-soft: rgba(34, 48, 31, .72);      /* on cream  -> 5.48:1 */
  --ink-mute: rgba(34, 48, 31, .70);      /* on cream  -> 4.75:1 */
  --ink-on-gold: rgba(34, 48, 31, .85);   /* on gold   -> 4.71:1 */
  --ink-on-pink: rgba(34, 48, 31, .75);   /* on pink   -> 4.61:1 */
  --paper: var(--cream);
  --paper-soft: rgba(250, 246, 239, .75); /* on dark   -> 7.98:1 */
  --paper-mute: rgba(250, 246, 239, .55); /* on dark   -> 5.10:1 */
  --paper-on-leaf: #faf6ef;               /* on leaf-deep -> 4.82:1 */

  /* One scale, eight steps. The design file typed every size by hand,
     which left nineteen of them in use -- 24 and 23 sitting next to
     each other doing the same job, three sizes between 13 and 15 all in
     heavy rotation. Nothing below is a new decision; each step is the
     nearest round value to the cluster it replaces. */
  --t-xs: 12px;    /* uppercase micro-labels */
  --t-sm: 14px;    /* component copy, links, controls, mono numbers */
  --t-md: 16px;    /* body */
  --t-lg: 19px;    /* lead paragraphs, the wordmark */

  --d-sm: clamp(20px, 1.9vw, 24px);   /* card and step titles */
  --d-md: clamp(26px, 2.9vw, 33px);   /* minor section heads, pull-quote */
  --d-lg: clamp(33px, 4.2vw, 52px);   /* major section heads */
  --d-xl: clamp(40px, 5.9vw, 76px);   /* the headline */

  /* And one vertical step, so sections stop being padded at 72, 64, 64,
     72 and 48 for no reason anyone could name. */
  --section-y: 72px;

  --display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --sans: 'Instrument Sans', 'Segoe UI', system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --radius-card: 20px;
  --radius-pill: 999px;
  /* Buttons are pills. The nav's "Free consultation" always was one, and
     the same words in the page body were a 14px rounded rect: the one
     hard-cornered shape on a page of pill nav links and petal-cornered
     cards, which is what made the button read as bolted on rather than
     drawn with everything else. The amber and its rim are unchanged --
     the fill only reaches 2.07:1 on cream, so the rim is what makes the
     control findable at its edge, and it has to stay. */
  --radius-btn: var(--radius-pill);

  --shell: 44px;

  /* One content column for every page that lays out in columns. It was
     five different widths -- work and about on 1080, services on 1120,
     contact on 1240, and the legal pages on 720 -- so the content edge
     moved every time you changed page, under a header that was doing
     the same thing. 1080 is what .wrap already declared and what the
     footer bar and .hp-grid were already using, so it wins by being the
     one the most things already agreed on.

     The legal pages keep their own narrower measure: 720 is a reading
     width for continuous prose, which is a different job. */
  --content: 1080px;
}

/* --------------------------------------------------------------- Reset */

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

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

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* The hero panel and the footer daisy both run past the right edge by
     design. They are clipped by their own containers rather than here,
     so this is a backstop, not the mechanism. */
  overflow-x: hidden;
}

h1, h2, h3, p, figure { margin: 0; }

/* Form controls do not inherit type from their ancestors -- they take
   the UA default, which is Arial here. The burger's label was the only
   one showing it and it is visually hidden, but any button text added
   to this page later would have set in Arial without this. */
button, input, select, textarea { font: inherit; }
img { display: block; max-width: 100%; }
ul, ol { margin: 0; padding: 0; list-style: none; }

a { color: inherit; }

/* One visible focus ring for the whole page, in a colour that clears
   3:1 against every surface it can land on. */
a:focus-visible,
button:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 3px;
  border-radius: 4px;
}

.hp-skip {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 100;
  background: var(--dark);
  color: var(--cream);
  padding: 12px 20px;
  border-radius: var(--radius-btn);
  font-weight: 800;
  font-size: var(--t-md);
  text-decoration: none;
  transition: top .18s ease;
}

.hp-skip:focus { top: 12px; }

main:focus { outline: none; }

/* Reachable by a screen reader, absent from the page. Used for the
   burger's label, which is otherwise three unlabelled bars. */
.hp-sr {
  position: absolute;
  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;
}

.hp-mono { font-family: var(--mono); }

/* Every display moment, in one place. SOFT 40 takes the hard corners
   off the serifs and WONK 1 turns on the irregular alternates -- the
   two axes together are what make it read as cut rather than picked.
   Optical sizing is left at its default of auto, so the 19px wordmark
   and the 58px headline get different drawings of the same face.
   Deliberately not on .hp-footer-col h2, which is an 11px uppercase
   label rather than a heading, nor on buttons and links, which are
   controls and want the sans. */
.hp-brand,
.hp-hero h1,
.hp-services h2,
.hp-work h2,
.hp-process h2,
.hp-cta h2,
.hp-card h3,
.hp-step h3,
.hp-case-name,
.hp-footer-word {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  /* A serif at display size does not want a grotesque's negative
     tracking -- at -.03em the joins started closing up. */
  letter-spacing: -.018em;
}

/* Fraunces' optical-size axis swaps in a swash ampersand somewhere
   between 19px and 24px. That left the wordmark drawn one way in the
   nav and another in the footer -- two logotypes on one page -- and
   turned three process headings into "Design (swash) feedback", which
   reads as a broken font. Pinning optical sizing on the ampersand alone
   keeps the display face's optical sizing everywhere else, which is
   most of the reason to use Fraunces at all. */
.amp {
  font-optical-sizing: none;
  font-variation-settings: 'SOFT' 40, 'WONK' 0;
}

/* ------------------------------------------------------------- The mark */

/* Six petals at 60 degrees around a centre, plus a disc. One ratio set,
   driven by --d, so the nav mark, the hero mark and the footer mark are
   the same drawing at three sizes rather than three drawings that
   happen to look alike. */
.daisy {
  position: relative;
  width: var(--d);
  height: var(--d);
  flex: none;
}

.daisy-petal {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--d) * .35);
  height: calc(var(--d) * .5);
  background: var(--petal, var(--pink));
  border-radius: 60% 60% 60% 60% / 70% 70% 45% 45%;
  transform-origin: 50% 100%;
}

/* Six identical petals at exact 60 degree intervals in one flat pink is
   the flower a child draws -- regular enough that the eye reads it as
   clip-art before it reads it as a mark. A few degrees of drift, petal
   lengths that differ by a couple of percent, and two pinks alternating
   make the same drawing look placed by a person. All of it is small
   enough that at the 26px nav size nothing is visibly irregular; it is
   at 340px in the hero that it does the work. */
.daisy-petal:nth-child(1) { transform: translate(-50%, -100%) rotate(-3deg);  height: calc(var(--d) * .52); }
.daisy-petal:nth-child(2) { transform: translate(-50%, -100%) rotate(58deg);  height: calc(var(--d) * .485); background: var(--pink-2); }
.daisy-petal:nth-child(3) { transform: translate(-50%, -100%) rotate(123deg); height: calc(var(--d) * .5); }
.daisy-petal:nth-child(4) { transform: translate(-50%, -100%) rotate(179deg); height: calc(var(--d) * .515); background: var(--pink-2); }
.daisy-petal:nth-child(5) { transform: translate(-50%, -100%) rotate(240deg); height: calc(var(--d) * .49); }
.daisy-petal:nth-child(6) { transform: translate(-50%, -100%) rotate(304deg); height: calc(var(--d) * .505); background: var(--pink-2); }

.daisy-eye {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--d) * .28);
  height: calc(var(--d) * .28);
  background: var(--gold);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: calc(var(--d) * .1);
  font-weight: 500;
  color: var(--dark);
  letter-spacing: -.02em;
}

/* A loose petal, used as punctuation. */
.petal {
  position: absolute;
  background: var(--petal, var(--pink));
  border-radius: 60% 60% 60% 60% / 70% 70% 45% 45%;
}

/* The loose petals are measured out from the middle of the hero, not in
   from its edges. On a percentage they drifted further out the wider the
   screen got: at 1920 they sat in empty margin with nothing to belong
   to, which is what made them look randomly dropped. From the centre
   they hold the same distance from the mark at every width, and they
   stay in the upper half where the mark is, so they read as having come
   off it.

   Four is the count. They work because they are sparse; a fifth and a
   sixth would be confetti. */
.hp-hero .petal { opacity: .7; }
/* The four loose petals are gone. Anchored from the centre they held
   their distance at every width, but that is exactly what made them
   look scattered on a wide screen: four marks at four heights with no
   relationship to anything on the page. Twice now they have read as a
   fault rather than as confetti, which is the answer. */
.petal-1, .petal-2, .petal-3, .petal-4 { display: none; }

/* Below this there is no margin either side of the 860px content column
   to hold them, and a petal with nowhere to sit lands on the headline
   instead. */
@media (max-width: 1040px) {
  .hp-hero .petal { display: none; }
}

/* The mark does not move. It swayed and swelled on a 9s loop, then came
   back as rotation alone, and both readings were the same: a slow turn
   on a dense block of small type is a distraction from the one thing on
   the page you want someone to stop and read. The loose petals hold no
   type but they sat still while the mark turned, which only drew
   attention to the turn. Nothing in the hero animates. */
@media (prefers-reduced-motion: reduce) {
  .hp-skip { transition: none; }
  * { scroll-behavior: auto !important; }
}

/* ------------------------------------------------------------------ Nav */

.hp-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
  padding: 18px var(--shell);
  background: var(--dark);
  color: var(--cream);
}

.hp-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 800;
  font-size: var(--t-lg);
  letter-spacing: -.01em;
  text-decoration: none;
}

.hp-nav-links {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--t-sm);
  font-weight: 600;
}

.hp-nav-links a {
  display: inline-flex;
  align-items: center;
  /* Flex drops the whitespace between the label and a trailing glyph,
     so "Say hello ✳" would set as "Say hello✳" without this. */
  gap: .4em;
  padding: 11px 16px;
  border-radius: var(--radius-pill);
  border: 1px solid rgba(250, 246, 239, .3);
  text-decoration: none;
  transition: background-color .18s ease, border-color .18s ease;
}

/* Hover paint is behind a hover query for the whole site. A touch
   screen has no pointer, but iOS holds :hover on the last thing you
   tapped until you tap something else, so after following a nav link
   and coming back the link you left from was still painted as though a
   cursor were resting on it -- which is exactly what a selected tab
   looks like. aria-current still marks the page you are actually on,
   and :focus-visible still marks the keyboard's position. */
@media (hover: hover) {
  .hp-nav-links a:hover {
    background: rgba(250, 246, 239, .12);
    border-color: rgba(250, 246, 239, .55);
  }
}

.hp-nav-links a[aria-current="page"] {
  background: rgba(250, 246, 239, .16);
  border-color: rgba(250, 246, 239, .6);
}

/* The login is for existing clients, not for the people this page is
   written for, so it is present without competing. */
.hp-nav-links .hp-nav-quiet {
  border-color: transparent;
  color: rgba(250, 246, 239, .72);
}

@media (hover: hover) {
  .hp-nav-links .hp-nav-quiet:hover { color: var(--cream); }
}

/* The same amber as the consultation button in the page body, from the
   same token: one call to action, one colour, wherever it appears. On
   the dark bar the amber reads at 6.22:1 as a shape and its dark label
   at 6.22:1 on the amber, so unlike the button on cream this one needs
   no rim to be found. */
.hp-nav-links .hp-nav-cta {
  background: var(--btn-primary);
  color: var(--btn-primary-ink);
  border-color: var(--btn-primary);
  font-weight: 800;
  white-space: nowrap;
}

@media (hover: hover) {
  .hp-nav-links .hp-nav-cta:hover {
    background: var(--btn-primary-hover);
    border-color: var(--btn-primary-hover);
  }
}

.hp-burger {
  display: none;
  width: 46px;
  height: 46px;
  padding: 0;
  border: 1px solid rgba(250, 246, 239, .3);
  border-radius: 12px;
  background: none;
  color: inherit;
  cursor: pointer;
}

.hp-burger span {
  display: block;
  width: 20px;
  height: 2px;
  margin: 4px auto;
  background: currentColor;
  border-radius: 2px;
}

/* ----------------------------------------------------------------- Hero */

/* One centred column on cream, not a two-up with a green panel. The
   panel was taking half the first screen to hold a flower, and boxing
   the mark in a rectangle made it read as an illustration sitting in a
   slot rather than as the studio's mark. On the open cream the dot grid
   carries the texture the panel used to, and the mark gets to be the
   thing you see first. */
.hp-hero {
  position: relative;
  overflow: hidden;
  padding: 44px var(--shell) 68px;
  background-image: radial-gradient(rgba(34, 48, 31, .085) 1.4px, transparent 1.4px);
  background-size: 26px 26px;
}

.hp-hero-inner {
  position: relative;
  z-index: 1;
  max-width: 860px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 24px;
}

/* The mark is sized by what its code needs to be legible, not by what a
   logo would need. The type is a fixed fraction of --d, so at the old
   250px it rendered at 4.75px -- pink noise. 330px with a slightly
   larger fraction puts it at 7.1px, the point where you can see it is
   CSS without leaning in, and costs 40px less height than reaching the
   same size by growing the mark alone. */
.hp-hero-daisy { --d: 330px; }

/* One bloom on arrival and then still. The mark carries readable code,
   and anything that loops competes with the words beside it -- which is
   what the old pulse did. This runs once, lasts under a second, and
   never repeats, so there is nothing to pause. */
@media (prefers-reduced-motion: no-preference) {
  .hp-hero-daisy { animation: hp-bloom .9s cubic-bezier(.2, .7, .3, 1) both; }
}

@keyframes hp-bloom {
  from { opacity: 0; transform: scale(.9) rotate(-5deg); }
  to   { opacity: 1; transform: none; }
}

.hp-hero-copy {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
}

.hp-hero h1 {
  font-weight: 800;
  font-size: var(--d-xl);
  /* Was 1.02, which is the right leading for plain display type but not
     for this headline: .hp-hl paints a chip behind the second line, and
     an inline background is drawn to the line box, so at 1.02 its top
     edge landed on the descenders of "Your business," -- the comma sat
     in the pink. Vertical padding on the chip cannot buy the room back,
     because padding on an inline element does not grow the line box, it
     just overflows further into the line above. The leading has to do
     it. 1.16 clears the descenders at both the 40px mobile floor and
     the 76px desktop ceiling while still reading as display-tight. */
  line-height: 1.16;
  letter-spacing: -.03em;
  text-wrap: balance;
}

.hp-hl {
  /* A background on an inline element is painted to the font's content
     box, not to its letters, and Fraunces asks for a lot of room it does
     not use: at 40px the chip came out 49px tall for 32px of actual
     letter, so a third of it was empty pink. That is what made it read
     as a slab sitting behind the words rather than a highlight drawn
     over them. The pink is a background image sized to the type instead,
     which is also why it is bottom-weighted -- a marker leaves more
     under the baseline than over the cap. */
  background: linear-gradient(var(--pink), var(--pink)) no-repeat;
  background-size: 100% 82%;
  background-position: 0 66%;
  /* In em, so the chip keeps the same relationship to the letters at
     every step of the display clamp. A flat 12px was a tight collar on
     a 40px headline and a loose one at 76px, where it pushed the second
     line noticeably wider than the first. */
  padding: 0 .16em;
  border-radius: .18em;
  /* The chip is a background behind live text, so the box has to grow
     with the line rather than clip it. */
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  /* And it must not break across lines. At 1440 the headline wrapped
     between the two words and clone dutifully drew two chips, one per
     fragment -- "full" in a box above "bloom" in another. The line
     breaks before the chip instead. */
  white-space: nowrap;
}

.hp-hero-sub {
  font-size: var(--t-lg);
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 34em;
  /* pretty only guards the last line against a single orphaned word,
     which left the middle of the block to fall where it liked: on a
     390px phone it broke "from the / first call" and set "you get. An"
     in the middle of a line, so the two sentences ran into each other.
     balance evens every line instead, and on a block this short it puts
     the break where the full stop already is: the first sentence ends a
     line and the second starts one. Declared after pretty so a browser
     without balance still gets the better of the two it knows. */
  text-wrap: pretty;
  text-wrap: balance;
}

.hp-hero-actions {
  display: flex;
  gap: 20px;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
}

/* Evidence on the first screen, pinned to the corner of the grid like a
   print on a board. It was a dark bar across a green panel, which read
   as a cookie notice; and at 62x44 a whole website screenshot was
   illegible mush rather than proof. Absolutely placed so the centred
   column stays centred -- it is the one thing on this screen that is
   deliberately off-axis. */
.hp-proof {
  position: absolute;
  left: max(calc(var(--shell) + 18px), calc((100% - 1240px) / 2));
  bottom: 84px;
  z-index: 1;
  width: 168px;
  padding: 7px 7px 0;
  background: var(--panel-cream);
  color: var(--dark);
  border: 1px solid rgba(34, 48, 31, .10);
  border-radius: 6px;
  box-shadow: 0 14px 30px -14px rgba(34, 48, 31, .35);
  transform: rotate(-2.4deg);
  text-decoration: none;
  transition: transform .2s ease, box-shadow .2s ease;
}

@media (hover: hover) {
  .hp-proof:hover {
    transform: rotate(0deg) translateY(-3px);
    box-shadow: 0 18px 36px -14px rgba(34, 48, 31, .42);
  }
}

.hp-proof img {
  display: block;
  width: 100%;
  height: 106px;
  object-fit: cover;
  object-position: center top;
  border-radius: 3px;
}

.hp-proof-cap { display: block; padding: 9px 3px 11px; }

.hp-proof-k {
  display: block;
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: rgba(34, 48, 31, .70);
}

.hp-proof-n {
  display: block;
  margin-top: 2px;
  font-size: var(--t-sm);
  font-weight: 700;
  letter-spacing: -.01em;
  line-height: 1.2;
}

@media (prefers-reduced-motion: reduce) {
  .hp-proof { transition: none; }
  .hp-proof:hover { transform: rotate(-2.4deg); }
}

/* -------------------------------------------------------------- Controls */

.hp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45em;
  min-height: 48px;
  padding: 13px 28px;
  border-radius: var(--radius-btn);
  /* The label is a sentence, not a word, so it has to be allowed to
     wrap and stay centred when it does rather than push the button
     past its column. */
  text-align: center;
  /* One action, inverted for the ground it sits on. The nav bar is dark
     so its button is pink; the page is light so this one is dark. Both
     are the same button, and each is the loudest thing on its own
     background: 12.90:1 here against cream and the beige closing card,
     8.24:1 for the pink one against the bar.

     Pink everywhere was measured and did not hold up. The label read at
     8.24:1, but the button *shape* against cream came out at 1.57:1 and
     against the closing card 1.38:1 -- legible words on a form that
     barely separated from the page at the two moments the page is
     asking for the click. */
  background: var(--btn-primary);
  color: var(--btn-primary-ink);
  border: 1.5px solid var(--btn-primary-edge);
  font-weight: 800;
  font-size: var(--t-sm);
  text-decoration: none;
  transition: background-color .18s ease, transform .18s ease;
}

@media (hover: hover) {
  .hp-btn:hover { background: var(--btn-primary-hover); }
}
.hp-btn:active { transform: translateY(1px); }

.hp-link {
  display: inline-flex;
  align-items: center;
  gap: .4em;
  min-height: 44px;
  font-weight: 800;
  font-size: var(--t-sm);
  text-decoration: underline;
  text-underline-offset: 5px;
  text-decoration-thickness: 2px;
}

.hp-link:hover { text-decoration-thickness: 3px; }

@media (prefers-reduced-motion: reduce) {
  .hp-btn { transition: none; }
}

/* ------------------------------------------------- The hero mark, in code */

/* The hero mark has no fill. Each petal is a shaped container and the
   code inside it IS the petal -- the text rotates with its own petal, so
   the six runs sit at six angles and the changes of direction between
   them are what draw the silhouette. An earlier attempt kept one upright
   sheet across all six and they merged straight back into the rectangle
   they were cut from; rotating the text with the petal is the whole
   trick.
   Hero only. At 26px in the nav or on a favicon this is a pink blur, so
   those marks stay solid -- the same drawing, two treatments.
   The rules are carried as generated content: cached with the
   stylesheet, absent from the HTML, unselectable, and invisible to
   find-in-page and translation tools, which is what you want from
   something that is texture rather than text. */
.hp-hero-daisy .daisy-petal {
  background: none;
  overflow: hidden;
}

/* The petals are filled with the stylesheet that draws them, coloured
   the way an editor would colour it. Values are by far the most common
   token, so they carry the mark's base pink -- give that slot the gold
   and the flower turns orange. The rarer tokens take the accents:
   selectors a deep rose, comments the centre's gold. */
.hp-hero-daisy .daisy-src {
  position: absolute;
  inset: 0;
  padding: 2px 3px;
  font-family: var(--mono);
  font-size: calc(var(--d) * .0215);
  line-height: 1.14;
  /* The source is written without spaces so break-all can pack it into
     the petal solid. With spaces it wraps at word boundaries and leaves
     ragged gaps at the tips, and the silhouette stops reading. */
  word-break: break-all;
  /* 500 is the heaviest mono weight actually hosted. 600 renders a
     little crisper but only via the browser's synthetic bold, which
     differs engine to engine, and a third font file for one decorative
     element is not worth it -- the colour change is what fixed the
     legibility here, not the weight. */
  font-weight: 500;
  -webkit-user-select: none;
  user-select: none;
}

.hp-hero-daisy .daisy-src i { font-style: normal; }

.hp-hero-daisy .daisy-src .v { color: var(--code-val); }
.hp-hero-daisy .daisy-src .p { color: var(--code-prop); }
.hp-hero-daisy .daisy-src .s { color: var(--code-sel); }
.hp-hero-daisy .daisy-src .b { color: var(--code-punc); }
.hp-hero-daisy .daisy-src .c { color: var(--code-note); }

/* ------------------------------------------------------------- Services */

.hp-services {
  padding: var(--section-y) var(--shell);
  background: var(--beige);
}

/* A supporting line under a section heading. The head is a flex row of
   title and link, so the title and its note are wrapped together in the
   left-hand child rather than added as a third sibling, which would have
   put the note beside the link instead of under the heading. */
.hp-section-note {
  margin-top: 8px;
  max-width: 46em;
  font-size: var(--t-md);
  line-height: 1.6;
  color: var(--ink-soft);
}

.hp-section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 24px;
  flex-wrap: wrap;
  margin-bottom: 32px;
}

.hp-services h2 {
  font-weight: 800;
  font-size: var(--d-lg);
  letter-spacing: -.03em;
  line-height: 1.05;
}

/* Three capabilities, three columns. This was repeat(4) when the studio
   sold four services; keeping four tracks for three cards left a hole in
   the row that read as a missing card rather than a deliberate set. */
.hp-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.hp-card {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 28px 24px;
  /* Petal corners: the top-left and bottom-right soft, the other two
     tight. Every card the same way round -- mirroring alternate cards
     made the row look like it had been assembled wrong rather than
     drawn on purpose. */
  border-radius: 64px 18px 64px 18px;
  text-decoration: none;
  transition: transform .2s ease;
}

/* The cards used to sit at four uneven tilts. The petal corners now
   carry the informality on their own, and the two together read as a
   layout fault rather than as a choice, so the row sits straight. */
@media (hover: hover) {
  .hp-card:hover { transform: translateY(-4px); }
}

.hp-card h3 {
  font-size: var(--d-sm);
  font-weight: 800;
  letter-spacing: -.02em;
  margin-bottom: 8px;
}

.hp-card p {
  font-size: var(--t-sm);
  line-height: 1.55;
}
/* Body copy on a coloured card is not softened. On the cream page a
   quieter grey under a heading is right, but these four cards each need
   a different amount of softening to stay legible -- pink survives 75%,
   gold needs 85%, and leaf fails at every value below 100% -- so
   borrowing the idea produced three different greys with no visible
   reason for the difference, side by side. The ink is the ink; size and
   weight already separate the heading from the paragraph. */
.hp-card-pink { background: var(--pink); color: var(--dark); }

.hp-card-gold { background: var(--gold); color: var(--dark); }

.hp-card-leaf { background: var(--leaf-deep); color: var(--cream); }
/* Cream, not pink: the pink number measures 3.08:1 on this green and
   13px mono is small text. Pink stays on --dark, where it is 8.24:1. */

.hp-card-dark { background: var(--dark); color: var(--cream); }

@media (prefers-reduced-motion: reduce) {
  .hp-card, .hp-btn { transition: none; }
  .hp-card:hover { transform: rotate(0deg); }
}

/* ------------------------------------------------------------ Case study */

.hp-work { padding: var(--section-y) var(--shell); }

.hp-work h2 {
  font-weight: 800;
  font-size: var(--d-md);
  letter-spacing: -.02em;
  margin-bottom: 24px;
}

.hp-case {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  border-radius: 18px;
  overflow: hidden;
  background: var(--leaf-deep);
  color: var(--cream);
  text-decoration: none;
}

/* The shot keeps its own ratio and sits centred in its column, rather
   than stretching to the card's full height.

   Stretched, the card's height came from the body copy beside it, not
   from the image, so cover had to scale a 1.93:1 screenshot up until it
   filled a much taller box and then trim the difference off the width:
   20% gone at 1440, a third at 1280, 45% at 1100. Anchoring left saved
   the client's logo but spent the whole trim on the right, which is
   where their own "Start your project" button sits, so the site being
   shown as finished work appeared with its main call to action sliced in
   half. Below 1040 the card already stacks for exactly this reason; this
   applies the same answer to the two-column range instead of choosing
   which end of someone's homepage to cut off.

   Sitting the shot at its own ratio inside a stretched column left a
   thin band of green above and below it, which read as a bleed that had
   failed rather than a decision. An even margin, a small radius and a
   shadow make it a screenshot presented on a mat instead, which is what
   it actually is. */
.hp-case-shot {
  width: calc(100% - 56px);
  height: auto;
  align-self: center;
  margin: 28px;
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .22);
}

.hp-case-body {
  padding: 40px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 12px;
}

/* Cream, not the design file's pink: at 12px this is small text, and
   pink on green measures 3.96:1 even after the green was deepened. */
.hp-case-eyebrow {
  font-size: var(--t-xs);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--cream);
}

.hp-case-name {
  font-size: var(--d-md);
  font-weight: 800;
  letter-spacing: -.02em;
}

.hp-case-meta {
  font-size: var(--t-sm);
  color: var(--paper-on-leaf);
}

.hp-case p {
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--paper-on-leaf);
}

.hp-case-go {
  display: inline-flex;
  align-items: center;
  gap: .4em;
  /* On the work page this is a standalone link on its own line rather
     than one inside a sentence, so the inline exception to 2.5.8 does
     not cover it and it needs the height itself. */
  min-height: 24px;
  font-size: var(--t-sm);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 4px;
}

.hp-case:hover .hp-case-go { text-decoration-thickness: 2px; }

/* The case study stops sitting beside its screenshot here rather than
   at phone width. The copy column sets the row height, and once the row
   is taller than the image column is wide, object-fit: cover takes the
   difference off the sides: at 1024 only 47% of the shot survived,
   which cut the site being shown in half. Stacked, the image keeps its
   own ratio and all of it is visible.

   It has to sit after .hp-case rather than up with the hero's own
   narrow rules, or the base two-column declaration wins on source order
   and the query does nothing. */
@media (max-width: 1040px) {
  .hp-case { grid-template-columns: 1fr; }
  .hp-case-shot { min-height: 0; height: auto; }
}

/* -------------------------------------------------------------- Process */

.hp-process {
  padding: var(--section-y) var(--shell);
  background: var(--dark);
  color: var(--cream);
}

.hp-process-grid {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 56px;
  /* Centred, not top-aligned. The intro is roughly 294px against a list
     of 490-540, so aligning both to the top left 197-242px of empty
     dark green hanging under the heading -- which is what made the
     section feel unfinished. */
  align-items: center;
}

/* The intro used to be sticky. Its travel was exactly the size of that
   void, so it pinned for about a fifth of a screen and released again
   before anyone registered it had moved -- an effect nobody saw, paid
   for with the gap that made the section look broken. */
.hp-process-intro {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.hp-process h2 {
  font-weight: 800;
  font-size: var(--d-lg);
  line-height: 1.02;
  letter-spacing: -.03em;
}

.hp-process h2 em {
  font-style: normal;
  color: var(--pink);
}

.hp-process-sub {
  font-size: var(--t-md);
  line-height: 1.6;
  color: var(--paper-soft);
  max-width: 320px;
}

.hp-seeds { display: flex; gap: 6px; margin-top: 4px; }

.hp-seed {
  width: 14px;
  height: 20px;
  border-radius: 60% 60% 60% 60% / 70% 70% 45% 45%;
}

.hp-step {
  display: flex;
  gap: 28px;
  align-items: baseline;
  padding: 26px 0;
  border-bottom: 1px solid rgba(250, 246, 239, .15);
}

.hp-step:last-child { border-bottom: 0; }

.hp-step-num {
  font-size: var(--t-sm);
  color: var(--pink);
  flex: none;
  width: 104px;
}

.hp-step h3 {
  font-size: var(--d-sm);
  font-weight: 800;
  letter-spacing: -.01em;
  margin-bottom: 6px;
}

.hp-step p {
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--paper-soft);
}

/* ----------------------------------------------------------- Testimonial */

/* Tom's quote used to be a section of its own beneath the case study,
   and above 1000px a .hp-close wrapper set it beside the closing CTA so
   the pair read as one moment. Both are gone. The quote is evidence for
   one project specifically -- the man quoted runs the business in the
   panel it sat under -- so standing alone it read as a floating
   endorsement, and the page spent a whole section, plus a wrapper and a
   media query, on one sentence. It lives inside the case card now,
   where it is the proof that card is already making, and the CTA stands
   on its own the way it already did on a phone.

   The relationship is disclosed by the summary two lines above it
   ("My brother's business, and my first commission"), so the caption
   does not repeat it. */
.hp-case-quote {
  margin: 14px 0 6px;
  padding: 18px 20px;
  border-radius: 12px;
  /* A step deeper than the card it sits on rather than a lighter colour
     placed on top of it. Every pale panel tried here read as a hole cut
     in the green; going down instead of up keeps the quote inside the
     same family, so it separates without interrupting. Cream measures
     7.66:1 on it and the attribution 5.79:1. */
  background: #3d5533;
  color: var(--cream);
}

.hp-case-quote blockquote {
  margin: 0;
  font-size: var(--t-md);
  line-height: 1.55;
  font-style: italic;
}

.hp-case-quote figcaption {
  margin-top: 8px;
  font-size: var(--t-xs);
  letter-spacing: .03em;
  color: rgba(250, 246, 239, .82);
}

.hp-case-quote figcaption strong { font-weight: 700; }

/* ------------------------------------------------------------- CTA card */

/* The decision moment, rebuilt. It was a green strip with a heading, one
   nine-word line and a button -- less reassurance than the hero button
   3,000px earlier, which at least says "no obligation". Everything that
   settles a nervous buyer lived in the process section far above it.
   Beige rather than green so the primary button can be the same dark
   green it is in the hero: the page taught "dark green = the main
   thing" for three thousand pixels and then switched to pink at the one
   moment it mattered. */
.hp-cta {
  /* Matches .wrap, which is the content column every inner page is laid
     out on. At 940 it sat inset from that column by 70px a side and at
     1180 it overhung it by 50, so on a wide screen the card lined up
     with nothing above it either way -- it read as a band that had come
     loose rather than the end of the page. */
  max-width: min(var(--content), calc(100% - var(--shell) * 2));
  margin: 0 auto;
  background: var(--beige);
  color: var(--ink);
  border: 1px solid rgba(34, 48, 31, .10);
  border-radius: 24px;
  padding: 48px 52px;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 30px 48px;
  position: relative;
  overflow: hidden;
}

/* The card had 72px of air under it -- the footer's own margin -- and
   none at all above, so its rounded top corners met the section above it
   flush and it read as attached to the wrong thing. Matched, so it sits
   between the two.

   But on all four pages that carry this card, the thing above it is a
   section with its own --section-y bottom padding, and the two stacked:
   144px between two cards on a desktop and 88 on a phone, where the
   rhythm everywhere else on the page is one --section-y. The margin now
   applies only when nothing precedes the card to space it. */
main > .hp-cta { margin-top: var(--section-y); }
main > * + .hp-cta { margin-top: 0; }

/* Except when the section above is a filled band. Its bottom padding is
   inside its own colour, so it reads as the band's inset, not as a gap:
   the card's rounded top corners met the dark green flush and the two
   looked welded together. A band needs the air put back. */
main > .hp-band + .hp-cta,
main > .hp-process + .hp-cta { margin-top: var(--section-y); }

/* The design file's decorative blob is gone. It existed to fill a void
   in a card that had a heading, one line and a button in it; this card
   now carries four reassurances and does not need filling. It also
   never survived the crop -- a 50% 0 50% 50% shape clipped by a 24px
   card radius produced a hard diagonal seam across the corner that read
   as a compression artefact rather than a designed edge. */
.hp-cta-blob { display: none; }

/* The measure belongs on the paragraph, not on the column. 30em here
   resolved against the parent's 16px, so it was a flat 480px cap on a
   heading set at 52px -- "Have a project in mind?" needs about 620px,
   so it broke in two and left the sub-line and the button sitting
   against a ragged hole. The paragraph keeps a measure of its own. */
.hp-cta-copy { position: relative; }

/* If a longer heading ever does wrap, it wraps evenly rather than
   dropping one orphaned word onto the second line. */
.hp-cta h2 { text-wrap: balance; }

/* The band that used to close the Work page put its second phrase in
   pink; on the beige card that measures 1.38:1, so this takes the deep
   leaf the page heads already use for the same job. Without a rule the
   em simply rendered italic, which is not what the mark is for. */
.hp-cta h2 em { font-style: normal; color: var(--leaf-deep); }

.hp-cta h2 {
  font-weight: 800;
  font-size: var(--d-lg);
  letter-spacing: -.02em;
  margin-bottom: 10px;
}

.hp-cta p {
  max-width: 48ch;
  font-size: var(--t-md);
  line-height: 1.6;
  color: var(--ink-soft);
}

.hp-cta-act {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}

/* The reassurance, at the point of decision rather than 1,500px above
   it. Ticks are decorative and marked as such; the list is the content. */
.hp-cta-facts {
  position: relative;
  grid-column: 1 / -1;
  margin-top: 4px;
  padding-top: 24px;
  border-top: 1px solid rgba(34, 48, 31, .12);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 32px;
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--ink-soft);
}

.hp-cta-facts li {
  position: relative;
  padding-left: 24px;
}

.hp-cta-facts li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .34em;
  width: 12px;
  height: 12px;
  border-radius: 60% 60% 60% 60% / 70% 70% 45% 45%;
  background: var(--leaf);
}

/* --------------------------------------------------------------- Footer */

.hp-footer {
  background: var(--dark);
  color: var(--cream);
  margin-top: var(--section-y);
  padding: var(--section-y) var(--shell) 28px;
  position: relative;
  overflow: hidden;
}

.hp-footer-daisy {
  --d: 260px;
  position: absolute;
  /* .daisy sets position: relative for its petals; the footer instance
     is placed against the section, so this override has to come after
     the component rule in source order. */
  right: -50px;
  /* Above the bottom bar, which is what the handoff asks for and what
     the design file's own 44px does not achieve: at 44px the petals run
     under the credit line and it measures 2.03:1 against them. Clear of
     the bar, every footer run is back on the dark green at 8.24:1. */
  bottom: 104px;
  opacity: .85;
  pointer-events: none;
}

.hp-footer-grid {
  position: relative;
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: 32px;
  padding-bottom: 48px;
}

.hp-footer-brand {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.hp-footer-word {
  font-weight: 800;
  font-size: var(--d-md);
  letter-spacing: -.02em;
}

.hp-footer-brand p {
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--paper-soft);
  max-width: 300px;
}

/* The three footer links below were each under 24px tall, which is the
   floor WCAG 2.5.8 sets for a pointer target. Padding gets them over it
   without changing where the text sits. */
.hp-footer-email {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 3px 0;
  font-size: var(--t-sm);
  color: var(--pink);
  text-decoration: none;
  align-self: flex-start;
}

.hp-footer-email:hover { text-decoration: underline; }

.hp-footer-col {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: var(--t-sm);
}

.hp-footer-col-h {
  font-size: var(--t-xs);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--paper-mute);
  margin-bottom: 8px;
}

.hp-footer-col a {
  display: inline-block;
  padding: 6px 0;
  text-decoration: none;
}

.hp-footer-col a:hover { text-decoration: underline; }

.hp-footer-bar {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding-top: 22px;
  border-top: 1px solid rgba(250, 246, 239, .15);
  font-size: var(--t-xs);
  color: var(--paper-mute);
}

.hp-footer-bar a { color: inherit; }

.hp-footer-legal { display: flex; gap: 16px; }

.hp-footer-legal a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 3px 2px;
}

/* ------------------------------------------------------- About: the intro

   The heading used to sit in a centred .hp-pagehead above this, which
   left the body copy starting two thirds of the way down its own column
   -- vertically centred against a 560px portrait with nothing above it.
   Heading, lede and copy are one column now, beside the photo, so the
   text starts at the top of the block the way it reads in the design.

   The block still sits inside a real .hp-pagehead, though, because that
   is what carries the dot texture and the closing hairline every other
   page opens with. Without it About was the one page that started on
   flat cream, which is what made it look like a different template
   rather than the same one with a photo in it. */
.hp-intro {
  max-width: var(--content);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.05fr .95fr;
  gap: 56px;
  align-items: start;
}

/* The copy is in two pieces so a phone can put the portrait between
   them, but on a wide screen .hp-intro-copy holds them both and the
   grid sees the same two items it always did: one column of words, one
   photo. An earlier attempt made all three grid items and had the photo
   span two rows, which quietly pushed the story down 18px -- a spanning
   item that is taller than the rows it covers stretches them. */
.hp-intro-body { margin-top: 14px; }

.hp-intro-head h1 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-lg);
  line-height: 1.06;
  letter-spacing: -.025em;
  margin: 10px 0 0;
}

.hp-intro-lede {
  margin-top: 14px;
  font-size: var(--t-lg);
  line-height: 1.55;
  color: var(--ink);
}

.hp-intro-body p + p { margin-top: 14px; }

.hp-intro-body p {
  font-size: var(--t-md);
  line-height: 1.7;
  color: var(--ink-soft);
}

.hp-intro-photo {
  width: 100%;
  height: auto;
  border-radius: var(--radius-card);
}

@media (max-width: 860px) {
  .hp-intro {
    grid-template-columns: 1fr;
    gap: 28px;
  }

  /* The copy wrapper stops being a box, so its two halves become grid
     items in their own right and the portrait can be ordered between
     them: title, sub-line, face, then the story. */
  .hp-intro-copy { display: contents; }
  .hp-intro-head { order: 1; }
  .hp-intro-photo { order: 2; }
  .hp-intro-body { order: 3; margin-top: 0; }

  /* The heading first, the same as every other page. The portrait used
     to be pulled above it -- the thinking was that the face is the point
     of an About page -- but it meant this was the one page whose first
     screen did not say which page you were on. Work and Services both
     open on kicker, title, sub-line; About does now too, and the
     portrait follows the words that introduce it. */
  .hp-intro-photo { max-width: 320px; justify-self: center; }
}

/* ---------------------------------------------- The simple footer

   What the site carried before Greenhouse: one centred column -- the
   four social marks, the address, the legal pair, the line of credit --
   rather than a four-column sitemap. Restored as structure only; the
   palette, type and target sizes are this design's, not the old
   cream-and-terracotta one, so nothing here reaches back into
   marketing.css.

   The nav already carries Work / Services / About / Contact at the top
   of every page, which is what made the sitemap columns repetition
   rather than navigation. */
.hp-footer-simple {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  text-align: center;
}

.hp-social {
  display: flex;
  gap: 12px;
}

/* 42px, well past the 24px WCAG 2.5.8 floor -- these are the smallest
   targets on the page and the ones most often thumbed on a phone. */
.hp-social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 13px;
  border: 1.5px solid rgba(250, 246, 239, .28);
  color: var(--cream);
  transition: color .15s ease, border-color .15s ease, background-color .15s ease;
}

@media (hover: hover) {
  .hp-social-link:hover {
    color: var(--pink);
    border-color: var(--pink);
    background: rgba(242, 184, 198, .1);
  }
}

/* Same 15% cream as .hp-footer-bar's top border, so the two rules in
   this footer and the one in the sitemap footer are one weight. */
.hp-footer-rule {
  width: min(360px, 100%);
  height: 1px;
  background: rgba(250, 246, 239, .15);
}

/* The sitemap footer's email is left-aligned in its brand column; here
   the column is centred and so is the address. */
.hp-footer-simple .hp-footer-email {
  align-self: center;
  /* 33 characters of mono, which is a fixed width per size: at a flat
     16px it measured 290px against the 280px a 320px phone actually
     leaves between the shell padding, so it clipped. Fluid between the
     two ends instead -- 14px clears 320px with room, 16px is the size
     the rest of the footer is set against. */
  font-size: clamp(14px, 4.2vw, 16px);
}

.hp-footer-legal-row {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: var(--t-xs);
  color: var(--paper-mute);
}

.hp-footer-legal-row a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 3px 2px;
  color: inherit;
}

.hp-footer-dot {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: currentColor;
  opacity: .55;
}

.hp-footer-copy {
  margin: 0;
  font-size: var(--t-xs);
  color: var(--paper-mute);
}

/* The statutory trading disclosure. Quieter than the copyright line
   above it, because it is there to be found rather than read, but it
   still clears 4.5:1 against the footer. */
.hp-footer-reg {
  max-width: 62ch;
  margin: 8px auto 0;
  font-size: var(--t-xs);
  line-height: 1.55;
  color: rgba(250, 246, 239, .68);
}

/* Cropped into the corner rather than floated above a bottom bar there
   is no longer any of. Kept clear of the centred column so every run of
   text still sits on flat dark green, which is the whole point of the
   placement note on .hp-footer-daisy above. */
.hp-footer--simple .hp-footer-daisy {
  --d: 200px;
  right: -54px;
  bottom: -40px;
  opacity: .45;
}

/* --------------------------------------------------------- Tablet down */

@media (max-width: 1000px) {
  :root { --shell: 28px; --section-y: 46px; }

  .hp-hero { padding: 56px var(--shell) 68px; }

  .hp-hero-inner { gap: 24px; }

  .hp-hero-daisy { --d: 250px; }

  .hp-process-grid {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .hp-process-sub { max-width: none; }

  .hp-footer-grid { grid-template-columns: 1fr 1fr; }
}

/* --------------------------------------------------------- Phone */

/* The print is absolutely placed in the hero's bottom-left corner, which
   only works while the centred column is narrow enough to clear it.
   Below about 1100px it starts crossing the sub-headline, and below
   810px it covers the first letter of the primary button -- iPad
   portrait is 768px, so this was breaking the single most common
   non-phone width. It joins the flow well before that happens. */
/* Between 721 and 1100 there is no margin beside the hero to hold the
   card, so it drops into the flow under the buttons. */
@media (max-width: 1100px) {
  .hp-proof {
    display: block;
    position: static;
    width: 168px;
    margin: 34px auto 0;
    transform: rotate(-2.4deg);
  }
}

/* On a phone it goes entirely. Stacked in the flow it is a second,
   smaller picture of the same site the case study shows in full a
   screen and a half below, so it costs a scroll to say something the
   page says again properly. */
@media (max-width: 720px) {
  /* Touch targets. The FAQ questions were 30px tall and the legal
     contents links 18px, both under the 44px a thumb actually wants, and
     both are lists of similar items sitting close together where a
     mis-tap opens the wrong one. Padding rather than type size, so
     nothing about the reading changes. */
  .faq-item summary { padding: 7px 0; }

  .legal-toc ul { gap: 2px 24px; }

  .legal-toc a { display: inline-block; padding: 9px 0; }

  .hp-case-go { display: inline-block; padding: 9px 0; }

  .hp-proof { display: none; }
}

/* The burger has to arrive before the bar runs out of room, not at the
   phone breakpoint. Between 721 and 840 the wordmark was wrapping to
   two lines and "Client log in" with it, pushing the header to 122px. */
@media (max-width: 860px) {
  .hp-cards { grid-template-columns: 1fr; }

  .hp-burger { display: block; }

  .hp-nav { position: relative; }

  .hp-nav-links {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    padding: 12px var(--shell) 18px;
    background: var(--dark);
    border-top: 1px solid rgba(250, 246, 239, .15);
    font-size: var(--t-md);
    z-index: 40;
  }

  .hp-nav[data-open="true"] .hp-nav-links { display: flex; }

  .hp-nav-links a {
    justify-content: center;
    min-height: 48px;
    border-radius: 12px;
  }

  /* On the bar the login is the quietest of five things in a row and a
     missing border reads as restraint. Stacked, every other row is a
     drawn box, so the one without an edge reads as a row that failed
     rather than as a softer choice. It gets its own edge here, a step
     fainter than the pages above it, and a gap that puts it with the
     button rather than with them: three pages, then the two things you
     came to do. */
  .hp-nav-links .hp-nav-quiet { border-color: rgba(250, 246, 239, .3); }
}

.hp-brand { white-space: nowrap; }

@media (max-width: 720px) {
  /* 44 put 88px between two sections, because each carries its own
     --section-y and a boundary is the sum of both. On a 390px phone
     that is a fifth of the viewport width of nothing, and between two
     cream sections there is no colour change to justify it. 32 lands a
     boundary at 64, which still separates without stranding. */
  :root { --shell: 20px; --section-y: 32px; }

  .hp-nav { padding: 14px var(--shell); }

  .hp-hero { padding: 40px var(--shell) 32px; }

  .hp-hero-daisy { --d: 178px; }

  .hp-hero-actions { gap: 14px; }

  /* Left, not centred. Every other block on a phone starts on the same
     left edge -- the section headings, the cards, the footer -- so a
     centred hero was the one place the eye had to find a new starting
     point on every line. Centring also puts a ragged edge on both sides
     of a four line paragraph, and two ragged edges is what reads as
     untidy rather than as composed.

     The mark stays centred. Pulled left it sits against the shell
     padding with its widest petals almost off the page, and it is a
     decorative mark rather than a line of text, so being the one
     centred thing reads as deliberate. */
  .hp-hero-inner { align-items: flex-start; text-align: left; }
  .hp-hero-copy { align-items: flex-start; }
  .hp-hero-actions { align-items: flex-start; }
  .hp-hero-daisy { align-self: center; }

  /* Full-width CTAs on a phone, per the mobile mock. */
  .hp-hero-actions {
    width: 100%;
    flex-direction: column;
    gap: 16px;
  }

  .hp-hero-actions .hp-btn,
  .hp-cta .hp-btn {
    width: 100%;
  }

  /* The service cards become a list: four tilted cards at phone width
     read as a stack of skewed boxes rather than as a set. */
  .hp-cards { grid-template-columns: 1fr; }

  .hp-card,
  .hp-card:nth-child(n) { transform: none; }


  /* Stacked, the shot is no longer filling a column beside the copy, so
     there is nothing for object-fit: cover to fill -- it just crops. The
     min-height forced 220px onto an image that wants 202px at this
     width, and cover took the difference off the sides, cutting the ends
     off the nav of the very site being shown. Its own ratio instead; the
     width/height attributes still reserve the space, so nothing shifts
     while it loads. */
  .hp-case-shot {
    min-height: 0;
    height: auto;
  }

  .hp-case-body { padding: 28px 24px; }

  .hp-step {
    flex-direction: column;
    gap: 8px;
    align-items: stretch;
  }

  .hp-step-num { width: auto; }

  .hp-cta {
    grid-template-columns: 1fr;
    padding: 36px 24px;
    gap: 22px;
  }

  .hp-cta-act { align-items: stretch; }

  .hp-cta-facts { grid-template-columns: 1fr; }

  .hp-footer-grid { grid-template-columns: 1fr; gap: 28px; }

  .hp-footer-daisy { --d: 180px; right: -64px; bottom: 128px; opacity: .5; }

  /* The centred column runs the full width of a phone, so the corner
     watermark shrinks and drops further out of frame rather than
     sitting behind the copyright line. */
  .hp-footer--simple .hp-footer-daisy {
    --d: 148px;
    right: -50px;
    bottom: -34px;
    opacity: .4;
  }

  .hp-footer-bar { justify-content: flex-start; }
}

/* ============================================================ Inner pages */

/* Everything below is for the six pages that are not the homepage. They
   share the shell above and differ only in what sits between the nav and
   the footer, so the patterns here are deliberately few: a page head, a
   prose column, a numbered list of offers, and a card grid. */

/* The dot texture, the top air and the closing hairline that every page
   opens on. .hp-pagehead is one user of it; About's portrait head is the
   other, and it keeps its own type treatment rather than the head's, so
   it takes the band and nothing else. */
.hp-pagehead,
.hp-headband {
  padding: calc(var(--section-y) + 16px) var(--shell) var(--section-y);
  background-image: radial-gradient(rgba(34, 48, 31, .085) 1.4px, transparent 1.4px);
  background-size: 26px 26px;
  border-bottom: 1px solid rgba(34, 48, 31, .12);
}

.hp-pagehead-inner {
  max-width: 820px;
  margin: 0 auto;
  text-align: center;
}

.hp-pagehead h1 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-lg);
  line-height: 1.04;
  letter-spacing: -.022em;
  text-wrap: balance;
}

.hp-pagehead p {
  margin: 18px auto 0;
  max-width: 36em;
  font-size: var(--t-lg);
  line-height: 1.6;
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* Left-aligned variant. A centred head works above a centred column;
   above a two-column ruled list it leaves the eye starting in a
   different place from every row beneath it.
   This block sits after .hp-pagehead p on purpose: that rule's margin
   shorthand carries the same specificity, so declaring the variant
   earlier lost the alignment back to auto and the sub-line stayed
   centred under a left-aligned headline. */
.hp-pagehead--left { padding-bottom: calc(var(--section-y) - 12px); border-bottom: 0; }
.hp-pagehead--left .hp-pagehead-inner { max-width: var(--content); text-align: left; }
/* Was --d-xl, which is the homepage hero's size. Two of the six pages
   set their title there and the other four sat a step down at --d-lg,
   so the same element rendered at 76px on work and services and 52px
   everywhere else. --d-lg for every page title; --d-xl stays the
   homepage's alone. */
.hp-pagehead--left h1 { font-size: var(--d-lg); }
.hp-pagehead--left h1 em { font-style: normal; color: var(--leaf-deep); }
.hp-pagehead--left p { margin: 20px 0 0; max-width: 30em; }

.hp-kicker {
  display: block;
  margin-bottom: 14px;
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--leaf-ink);
}

/* A single reading column: about, terms, privacy. */
.hp-prose {
  max-width: 720px;
  margin: 0 auto;
  padding: var(--section-y) var(--shell);
}

.hp-prose h2 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-md);
  line-height: 1.12;
  letter-spacing: -.018em;
  margin: 44px 0 14px;
}

.hp-prose h2:first-child { margin-top: 0; }

.hp-prose h3 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-sm);
  letter-spacing: -.015em;
  margin: 30px 0 10px;
}

.hp-prose p,
.hp-prose li {
  font-size: var(--t-md);
  line-height: 1.7;
  color: var(--ink-soft);
}

.hp-prose p + p { margin-top: 14px; }

.hp-prose ul {
  margin: 14px 0;
  padding-left: 22px;
  list-style: disc;
}

.hp-prose li + li { margin-top: 8px; }

.hp-prose a { color: var(--leaf-ink); text-underline-offset: 3px; }
.hp-prose a:hover { color: var(--dark); }

.hp-prose strong { color: var(--ink); font-weight: 700; }

/* The numbered offer list on services. */
.hp-offers {
  max-width: 1080px;
  margin: 0 auto;
  padding: var(--section-y) var(--shell);
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.hp-offer {
  display: grid;
  grid-template-columns: 92px 1fr auto;
  gap: 28px;
  align-items: start;
  padding: 30px 32px;
  border-radius: var(--radius-card);
  background: var(--beige);
  scroll-margin-top: 24px;
}

.hp-offer:nth-child(even) { background: var(--band-alt); }

.hp-offer-num {
  font-family: var(--mono);
  font-size: var(--t-sm);
  color: var(--leaf-ink);
  padding-top: 4px;
}

.hp-offer h2 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-sm);
  letter-spacing: -.015em;
  margin-bottom: 6px;
}

.hp-offer-for {
  font-size: var(--t-sm);
  color: var(--leaf-ink);
  font-weight: 600;
  margin-bottom: 10px;
}

.hp-offer p {
  font-size: var(--t-md);
  line-height: 1.65;
  color: var(--ink-soft);
  max-width: 48ch;
}

.hp-offer .hp-link { flex: none; white-space: nowrap; }

/* Two- and three-up card grids: about, work. */
.hp-grid {
  max-width: 1080px;
  margin: 0 auto;
  padding: var(--section-y) var(--shell);
  display: grid;
  gap: 18px;
}

.hp-grid--2 { grid-template-columns: repeat(2, 1fr); }
.hp-grid--3 { grid-template-columns: repeat(3, 1fr); }

.hp-tile {
  padding: 28px 26px;
  border-radius: var(--radius-card);
  background: var(--beige);
}

.hp-tile h2,
.hp-tile h3 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-sm);
  letter-spacing: -.015em;
  margin-bottom: 8px;
}

.hp-tile p {
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--ink-soft);
}

/* The commercial boundary on the discovery tile: what a build quote
   already covers, and where a separately scoped piece of work starts.
   It is the one line on the page a client needs to have read before
   they ask for a price, so it gets a rule and full-strength ink rather
   than sitting in the soft body colour with everything else. */
.hp-tile .hp-tile-note {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid rgba(34, 48, 31, .16);
  color: var(--ink);
}

/* .hp-link is inline-flex with a 44px min-height, so it carries roughly
   12px of its own air above the text. 4px is what it needs on top of
   that, not a full gap. */
.hp-tile .hp-link { margin-top: 4px; }

/* Colour modifiers belong to the tile, not borrowed from .hp-card-*.
   Those are declared earlier in this file, so .hp-tile's own background
   won while their colour stayed -- which is how cream text ended up on
   a beige tile at 1.13:1. Each modifier now sets both halves. */
.hp-tile--pink { background: var(--pink); }

.hp-tile--gold { background: var(--gold); }

.hp-tile--leaf { background: var(--leaf-deep); color: var(--cream); }

.hp-tile--dark { background: var(--dark); color: var(--cream); }

/* A coloured tile carries its own ink, the same as a coloured card. The
   soft grey on .hp-tile p above is a cream-page colour: on the leaf tile
   it is dark text on green, which is how it read until this rule. */
.hp-tile--pink p,
.hp-tile--gold p,
.hp-tile--leaf p,
.hp-tile--dark p { color: inherit; }

/* A band that breaks up a long page. */
.hp-band {
  background: var(--dark);
  color: var(--cream);
  padding: var(--section-y) var(--shell);
}

.hp-band-inner { max-width: 820px; margin: 0 auto; text-align: center; }

.hp-band h2 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-md);
  letter-spacing: -.018em;
  line-height: 1.1;
}

.hp-band h2 em { font-style: normal; color: var(--pink); }

.hp-band p {
  margin: 16px auto 0;
  max-width: 34em;
  font-size: var(--t-md);
  line-height: 1.65;
  color: var(--paper-soft);
}

@media (max-width: 860px) {
  .hp-grid--2, .hp-grid--3 { grid-template-columns: 1fr; }

  .hp-offer {
    grid-template-columns: 1fr;
    gap: 6px;
    padding: 26px 22px;
  }

  .hp-offer-num { padding-top: 0; }
  .hp-offer p { max-width: none; }
  .hp-offer .hp-link { margin-top: 8px; }
}

/* ------------------------------------------------------------ Contact form */

/* The enquiry form's markup and its four scripts are untouched by the
   rebrand -- it is the one thing on the public site that can lose a
   lead, and re-marking a working form to change its colours is a bad
   trade. These rules restyle the classes it already uses. */

/* Contact is the one page with a job rather than a subject, so it drops
   the centred .hp-pagehead the content pages use and puts the heading in
   the left column instead, beside the form rather than above it. That
   also settles a duplication: the page carried the page head AND a
   second <h1> of the same words inside the form column, so a visitor
   read "Tell me about your project." twice, under two intros saying the
   same thing, before reaching a single field.

   Everything used to sit in one 720px column on a 1440px screen -- the
   form, the direct details and the questions all in the middle third,
   with the rest of the page empty either side. */
.contact-split {
  /* min() with the shell rather than padding inside the column: the
     other containers put the gutter outside the max-width, so a column
     that padded inside it started its content 44px further in and the
     heading did not line up with any other page's. */
  max-width: min(var(--content), calc(100% - var(--shell) * 2));
  margin: 0 auto;
  padding: calc(var(--section-y) + 16px) 0 var(--section-y);
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: 64px;
  align-items: start;
}

.contact-intro { position: sticky; top: 96px; }

.contact-intro h1 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-lg);
  line-height: 1.08;
  letter-spacing: -.02em;
  margin: 10px 0 0;
}

/* The form is the page's actual work, so it gets the card and the
   contrast; the column beside it stays on the page background. */
.contact-card {
  background: var(--beige);
  border: 1px solid rgba(34, 48, 31, .10);
  border-radius: var(--radius-card);
  padding: 40px;
}

@media (max-width: 1000px) {
  .contact-split {
    grid-template-columns: 1fr;
    gap: 40px;
    /* The gutter has to be kept in the override. The base rule reads
       min(--content, 100% - shell*2), and setting a bare 780px here
       threw the second half away: under 780px the column simply became
       the full width of the screen, so on a phone the kicker, the title
       and the whole intro started hard against the left edge while
       every other page started 20px in. */
    max-width: min(780px, calc(100% - var(--shell) * 2));
  }

  /* Nothing to stick to once the two columns become one. */
  .contact-intro { position: static; }
}

@media (max-width: 720px) {
  .contact-card { padding: 28px 22px; }
}

.contact-split .lede {
  font-size: var(--t-lg);
  line-height: 1.6;
  color: var(--ink-soft);
  /* 20 above, the same as the sub-line on Work and Services. It had
     none, so the sub-line sat straight on the descenders of the title
     while every other page gave it a breath. */
  margin-top: 20px;
  margin-bottom: 28px;
}

.contact-form { display: flex; flex-direction: column; gap: 20px; }

.field { display: flex; flex-direction: column; gap: 7px; }

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }

.field label,
.checkbox-field-legend {
  font-size: var(--t-sm);
  font-weight: 700;
  color: var(--ink);
}

.field-hint,
.field-note,
.form-note,
.contact-direct-note {
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--ink-mute);
}

.contact-form input[type="text"],
.contact-form input[type="email"],
.contact-form select,
.contact-form textarea,
.auth-form input[type="text"],
.auth-form input[type="email"],
.auth-form input[type="password"] {
  width: 100%;
  padding: 13px 15px;
  border: 1.5px solid rgba(34, 48, 31, .22);
  border-radius: 12px;
  background: var(--panel-cream);
  color: var(--ink);
  font: inherit;
  font-size: var(--t-md);
  transition: border-color .16s ease, box-shadow .16s ease;
}

.contact-form textarea { min-height: 150px; resize: vertical; }

.contact-form input:focus,
.contact-form select:focus,
.contact-form textarea:focus,
.auth-form input:focus {
  outline: none;
  border-color: var(--leaf-deep);
  box-shadow: 0 0 0 3px rgba(87, 117, 73, .22);
}

.contact-form input:focus-visible,
.contact-form select:focus-visible,
.contact-form textarea:focus-visible,
.auth-form input:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
}

.checkbox-field { display: flex; flex-direction: column; gap: 10px; border: 0; padding: 0; margin: 0; }

.checkbox-group { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }

.checkbox-option {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 46px;
  padding: 10px 14px;
  border: 1.5px solid rgba(34, 48, 31, .18);
  border-radius: 12px;
  background: var(--panel-cream);
  font-size: var(--t-sm);
  cursor: pointer;
  transition: border-color .16s ease, background-color .16s ease;
}

@media (hover: hover) {
  .checkbox-option:hover { border-color: var(--leaf-deep); }
}

.checkbox-option input { accent-color: var(--leaf-deep); width: 18px; height: 18px; flex: none; }

.checkbox-option:has(input:checked) { border-color: var(--leaf-deep); background: var(--leaf-tint); }

/* Errors carry a word as well as the colour: colour alone fails 1.4.1. */
.field-error {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--error);
}

.contact-form [aria-invalid="true"],
.auth-form [aria-invalid="true"] { border-color: var(--error); }

.form-status[role="status"] { font-size: var(--t-sm); color: var(--ink-soft); }

.form-sent {
  padding: 26px 28px;
  border-radius: var(--radius-card);
  background: var(--leaf-deep);
  color: var(--cream);
}

.form-sent p { color: var(--paper-on-leaf); }

.btn-spinner { display: none; }
.btn.is-busy .btn-spinner { display: inline-block; }

/* The old shell's button classes, mapped onto the new one so the
   submit button needs no markup change. */
.contact-form .btn,
.contact-direct .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45em;
  align-self: flex-start;
  min-height: 48px;
  padding: 13px 28px;
  border: 1.5px solid var(--btn-primary-edge);
  border-radius: var(--radius-btn);
  background: var(--btn-primary);
  color: var(--btn-primary-ink);
  font: inherit;
  font-weight: 800;
  font-size: var(--t-sm);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .18s ease;
}

@media (hover: hover) {
  .contact-form .btn:hover,
  .contact-direct .btn:hover { background: var(--btn-primary-hover); }
}
.contact-form .btn[disabled] { opacity: .6; cursor: default; }

.contact-direct {
  margin-top: 32px;
  padding-top: 28px;
  border-top: 1px solid rgba(34, 48, 31, .14);
}

.contact-direct h2 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-sm);
  margin-bottom: 6px;
}

.contact-direct .row { display: flex; gap: 10px; flex-wrap: wrap; font-size: var(--t-md); }
.row-label {
  color: var(--ink-mute);
  /* Was EMAIL and BASED IN typed in capitals at body size, which is
     shouting rather than labelling. Sentence case in the markup now,
     set smaller and tracked so it reads as a label without raising its
     voice. */
  font-size: var(--t-sm);
  letter-spacing: .04em;
  align-self: baseline;
}
.row-value-link { color: var(--leaf-ink); }

/* The rail's reassurances: the same facts every closing card carries,
   here so the sticky column isn't dead air beside a tall form. */
.contact-facts {
  list-style: none;
  margin: 22px 0 0;
  padding: 18px 0 0;
  border-top: 1px solid rgba(34, 48, 31, .12);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.contact-facts li {
  position: relative;
  padding-left: 22px;
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--ink-soft);
}

.legal-toc {
  margin: 0 0 34px;
  padding: 18px 22px;
  background: var(--beige);
  border-radius: 14px;
}

.legal-toc ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 6px 24px;
}

.legal-toc a {
  font-size: var(--t-sm);
  color: var(--leaf-ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.contact-facts li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .42em;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--leaf-deep);
}

/* FAQ */
.faq-section { background: var(--beige); padding: var(--section-y) var(--shell); }

.faq-section h2 {
  max-width: 820px;
  margin: 0 auto 28px;
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-md);
  letter-spacing: -.02em;
}
.faq-list { max-width: 820px; margin: 0 auto; }

.faq-item { padding: 22px 0; border-bottom: 1px solid rgba(34, 48, 31, .14); }
.faq-item:last-child { border-bottom: 0; }

/* These rules used to be written against .faq-item h3. The markup is
   <details><summary>, and always was, so not one of them applied: the
   questions rendered at body size in the sans face behind the browser's
   default black triangle, on a page where every other heading is
   Fraunces. */
.faq-item summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  cursor: pointer;
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-sm);
  letter-spacing: -.015em;
  /* Both are needed: the pseudo-element covers WebKit, list-style covers
     Firefox, and neither one alone removes the marker everywhere. */
  list-style: none;
}

.faq-item summary::-webkit-details-marker { display: none; }

@media (hover: hover) {
  .faq-item summary:hover { color: var(--leaf-ink); }
}

/* A chevron built from two borders rather than a glyph, so it turns
   with the panel instead of swapping character. */
.faq-item summary::after {
  content: "";
  flex: none;
  align-self: center;
  width: 9px;
  height: 9px;
  margin-right: 4px;
  border-right: 2px solid var(--leaf-ink);
  border-bottom: 2px solid var(--leaf-ink);
  transform: rotate(45deg);
  transition: transform .18s ease;
}

.faq-item[open] summary::after { transform: rotate(-135deg); }

.faq-item p {
  margin-top: 12px;
  padding-right: 40px;
  font-size: var(--t-md);
  line-height: 1.65;
  color: var(--ink-soft);
}

/* The honeypot must stay reachable to a bot and invisible to a person --
   display:none would let a bot skip it. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.wrap { max-width: var(--content); margin: 0 auto; }

@media (max-width: 720px) {
  .field-row, .checkbox-group { grid-template-columns: 1fr; }
  .contact-form .btn { align-self: stretch; width: 100%; }
}

/* --------------------------------------------------------- Service list */

/* Replaces the beige offer cards. A card per service made four heavy
   boxes competing for the same attention; a ruled list puts the name in
   one column and what you get in the other, so the page is scanned
   rather than read. The chips are the deliverables -- the nearest this
   page gets to answering "what do I actually receive", which is the
   question the cards left open. */
.svc-list {
  max-width: var(--content);
  margin: 0 auto;
  padding: 0 var(--shell) var(--section-y);
}

.svc {
  display: grid;
  grid-template-columns: minmax(0, 34%) minmax(0, 1fr);
  gap: 28px 56px;
  align-items: start;
  padding: 44px 0;
  border-top: 1px solid rgba(34, 48, 31, .16);
  scroll-margin-top: 24px;
}

.svc h2 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-md);
  line-height: 1.05;
  letter-spacing: -.022em;
}

.svc-body p {
  font-size: var(--t-md);
  line-height: 1.65;
  color: var(--ink-soft);
  max-width: 46ch;
}

.svc-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 18px;
}

.svc-tags li {
  padding: 7px 14px;
  border-radius: var(--radius-pill);
  font-size: var(--t-sm);
  font-weight: 600;
  line-height: 1.3;
}

/* Each service gets one colour so the eye can tell the blocks apart
   without a border round each. All four measured on their own chip. */
.svc--pink  .svc-tags li { background: var(--pink); color: var(--dark); }
.svc--gold  .svc-tags li { background: var(--gold); color: var(--dark); }
.svc--leaf  .svc-tags li { background: var(--leaf-deep); color: var(--cream); }
.svc--dark  .svc-tags li { background: var(--dark); color: var(--cream); }

.svc-go { margin-top: 20px; }

/* The list had a rule above every row and nothing under the last one, so
   the block never closed. That mattered because each row's left column
   is blank below its heading by design -- fine while another rule
   follows, but under the last row it ran straight into the section gap
   and the two read as one large void rather than as air. A closing rule
   gives the list an edge, so the space below it belongs to the next
   block instead of trailing off the end of this one. */
.svc-list { padding-bottom: 0; }
.svc:last-child { border-bottom: 1px solid rgba(34, 48, 31, .16); }

/* Website review and ongoing support are the tail of the same answer the
   capabilities and the combined route give, not a new subject, and a
   full section break between them and the tile above made three
   related blocks read as three separate sections. Half a break still
   separates them while keeping the group together; the full break is
   saved for the process and the CTA, which genuinely are new subjects. */
main > .svc-list + .hp-grid ~ .hp-grid { padding-top: calc(var(--section-y) / 2); }

/* The secondary services used to be three separate grid rows -- one full
   width, then a pair, then another full width -- with nothing saying what
   the group was. Read top to bottom it was just blocks of different
   widths appearing after the numbered services. They are now one grid
   with one heading, and the two that need the width take it by spanning
   the tracks rather than by being their own row. */
.hp-span { grid-column: 1 / -1; }

/* The head brings its own bottom margin for the flex layouts it was
   built for. Inside a grid that margin lands on top of the 18px gap and
   the heading floats away from the first tile. */
.hp-grid > .hp-section-head { margin-bottom: 0; }

/* The group heading sits a step below the numbered services rather than
   matching them: those are the offer, this is what else is available. */
.hp-grid > .hp-section-head h2 {
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-md);
  letter-spacing: -.022em;
  line-height: 1.05;
}

.hp-grid > .hp-section-head .hp-section-note { font-size: var(--t-sm); }


@media (max-width: 860px) {
  .svc {
    grid-template-columns: 1fr;
    gap: 14px;
    padding: 34px 0;
  }

  .svc-body p { max-width: none; }
}

/* "Scoped around you." needs 311px on one line and had 300, so it wrapped
   -- and balance, doing exactly what it is for, split the two lines as
   evenly as it could: "Scoped" over "around you.". One short word alone
   under a 33px serif reads as a mistake whichever way it breaks, so the
   fix is to give the line the room rather than to change how it breaks.
   Less card padding, and a size that tracks the viewport instead of
   sitting at a flat 33px, so the line keeps fitting all the way down to
   a 360px phone rather than only at 390.

   Last in the file on purpose: .hp-cta's padding and .hp-cta h2's size
   are both set again inside the 720px block at the same specificity, so
   an override written beside the rule it fights would lose on source
   order. */
@media (max-width: 480px) {
  .hp-cta { padding: 32px 20px; }
  .hp-cta h2 { font-size: clamp(28px, 8vw, 33px); }
}

/* ------------------------------------------------------------ Auth pages

   login, forgot-password and update-password used to run on
   base.css + marketing.css: the same colours and type as here after the
   repaint, but the old light nav bar and a different footer, so the one
   place a client crosses from the public site into the portal was also
   the one place the chrome changed. They are Greenhouse pages now and
   carry the same nav and footer as every other public page. */

.auth-section {
  display: flex;
  justify-content: center;
  padding: var(--section-y) var(--shell) calc(var(--section-y) + 20px);
}

.auth-wrap { width: 100%; max-width: 460px; }

.auth-back {
  display: inline-flex;
  align-items: center;
  gap: .4em;
  min-height: 44px;
  margin-bottom: 12px;
  font-size: var(--t-sm);
  font-weight: 700;
  color: var(--ink-soft);
  text-decoration: none;
}

@media (hover: hover) {
  .auth-back:hover { color: var(--ink); }
}

.auth-card {
  /* forgot-password and update-password have no .auth-wrap around the
     card, so inside a centring flex parent it shrank to its content and
     came out 80px narrower than login's. The card carries its own
     measure instead of inheriting one. */
  width: 100%;
  max-width: 460px;
  padding: 40px 34px 34px;
  border: 1px solid rgba(34, 48, 31, .10);
  border-radius: var(--radius-card);
  background: var(--panel-cream);
  box-shadow: 0 14px 34px -20px rgba(34, 48, 31, .30);
}

.auth-card h1 {
  margin: 0 0 8px;
  font-family: var(--display);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 800;
  font-size: var(--d-md);
  letter-spacing: -.02em;
  text-align: center;
}

.auth-card .auth-sub {
  margin: 0 0 26px;
  font-size: var(--t-md);
  line-height: 1.6;
  color: var(--ink-soft);
  text-align: center;
  text-wrap: pretty;
}

.auth-form { display: flex; flex-direction: column; gap: 20px; }

.auth-form .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45em;
  width: 100%;
  min-height: 48px;
  padding: 13px 28px;
  border: 0;
  border-radius: var(--radius-btn);
  /* Light card, dark button -- the same rule as the public pages. */
  background: var(--btn-primary);
  color: var(--btn-primary-ink);
  border: 1.5px solid var(--btn-primary-edge);
  font-weight: 800;
  font-size: var(--t-sm);
  cursor: pointer;
  transition: background-color .18s ease, transform .18s ease;
}

@media (hover: hover) {
  .auth-form .btn:hover { background: var(--btn-primary-hover); }
}
.auth-form .btn:active { transform: translateY(1px); }
.auth-form .btn[disabled] { opacity: .6; cursor: default; }

/* The eye button sits over the right-hand end of the password field, so
   the input needs room for it and the button must not stretch. */
.field-password-wrap { position: relative; display: block; }
.field-password-wrap input { width: 100%; padding-right: 46px; }

.auth-form .field-password-toggle {
  position: absolute;
  top: 50%;
  right: 6px;
  width: 38px;
  height: 38px;
  min-height: 0;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--ink-mute);
  cursor: pointer;
}

@media (hover: hover) {
  .auth-form .field-password-toggle:hover { color: var(--ink); }
}

/* The toggle holds both icons and swaps them with the hidden attribute.
   greenhouse.css has no blanket [hidden] rule -- it cannot have one,
   because the burger is markup-hidden and shown again by a media query
   -- so the icons say so themselves. */
.field-password-toggle svg[hidden] { display: none; }

.auth-error {
  margin: 0;
  padding: 12px 14px;
  border-radius: 10px;
  background: rgba(140, 47, 34, .10);
  color: var(--error);
  font-size: var(--t-sm);
  line-height: 1.5;
}

.auth-switch,
.auth-note {
  margin: 18px 0 0;
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--ink-soft);
  text-align: center;
}

.auth-note {
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid rgba(34, 48, 31, .12);
  font-size: var(--t-xs);
}

.auth-switch a,
.auth-note a {
  color: inherit;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 4px;
}

@media (max-width: 480px) {
  .auth-card { padding: 32px 22px 26px; }
}
