/* ==========================================================================
   CAI demo site renderer
   --------------------------------------------------------------------------
   One stylesheet serves every client site. Anything that varies per site is a
   custom property set inline in the <head> from the theme block of the content
   document, so this file stays static, cacheable, and identical across all of
   them. Nothing in here may reference a specific business or niche.

   LAYOUTS. The renderer puts data-layout on <body>, one of classic, editorial,
   bold, minimal, split or dark. The base rules below describe "classic", and
   the block near the end of the file restates only what each other layout
   does differently: where the hero photo sits, whether the page is light or
   dark, how cards and lists are drawn. Same document, different skeleton.

   TOKENS. The theme decides the colours, and it flips the whole ink scale for
   the dark layout, so every rule here reads --ink, --line, --surface, --card
   and never a literal white or black. A literal colour is a bug: it is the
   thing that turns into white-on-white the day somebody picks the dark layout.
   ========================================================================== */

/* --------------------------------------------------------------- resets --- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 88px;
  /* No client site may ever scroll sideways on a phone, whatever ends up in the
     content document. Belt and braces with the rule on body. */
  overflow-x: hidden;
}

body {
  margin: 0;
  font-family: var(--font);
  color: var(--ink);
  background: var(--page);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }
h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-heading);
  /* From the pairing. A display serif at 700 is a different typeface
     from the same serif at 400, and only one of them is the reason
     it was chosen. Falls back to 700 for any theme predating this. */
  font-weight: var(--heading-weight, 700);
  line-height: 1.1;
  letter-spacing: var(--heading-track);
  text-transform: var(--heading-case);
  text-wrap: balance;
}
p { margin: 0; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; list-style: none; }
dl, dd { margin: 0; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
svg { display: block; }
iframe { border: 0; display: block; }

::selection { background: var(--accent); color: var(--accent-ink); }

/*
 * The focus ring, which has to be visible on every ground on every site.
 *
 * It used to be drawn in --accent, and an accent is chosen to look right, not
 * to contrast: measured across the forty-four palettes it fell to 1.52:1 on
 * lumo-el and 1.79:1 on kraftverket, against the 3:1 WCAG 2.4.11 asks for. A
 * focus ring nobody can see is the same as no focus ring, and it was the one
 * on every control on every page.
 *
 * --ink is the page's own text colour, so it is high contrast against --page,
 * --card and --surface by construction, whichever way round the theme is.
 * The dark bands are the exception and take the ink that belongs to them.
 */
:focus-visible {
  outline: 2px solid var(--focus, var(--ink));
  outline-offset: 3px;
  border-radius: 2px;
}

/*
 * The dark grounds declare their own focus colour rather than having it
 * guessed at from outside.
 *
 * A custom property inherits, so setting it on the band covers every control
 * inside it however deeply nested. The first version of this listed focused
 * descendants instead, and missed .site-footer and .cta-band because it
 * guessed at their names: the ring came out near black on a near black ground,
 * 1.01:1.
 */
.section--dark,
.site-footer,
.mobile-nav,
.cta-band--photo,
.about-overlay,
.callbar,
.example-bar,
.hero:not(.hero--light),
[data-layout="dark"] { --focus: #fff; }

/* Back to ink wherever a light panel sits inside one of those. */
.section--dark .panel--light,
[data-layout="dark"] .hero--light { --focus: var(--ink); }

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

.skip-link {
  position: absolute;
  top: 8px; left: 8px;
  z-index: 200;
  padding: 10px 16px;
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: var(--radius);
  font-weight: 600;
  transform: translateY(-160%);
  transition: transform .18s ease;
}
.skip-link:focus { transform: none; }

/* ------------------------------------------------------------- primitives --- */

/* Open and closed. The only two colours on a client site that do not come
   from the client's palette, because a business whose brand colour is red
   must not have "open now" drawn in it. Defined here rather than in
   Theme.php for exactly that reason: they are the same on every site.

   Measured on white and on --deep, the two grounds they are drawn on:
     --ok      #2f9d57 on #ffffff  4.51:1
     --bad     #c2453a on #ffffff  4.54:1
     --ok-up   #74e39b on #1c1a17  9.90:1
     --bad-up  #f09287 on #1c1a17  8.16:1
   The dot cuts are not text and answer to the 3:1 control edge instead. */
:root {
  --ok: #2f9d57;
  --ok-up: #74e39b;
  --ok-dot: #37c46a;
  --ok-wash: rgb(55 196 106 / .14);
  --ok-ring: rgb(55 196 106 / .22);
  --bad: #c2453a;
  --bad-up: #f09287;
  --bad-dot: #d4483b;
  --bad-wash: rgb(212 72 59 / .14);
  --bad-ring: rgb(212 72 59 / .2);
  --bad-ink: #a3231e;
}


.wrap {
  width: 100%;
  max-width: 1180px;
  margin-inline: auto;
  padding-inline: 20px;
}

.eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent-strong);
  margin: 0 0 18px;
}
.eyebrow::before {
  content: '';
  width: 26px;
  height: 2px;
  background: var(--accent);
  flex: none;
}
.eyebrow.is-centred { justify-content: center; }

.btn {
  --btn-bg: var(--accent);
  --btn-ink: var(--accent-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 24px;
  min-height: 52px;
  background: var(--btn-bg);
  color: var(--btn-ink);
  border-radius: var(--radius);
  font-family: var(--font);
  font-weight: 650;
  font-size: 15.5px;
  letter-spacing: -0.005em;
  white-space: nowrap;
  transition: transform .16s ease, background-color .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn svg { width: 18px; height: 18px; flex: none; }

.btn--accent { box-shadow: 0 8px 22px -12px rgb(var(--accent-rgb) / .9); }
.btn--accent:hover { background: var(--accent-deep); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-ink: #fff;
  /* The edge is the whole control: there is no fill behind it, so if the edge
     is not visible the button is not visible. At .3 it measured 2.7:1 against
     the darkest ground it is used on, under the 3:1 a control boundary has to
     hold. .42 measures 4.0 there and 3.2 over the palest photograph. */
  border: 1px solid rgb(255 255 255 / .42);
  backdrop-filter: blur(6px);
}
.btn--ghost:hover { background: rgb(255 255 255 / .12); border-color: rgb(255 255 255 / .55); }

.btn--outline {
  --btn-bg: transparent;
  --btn-ink: var(--ink);
  border: 1px solid var(--line);
}
.btn--outline:hover { border-color: var(--ink); background: var(--surface); }

.btn--sm { min-height: 44px; padding: 10px 18px; font-size: 14.5px; }
.btn--lg { min-height: 58px; padding: 16px 30px; font-size: 16.5px; }
.btn--block { width: 100%; }

/* Star ratings: one grey row, one gold row clipped to the exact percentage. */
.stars { position: relative; display: inline-block; line-height: 0; flex: none; }
.stars__row { display: flex; gap: 2px; }
.stars__row svg { width: var(--star, 16px); height: var(--star, 16px); flex: none; }
.stars__base { color: rgb(var(--primary-rgb) / .18); }
.stars__fill {
  position: absolute;
  inset: 0;
  width: var(--pct, 100%);
  overflow: hidden;
  color: var(--accent);
}
.stars__fill .stars__row { width: max-content; }
.hero .stars__base,
.section--dark .stars__base { color: rgb(255 255 255 / .22); }
.hero--light .stars__base { color: rgb(var(--primary-rgb) / .18); }

/* Form notices, shared by the booking form. */
.notice { border-radius: var(--radius); padding: 18px 20px; }
.notice h3 { font-size: 1.05rem; margin-bottom: 4px; }
.notice p, .notice li { font-size: 15px; color: var(--ink-2); }
.notice ul { margin-top: 6px; padding-left: 1.1rem; list-style: disc; }
.notice--ok { background: rgb(55 196 106 / .12); border: 1px solid rgb(55 196 106 / .35); }
.notice--bad { background: rgb(212 72 59 / .1); border: 1px solid rgb(212 72 59 / .35); margin-bottom: 16px; }

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

.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  transition: background-color .3s ease, box-shadow .3s ease, border-color .3s ease;
  border-bottom: 1px solid transparent;
}
.site-header::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgb(0 0 0 / .55), rgb(0 0 0 / 0));
  opacity: 1;
  transition: opacity .3s ease;
  pointer-events: none;
}
.site-header.is-stuck {
  background: rgb(255 255 255 / .92);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom-color: var(--line);
  box-shadow: 0 10px 30px -24px rgb(var(--primary-rgb) / .5);
}
.site-header.is-stuck::before { opacity: 0; }

.header-inner {
  display: flex;
  align-items: center;
  gap: 18px;
  min-height: 74px;
  position: relative;
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-right: auto;
  min-width: 0;
  flex: 0 1 auto;
}
.brand > span { min-width: 0; display: grid; }
.brand__mark {
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  flex: none;
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: var(--radius);
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: var(--heading-weight-strong);
  letter-spacing: 0;
}
.brand__name {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.02em;
  text-transform: var(--heading-case);
  color: #fff;
  transition: color .3s ease;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.brand__meta {
  display: none;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  color: rgb(255 255 255 / .66);
  transition: color .3s ease;
}
.is-stuck .brand__name { color: var(--ink); }
.is-stuck .brand__meta { color: var(--ink-3); }

.nav { display: none; gap: 4px; min-width: 0; flex: 0 1 auto; overflow: hidden; }
.nav a {
  white-space: nowrap;
  padding: 9px 14px;
  border-radius: var(--radius);
  font-size: 14.5px;
  font-weight: 550;
  color: rgb(255 255 255 / .82);
  transition: color .2s ease, background-color .2s ease;
}
.nav a:hover { color: #fff; background: rgb(255 255 255 / .12); }
.is-stuck .nav a { color: var(--ink-2); }
.is-stuck .nav a:hover { color: var(--ink); background: var(--surface); }

.header-actions { display: flex; align-items: center; gap: 12px; }
.header-actions .btn { display: none; }

.status-pill {
  display: none;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 600;
  color: rgb(255 255 255 / .82);
  transition: color .3s ease;
}
.is-stuck .status-pill { color: var(--ink-2); }
.status-pill__dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--ok-dot);
  box-shadow: 0 0 0 3px var(--ok-ring);
  flex: none;
}
/* The contact panel prints the same dot inside .contact-status rather than
   inside .status-pill, so the closed state was only reaching the words: every
   layout drew a green dot in front of red text saying the place was shut. */
.status-pill--closed .status-pill__dot,
.contact-status--closed .status-pill__dot { background: var(--bad-dot); box-shadow: 0 0 0 3px var(--bad-ring); }

.nav-toggle {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  flex: none;
  border-radius: var(--radius);
  color: #fff;
  transition: color .3s ease, background-color .2s ease;
}
.nav-toggle:hover { background: rgb(255 255 255 / .12); }
.is-stuck .nav-toggle { color: var(--ink); }
.is-stuck .nav-toggle:hover { background: var(--surface); }
.nav-toggle svg { width: 22px; height: 22px; }
.nav-toggle__close { display: none; }
.nav-open .nav-toggle__open { display: none; }
.nav-open .nav-toggle__close { display: block; }

/* Light heroes: the bar starts in ink and stays there, and it always has a
   ground, because on the split layout it sits over the photograph from the
   first pixel. */
.hero-light .site-header::before { display: none; }
.hero-light .site-header {
  background: rgb(255 255 255 / .9);
  backdrop-filter: saturate(180%) blur(14px);
}
.hero-light .site-header.is-stuck { background: rgb(255 255 255 / .94); }
.hero-light .brand__name { color: var(--ink); }
.hero-light .brand__meta { color: var(--ink-3); }
.hero-light .nav a { color: var(--ink-2); }
.hero-light .nav a:hover { color: var(--ink); background: var(--surface); }
.hero-light .status-pill { color: var(--ink-2); }
.hero-light .nav-toggle { color: var(--ink); }
.hero-light .nav-toggle:hover { background: var(--surface); }

/* The number set as a line of type rather than as a filled pill, which is what
   the header draws for every trade whose phone pill is off. It had no rule of
   its own anywhere in the file: it inherited the header's body size and, worse,
   was allowed to wrap, so at 375px a Swedish number broke across two lines and
   squeezed the business name beside it down to an ellipsis. It is one short
   string and it never wraps. */
.header-tel {
  white-space: nowrap;
  font-size: 14.5px;
  font-weight: 600;
  color: #fff;
  transition: color .3s ease;
}
.is-stuck .header-tel,
.hero-light .header-tel { color: var(--ink); }

/* Below the fold of the smallest phone the fixed call bar is already carrying
   the number across the whole width of the screen, and the bar has room for a
   wordmark or a number but not for both. */
@media (max-width: 480px) {
  body.has-callbar .header-tel { display: none; }
}

/* Mobile drawer */
.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: 99;
  display: grid;
  align-content: center;
  gap: 4px;
  padding: 90px 28px 40px;
  background: var(--deep);
  color: #fff;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity .26s ease, transform .26s ease, visibility .26s;
  overflow-y: auto;
}
.nav-open .mobile-nav { opacity: 1; visibility: visible; transform: none; }
.mobile-nav a {
  padding: 14px 4px;
  border-bottom: 1px solid rgb(255 255 255 / .1);
  font-family: var(--font-heading);
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-transform: var(--heading-case);
}
.mobile-nav__foot { margin-top: 28px; display: grid; gap: 10px; }
.mobile-nav__meta { font-size: 14px; color: rgb(255 255 255 / .6); }
.mobile-nav__social { display: flex; gap: 8px; }
.mobile-nav__social a { border: 0; padding: 10px; }
.mobile-nav__social svg { width: 22px; height: 22px; }

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

.hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: 640px;
  min-height: 92svh;
  max-height: 900px;
  padding: 108px 0 clamp(36px, 7vw, 88px);
  color: #fff;
  background: var(--deep);
  overflow: hidden;
  isolation: isolate;
}
/*
   A hero with no photograph.

   It used to read as a hero that had lost its picture: the same layout at the
   same sizes with a flat band of colour where the image should have been. A
   photo-less opening is a legitimate thing, and several of the best barbershop
   and clinic sites do exactly it, but only when the type takes over the job the
   photograph was doing. So the headline goes up a step and comes in to a narrow
   measure, which turns it from a paragraph into a shape, and the block keeps
   enough height to still be a first screen.

   Written as .hero.hero--noimage because the layout blocks further down the
   file reset min-height and would otherwise win on source order.
*/
.hero.hero--noimage {
  align-items: center;
  min-height: 68svh;
  max-height: none;
  padding-top: 150px;
  padding-bottom: clamp(56px, 8vw, 104px);
}
.hero.hero--noimage h1 {
  max-width: 14ch;
  font-size: clamp(2.6rem, 8vw, 5.6rem);
  line-height: .98;
}
.hero.hero--noimage .hero__sub { font-size: clamp(1.06rem, 2.6vw, 1.3rem); }
/* The split hero drops its own padding because the picture runs to the edge.
   With no picture there is nothing to run to the edge, so it takes the wrap
   back and behaves like the others. */
.hero.hero--noimage > .wrap { max-width: 1180px; padding-inline: 20px; }
/* Both selectors, because the split hero's own top padding is written twice,
   once plain and once for the showcased sites, and the second carries an
   element on the end of it. Without the pair a photo-less split hero opened on
   164px of empty ground and ran to 142% of a laptop screen. */
.hero.hero--noimage .hero__inner,
body.has-example-bar .hero.hero--noimage .hero__inner { padding: 0; }
/* No picture means no edge of its own, so the section borrows a hairline. The
   bold hero is a block of solid colour and the edge is where the colour stops,
   so a hairline drawn on top of it would be a line inside a poster. */
.hero.hero--noimage:not(.hero--bold)::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 1px;
  background: currentColor;
  opacity: .18;
}
.hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
}
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 42%;
}
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  /*
     The headline has to stay readable over a photograph nobody vetted.

     These pages are generated from whatever pictures a business happens to
     have, and a bright one washed white text out completely. The band between
     roughly 30% and 70% is where the headline sits, so that is where the scrim
     is strongest now. Dark photographs still read as photographs; light ones no
     longer swallow the text.
  */
  background:
    linear-gradient(to top, rgb(var(--primary-rgb) / .96) 0%, rgb(var(--primary-rgb) / .86) 30%, rgb(var(--primary-rgb) / .6) 62%, rgb(var(--primary-rgb) / .66) 100%),
    linear-gradient(to right, rgb(var(--primary-rgb) / .75) 0%, rgb(var(--primary-rgb) / .25) 70%, rgb(var(--primary-rgb) / .15) 100%);
}
/* Wide enough that a 75px headline still lands on two lines. At 720px the
   headline hit its ceiling and then sat in a column barely half the width of
   the photograph behind it, which is what made a full-bleed hero read as a
   banner with a caption. */
.hero__inner { max-width: 840px; }
.hero h1 {
  /*
     The photo heroes had the smallest headline of the six variants and the
     most room for it. The old ceiling of 3.85rem was reached at a 963px
     viewport, so from a laptop upwards the screen kept growing and the
     headline did not. Independent barbershops and restaurants that open on a
     photograph run 75 to 85px here; this reaches 75px at 1233px and above.
  */
  font-size: clamp(2.3rem, 6.1vw, 4.7rem);
  line-height: 1.02;
  letter-spacing: var(--heading-track);
}
.hero__sub {
  margin-top: 20px;
  max-width: 54ch;
  font-size: clamp(1.02rem, 2.5vw, 1.19rem);
  line-height: 1.6;
  color: rgb(255 255 255 / .82);
}
.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 32px;
}
.hero__actions .btn { flex: 1 1 auto; min-width: 0; }

/*
   The rating, the opening state and the address.

   This row is the reason a first screen answers "where is it and are they
   open" without a scroll, so it stays. What it was not doing was reading as
   something anybody designed: three phrases and three accent icons in one run
   of small grey text, separated by nothing but a gap.

   Three changes. A hairline between items, so the eye gets a rhythm instead of
   a sentence. One accent element rather than three, which makes the stars the
   anchor and lets the clock and the pin recede to the row's own colour. And a
   weight step, so the score and the opening state carry and the address, which
   is the longest and least urgent of the three, sits behind them.
*/
.trust {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 20px;
  margin-top: clamp(26px, 4vw, 38px);
  padding-top: clamp(20px, 3vw, 26px);
  border-top: 1px solid rgb(255 255 255 / .18);
  font-size: 14.5px;
  color: rgb(255 255 255 / .84);
}
.trust__item { display: flex; align-items: center; gap: 9px; }
/* One accent element in the row, not three. The stars keep the accent and
   become the anchor; the clock and the pin recede to the row's own ink so they
   read as marks against a label rather than as three competing signals. */
.trust__item > svg { width: 16px; height: 16px; color: inherit; opacity: .68; flex: none; }
.trust__score { font-weight: 700; color: #fff; letter-spacing: .01em; }

/*
   The rules answer to the width of the column the row is in, not to the width
   of the window, which is why this is a container query and not a media query.

   A viewport breakpoint got it wrong on half the layouts: the editorial and
   split heroes hold their text in a column of around 500px however wide the
   screen is, the row wraps there, and a rule drawn on the left of an item that
   has just started a new line hangs in the middle of nothing with a 20px
   indent behind it. Asking the column instead means the wide single column
   heroes get the meta bar and the narrow ones keep their gaps, at every
   viewport, with no list of exceptions to maintain.
*/
.hero__inner { container-type: inline-size; container-name: heroinner; }

@container heroinner (min-width: 620px) {
  .trust { flex-wrap: nowrap; gap: 0; align-items: stretch; }
  .trust__item {
    align-items: center;
    padding-inline: 20px;
    border-left: 1px solid rgb(255 255 255 / .2);
  }
  .trust__item:first-child { padding-left: 0; border-left: 0; }
}

/*
   The keyboard ring has to answer to the ground it is drawn on.

   The shipped ring is the raw accent, which is right on a card and wrong here,
   because the hero is the one place the ground is neither the page nor a
   surface. Measured across all forty four: a dark accent on a dark hero
   (#8a3324 on #1a1815) gives 1.95:1 and a pale accent on a white one (#f5c518
   on #ffffff) gives 1.63:1, both under the 3:1 an indicator has to hold.

   Each tint below is already mixed for its ground, so no new colour is
   invented: --accent-on-dark is the accent lifted toward white and measures no
   worse than 4.4:1 over the palest scrim in the set, --accent-strong is the
   accent taken toward the page's own ink and measures no worse than 3.2:1.
*/
/* The hero sits on a photograph and takes white, set with the other dark
   grounds above. */
.hero--light :focus-visible,
.pagehead :focus-visible { --focus: var(--ink); }

/* The light heroes share the ink palette instead of white on a photo. */
.hero--light { color: var(--ink); background: var(--page); }
.hero--light .hero__sub { color: var(--ink-2); }
.hero--light .trust { border-top-color: var(--line); color: var(--ink-2); }
.hero--light .trust__item { border-left-color: var(--line); }
.hero--light .trust__score { color: var(--ink); }
.hero--light .btn--ghost {
  --btn-ink: var(--ink);
  /* --line is a hairline for separating blocks, not for drawing a control:
     against the white a light hero sits on it measures 1.27:1, so the second
     button on half the sites had no visible edge at all. --ink-3 is the
     lightest ink in the set that clears 3:1 on paper. */
  border-color: var(--ink-3);
  backdrop-filter: none;
}
.hero--light .btn--ghost:hover { background: var(--surface); border-color: var(--ink); }

/* The two column heroes: text one side, picture the other. */
.hero__grid { display: grid; gap: 34px; align-items: center; width: 100%; }
.hero__figure { margin: 0; position: relative; }
.hero__figure img {
  width: 100%;
  aspect-ratio: 4 / 3.3;
  object-fit: cover;
  border-radius: var(--radius);
}

/* -------------------------------------------------------------- sections --- */

.section { padding: clamp(64px, 9vw, 118px) 0; }
.section--alt { background: var(--surface); }
.section--tight { padding: clamp(44px, 6vw, 72px) 0; }

/* Two sections on the same ground do not read as two sections. They read as one
   very tall band with a hole in the middle, because the seam between them is
   both paddings added together and nothing marks where one subject ended. That
   is the shape a page takes when a document happens to file two alt sections
   next to each other, which several of them do. Halve the seam and draw the
   boundary the ground change would otherwise have drawn.

   The :has half is the same fix applied upwards. Where it is missing the seam
   is still shorter than it was, so the rule degrades to a smaller improvement
   rather than to a broken page. */
.section--alt + .section--alt,
.section:not(.section--alt, .section--dark) + .section:not(.section--alt, .section--dark) {
  padding-top: clamp(38px, 5vw, 62px);
  border-top: 1px solid var(--line);
}
.section--alt:has(+ .section--alt),
.section:not(.section--alt, .section--dark):has(+ .section:not(.section--alt, .section--dark)) {
  padding-bottom: clamp(38px, 5vw, 62px);
}

/* The dark sections (gallery, contact) carry their own ink tokens, so a
   layout that would rather have them light only redefines the tokens. */
.section--dark {
  --on-deep: #fff;
  --on-deep-2: rgb(255 255 255 / .72);
  --on-deep-3: rgb(255 255 255 / .58);
  --panel: rgb(255 255 255 / .045);
  --panel-line: rgb(255 255 255 / .12);
  --panel-today: rgb(var(--accent-rgb) / .13);
  background: var(--deep);
  color: var(--on-deep);
}
.section--dark .section-head p:not(.eyebrow) { color: var(--on-deep-2); }
.section--dark .eyebrow { color: var(--accent); }

.section-head { max-width: 640px; margin-bottom: clamp(36px, 5vw, 56px); }
.section-head--centre { margin-inline: auto; text-align: center; }
.section-head h2 { font-size: clamp(1.85rem, 4.6vw, 2.85rem); }
.section-head h2.h2--small { font-size: clamp(1.5rem, 3.4vw, 2rem); }
/*
   The lede, and NOT the eyebrow above it.

   Every section template emits the label as <p class="eyebrow"> inside the
   head, so an unqualified .section-head p (0,1,1) outranked .eyebrow (0,1,0)
   on both size and colour and the label came out as a 16.8px line of grey
   tracked capitals carrying 16px of margin above its own 18px below. That is
   the grey stamped opening a reader meets up to fifteen times across a five
   page site, and nobody chose it: it is a cascade accident.
*/
.section-head p:not(.eyebrow) {
  margin-top: 16px;
  font-size: 1.05rem;
  color: var(--ink-2);
}

/* ------------------------------------------------------------- services --- */

.services { display: grid; gap: 14px; }

.service {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  align-items: flex-start;
  padding: 22px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color .2s ease, transform .2s ease, box-shadow .2s ease;
}
.service:hover {
  border-color: rgb(var(--accent-rgb) / .55);
  transform: translateY(-2px);
  box-shadow: 0 18px 40px -30px rgb(var(--primary-rgb) / .75);
}
.service__icon {
  display: grid;
  place-items: center;
  width: 52px; height: 52px;
  flex: none;
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--accent-strong);
}
.service__icon svg { width: 27px; height: 27px; stroke-width: 1.5; }
.service__body { min-width: 0; flex: 1; }
.service h3 { font-size: 1.08rem; letter-spacing: -0.015em; }
.service p { margin-top: 7px; font-size: 15px; line-height: 1.6; color: var(--ink-2); }
/* The price and the minutes, on a rule at the foot of the card. It shipped as
   a bare number sitting wherever the description happened to end, which put it
   a third of the way up one card and at the bottom of the next, at a size one
   step off the service name. In a grid the cards in a row are the same height,
   so pinning the pair to the bottom edge lines every price up. */
.service__meta {
  width: 100%;
  margin-top: auto;
  padding-top: 13px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: baseline;
  gap: 12px;
  /* One line, so it is set tighter than the page's reading leading, and the
     height is then fixed rather than dependent on what is in it. Five sites
     price some services and not others; the template still draws the footer
     on the unpriced cards, and this keeps that empty rule on the same line as
     the ones with a number beside them. */
  line-height: 1.35;
  min-height: calc(1.2rem * 1.35 + 14px);
}
/* --ink-2, not --ink-3. --ink-3 is mixed far enough towards the page that it
   measures between 3.6 and 4.9 to 1 across the forty-four palettes, under the
   4.5 this needs at 13.5px on thirty-seven of them. --ink-2 is 5.1 at worst
   and still reads as the quieter half of the pair. */
.service__time {
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: .01em;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.service__price {
  /* Pushed right on its own so it stays on the right edge whether or not the
     item carries a duration, and stays at the baseline of the minutes. */
  margin-left: auto;
  align-self: baseline;
  flex: none;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.2rem;
  color: var(--accent-strong);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* The card grid was built for six and several trades have four or five, which
   left one card stranded on a row of its own. Four becomes two by two and
   fills the extra width by laying the card out sideways again; five keeps its
   row of three and centres the remaining pair under it on a six track grid. */
@media (min-width: 860px) {
  .service { flex-wrap: nowrap; }
  .service__meta { flex-wrap: nowrap; }

  .services:has(> :nth-child(4)):not(:has(> :nth-child(5))) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .services:has(> :nth-child(4)):not(:has(> :nth-child(5))) > .service {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 18px;
  }

  .services:has(> :nth-child(5)):not(:has(> :nth-child(6))) {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
  .services:has(> :nth-child(5)):not(:has(> :nth-child(6))) > .service { grid-column: span 2; }
  .services:has(> :nth-child(5)):not(:has(> :nth-child(6))) > .service:nth-child(4) { grid-column: 2 / span 2; }
}

/* ----------------------------------------------------------------- menu --- */

.menu-groups { display: grid; gap: clamp(28px, 4vw, 44px); }

.menu-group__name {
  font-size: 1.3rem;
  padding-bottom: 12px;
  margin-bottom: 6px;
  border-bottom: 2px solid var(--accent);
  display: inline-block;
}
/* --ink-2 rather than --ink-3, which is under 4.5:1 against the page on
   thirty-seven of the forty-four palettes. The group name above it is doing
   the separating, so this loses nothing by being readable. */
.menu-group__desc { font-size: 15px; color: var(--ink-2); margin: 4px 0 8px; }

.menu-list { display: grid; }
.menu-item { padding: 13px 0; border-bottom: 1px solid var(--line); }
.menu-item:last-child { border-bottom: 0; }
.menu-item__row { display: flex; align-items: baseline; gap: 8px; }
.menu-item__name { font-weight: 650; font-size: 1.05rem; min-width: 0; }
.menu-item__lead {
  flex: 1;
  min-width: 18px;
  border-bottom: 1px dotted var(--ink-3);
  opacity: .6;
  transform: translateY(-5px);
}
/* Set in the text colour rather than the accent. A printed menu prints the
   number in the same ink as the dish, and a column of accent coloured figures
   reads as fifteen links and gets scanned before any of the names do. The
   leader dots are what carry the eye across, so the price does not have to
   shout to be found. */
.menu-item__price {
  flex: none;
  font-weight: 650;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.menu-item__desc { margin-top: 3px; font-size: 14.5px; line-height: 1.55; color: var(--ink-2); max-width: 60ch; }
/* A footnote under a menu, held to a readable measure instead of running the
   full width of a 1180px page as one 14px line. The rule above it is what
   makes it a footnote, so the colour does not have to, and --ink-3 at 14px
   fell under 4.5:1 on most of the palettes. */
.menu-note {
  margin-top: 26px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  max-width: 68ch;
  font-size: 14px;
  color: var(--ink-2);
}

/* ------------------------------------------------------------- features --- */

.features { display: grid; gap: 14px; }
.feature {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 18px 20px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
}
.feature__icon {
  flex: none;
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--accent-strong);
}
.feature__icon svg { width: 21px; height: 21px; }
.feature h3 { font-size: 1rem; letter-spacing: -0.01em; }
.feature p { margin-top: 4px; font-size: 14.5px; line-height: 1.55; color: var(--ink-2); }

/* ---------------------------------------------------------------- steps --- */

.steps { display: grid; gap: 14px; }
.step {
  position: relative;
  display: flex;
  gap: 18px;
  align-items: flex-start;
  padding: 24px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.step__num {
  flex: none;
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-heading);
  font-weight: var(--heading-weight-strong);
  font-size: 16px;
}
.step h3 { font-size: 1.08rem; }
.step p { margin-top: 6px; font-size: 15px; line-height: 1.6; color: var(--ink-2); }

/* -------------------------------------------------------------- gallery --- */

.gallery {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
.gallery figure {
  position: relative;
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius);
  background: rgb(255 255 255 / .05);
}
.gallery img {
  width: 100%; height: 100%;
  object-fit: cover;
  aspect-ratio: 1 / 1;
  transition: transform .5s cubic-bezier(.2, .7, .3, 1);
}
.gallery figure:hover img { transform: scale(1.045); }
.gallery figure:first-child { grid-column: span 2; }
.gallery figure:first-child img { aspect-ratio: 16 / 11; }

/* -------------------------------------------------------------- reviews --- */

/* Evidence, not a badge. A boxed panel with a logo pinned to the right edge
   is the silhouette of a bought widget, so the box is gone and what is left
   is a masthead: one very large numeral, then the star row, the count and the
   source running on beside it, closed by a hairline. The numeral carries the
   section on its own, which is why it is set four times the size of the line
   it sits next to rather than one step above it. */
.rating-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 22px;
  padding: 0 0 clamp(20px, 3vw, 28px);
  margin-bottom: clamp(26px, 4vw, 40px);
  border-bottom: 1px solid var(--line);
}
.rating-summary__score {
  font-family: var(--font-heading);
  font-size: clamp(3.2rem, 9vw, 4.4rem);
  font-weight: var(--heading-weight-strong);
  line-height: .86;
  letter-spacing: -0.045em;
}
/* Star row, count and source share one line and wrap together on a phone.
   The alignment is inherited so that a layout which centres the summary,
   minimal does, centres this too: without it the numeral sits in the middle
   of the column and everything under it hangs off the left edge. */
.rating-summary__body {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: inherit;
  gap: 8px 16px;
}
.rating-summary__meta { font-size: 15.5px; color: var(--ink-2); }
.rating-summary__meta strong { color: var(--ink); font-weight: 650; }
/* --ink-2 rather than --ink-3 here and on the other small labels in this
   section. --ink-3 is mixed 40 per cent towards white from the site's own
   primary colour, so how dark it lands depends on the brand: measured across
   the demos it runs from 7:1 down to 3.4:1 against this band, which is under
   the 4.5:1 a 13px label owes a reader. The size, the weight and the caps do
   the work of putting these behind the words anyway. */
.rating-summary__badge {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
}
.rating-summary__badge svg { width: 15px; height: 15px; }

/* Horizontal snap rail on phones, balanced columns on desktop. A tall stack of
   five review cards is the fastest way to make someone stop scrolling. */
.reviews {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  margin-inline: -20px;
  padding: 4px 20px 18px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.reviews::-webkit-scrollbar { display: none; }

.review {
  scroll-snap-align: start;
  flex: 0 0 82%;
  display: flex;
  flex-direction: column;
  padding: clamp(24px, 2.6vw, 32px);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
/* The 82% is there so the next card shows at the edge and the rail reads as
   something to swipe. With one review there is no next card, so all it does is
   leave a strip of empty band on the right of the only thing in the section.
   Inert above 860px, where the rail becomes a grid and flex-basis stops
   meaning anything. */
.reviews:has(.review:only-child) .review { flex: 1 1 100%; }
/* Three registers rather than one. The review is the reason the card exists,
   so it is set at reading size in full ink; the name is small and semibold;
   the date is smaller still, tracked and capitalised so it reads as a label.
   Before this every line in the card was within half a step of every other
   one, which is what makes a card look filled in rather than composed. */
.review__text {
  font-size: 1.0625rem;
  line-height: 1.62;
  color: var(--ink);
  text-wrap: pretty;
}
/* The auto margin pushes the attribution to the foot of a card that has been
   stretched to the tallest in its row, so the rules above the names line up
   across the row instead of stopping at three different heights. Where the
   card is not stretched the margin resolves to nothing and the padding is the
   whole gap, which is why the gap lives in the padding. */
.review__author {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-top: auto;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}
.review__stars { margin: 5px 0 3px; }
.review__avatar {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  flex: none;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-size: 14px;
  font-weight: 700;
}
.review__name { font-size: 14.5px; font-weight: 650; line-height: 1.3; }
.review__when {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.reviews-hint {
  margin-top: 2px;
  font-size: 13px;
  color: var(--ink-2);
}

/* ---------------------------------------------------------------- about --- */

.about { display: grid; gap: 30px; }
.about__media { position: relative; }
.about__media img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--radius);
}
.about__body { align-self: center; }
.about__body h2 { font-size: clamp(1.85rem, 4.6vw, 2.85rem); }
.about__body p + p { margin-top: 18px; }
.about__body p { font-size: 1.05rem; color: var(--ink-2); }
.about__rule {
  width: 54px; height: 3px;
  background: var(--accent);
  margin: 22px 0;
}

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

.prose { max-width: 68ch; }
.prose h2 { font-size: clamp(1.6rem, 3.6vw, 2.3rem); margin-bottom: 18px; }
.prose p { font-size: 1.05rem; color: var(--ink-2); }
.prose p + p { margin-top: 16px; }

/* ------------------------------------------------------------------ faq --- */

.faq-grid { display: grid; gap: 30px; }
.faq { display: grid; gap: 10px; }
.faq__item {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  overflow: hidden;
}
.faq__item[open] { border-color: rgb(var(--accent-rgb) / .5); }
.faq__item summary {
  cursor: pointer;
  list-style: none;
  padding: 17px 20px;
  font-weight: 650;
  font-size: 1.01rem;
  display: flex;
  align-items: center;
  gap: 14px;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after {
  content: '';
  margin-left: auto;
  flex: none;
  width: 9px; height: 9px;
  border-right: 2px solid var(--ink-3);
  border-bottom: 2px solid var(--ink-3);
  transform: rotate(45deg) translateY(-3px);
  transition: transform .2s ease;
}
.faq__item[open] summary::after { transform: rotate(225deg) translateY(-3px); border-color: var(--accent); }
.faq__body { padding: 0 20px 18px; font-size: 15.5px; line-height: 1.65; color: var(--ink-2); max-width: 66ch; }

/* ---------------------------------------------------------------- areas --- */

.areas {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 14.5px;
  font-weight: 550;
  color: var(--ink-2);
}
.chip::before {
  content: '';
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

/* -------------------------------------------------------------- cta band --- */

.cta-band {
  position: relative;
  padding: clamp(48px, 7vw, 84px) 0;
  background: var(--accent);
  color: var(--accent-ink);
  overflow: hidden;
  isolation: isolate;
}
.cta-band__media { position: absolute; inset: 0; z-index: -2; }
.cta-band__media img { width: 100%; height: 100%; object-fit: cover; }
.cta-band--photo { background: var(--deep); color: #fff; }
.cta-band--photo::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to right, rgb(var(--primary-rgb) / .9), rgb(var(--primary-rgb) / .55));
}
.cta-band__inner {
  display: grid;
  gap: 24px;
  align-items: center;
}
.cta-band h2 { font-size: clamp(1.7rem, 4vw, 2.6rem); }
.cta-band p { margin-top: 12px; font-size: 1.05rem; opacity: .86; max-width: 56ch; }
.cta-band .btn--accent {
  --btn-bg: var(--accent-ink);
  --btn-ink: var(--accent);
  box-shadow: none;
  justify-self: start;
}
.cta-band--photo .btn--accent { --btn-bg: var(--accent); --btn-ink: var(--accent-ink); }
.cta-band .btn--accent:hover { --btn-bg: var(--accent-ink); filter: brightness(.96); }

/* -------------------------------------------------------------- booking --- */

.booking { display: grid; gap: 30px; align-items: start; }
.booking__intro h2 { font-size: clamp(1.85rem, 4.6vw, 2.85rem); }
.booking__lede { margin-top: 16px; font-size: 1.05rem; color: var(--ink-2); max-width: 46ch; }
.booking__note { margin-top: 14px; font-size: 14.5px; color: var(--ink-3); max-width: 46ch; }
.booking__alt { margin-top: 22px; }

.booking__card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(20px, 3vw, 30px);
  box-shadow: 0 24px 60px -40px rgb(var(--primary-rgb) / .6);
}

.bform { display: grid; gap: 14px; }
.bfield { display: grid; gap: 6px; }
.bfield > span { font-size: 14px; font-weight: 650; }
.bfield input,
.bfield select,
.bfield textarea {
  font: inherit;
  font-size: 16px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
  width: 100%;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.bfield input:focus,
.bfield select:focus,
.bfield textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgb(var(--accent-rgb) / .2);
}
.bfield textarea { resize: vertical; min-height: 80px; }
.bfield-pair { display: grid; gap: 14px; }
.bfield__hint { margin: -6px 0 0; font-size: 13px; color: var(--ink-3); }
.bform__privacy { font-size: 13px; color: var(--ink-3); }

/* Off screen rather than display:none: some bots skip anything hidden outright. */
.trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* -------------------------------------------------------------- contact --- */

/* minmax(0,…) rather than 1fr: a long hours row must wrap, not stretch the
   column past the screen. */
.contact { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; }

.panel {
  padding: clamp(24px, 4vw, 34px);
  background: var(--panel);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
}
.panel h3 {
  font-family: var(--font);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 20px;
}

.hours { display: grid; gap: 2px; }
.hours__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  padding: 11px 9px;
  border-radius: var(--radius);
  font-size: 14.5px;
  color: var(--on-deep-2);
}
.hours__row dt { min-width: 0; }
.hours__row.is-today {
  background: var(--panel-today);
  color: var(--on-deep);
  font-weight: 650;
}
.hours__today {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  vertical-align: 1px;
}
.hours__value { font-variant-numeric: tabular-nums; white-space: nowrap; }

.contact-status {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 22px;
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--ok-wash);
  color: var(--ok);
  font-size: 13.5px;
  font-weight: 650;
}
.section--dark .contact-status { color: var(--ok-up); }
.contact-status--closed { background: var(--bad-wash); color: var(--bad); }
.section--dark .contact-status--closed { color: var(--bad-up); }

.contact-line { display: flex; gap: 14px; align-items: flex-start; }
.contact-line + .contact-line { margin-top: 20px; }
.contact-line svg { width: 20px; height: 20px; color: var(--accent); flex: none; margin-top: 3px; }
.contact-line dt {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--on-deep-3);
}
.contact-line dd {
  margin: 3px 0 0;
  font-size: 16.5px;
  color: var(--on-deep);
  line-height: 1.45;
  overflow-wrap: anywhere;
}
/* Give the inline phone link a thumb-sized hit area of its own. */
.contact-line dd a { display: inline-block; padding: 6px 0; }
.contact-line dd a:hover { color: var(--accent); }

/* Buttons sit at the bottom of the panel so it visually balances the taller
   hours panel next to it instead of trailing off into empty space. */
.contact > .panel { display: flex; flex-direction: column; }
.contact-actions { display: grid; gap: 10px; margin-top: 28px; }
.section--dark .btn--ghost { --btn-ink: var(--on-deep); border-color: var(--panel-line); }
.section--dark .btn--ghost:hover { background: var(--panel); border-color: var(--on-deep-3); }

.map { margin-top: 18px; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--panel-line); }
.map iframe { width: 100%; aspect-ratio: 16 / 8; min-height: 260px; }

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

/* Room for the fixed call bar so it never sits on top of the small print. Taken
   out of the footer rather than off the bottom of the page, because the page is
   white and the footer is not: reserving it on the body left a white strip
   below a dark footer on every phone. Only show.blade.php prints both the bar
   and the footer, so the two always travel together. */
body.has-callbar { padding-bottom: 0; }
body.has-callbar .site-footer { padding-bottom: 118px; }

.site-footer {
  padding: 44px 0 40px;
  background: var(--deep);
  color: rgb(255 255 255 / .55);
  border-top: 1px solid rgb(255 255 255 / .1);
  font-size: 14px;
}
/* Four columns rather than three ends the flex row that used to space them out
   across whatever width was left, which put the contact block a different
   distance from the middle on every site. A grid holds the same shape at every
   width and lets the brand column keep the extra room it needs for a tagline. */
/* Four columns in a stack is a very long phone footer, so the two short lists
   go side by side and the week keeps the full width, where the day and its
   hours have room to sit at opposite edges of the same line. Placement is
   stated rather than flowed, so a site with no hours closes the gap instead of
   leaving one. */
.site-footer__top {
  display: grid;
  /* Uneven, because the two columns hold different things: a list of one word
     links on the left, and an address and an email address on the right, which
     want every pixel they can get before they start breaking mid word. */
  grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr);
  gap: 28px 28px;
  align-items: start;
  padding-bottom: 26px;
  margin-bottom: 26px;
  border-bottom: 1px solid rgb(255 255 255 / .1);
}
.site-footer__brand { grid-column: 1 / -1; }
.site-footer__col--hours { grid-column: 1 / -1; grid-row: 3; }

@media (min-width: 900px) {
  .site-footer__top { grid-template-columns: 1.4fr .8fr 1fr 1.1fr; gap: 30px 40px; }
  .site-footer__brand,
  .site-footer__col--hours { grid-column: auto; grid-row: auto; }
}

/* The label over each column. Small and spaced, so it reads as a heading
   without being loud enough to compete with the business name beside it. */
.site-footer__heading {
  margin-bottom: 12px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .82);
}
.site-footer__name {
  font-family: var(--font-heading);
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-transform: var(--heading-case);
  color: #fff;
}
.site-footer__tagline { margin-top: 4px; }
.site-footer__social { display: flex; gap: 6px; margin-top: 14px; }
.site-footer__social a { padding: 8px; border-radius: var(--radius); color: rgb(255 255 255 / .7); transition: color .2s ease, background-color .2s ease; }
.site-footer__social a:hover { color: #fff; background: rgb(255 255 255 / .1); }
.site-footer__social svg { width: 20px; height: 20px; }
.site-footer__links { display: grid; justify-items: start; gap: 8px; }
.site-footer__links a:hover { color: #fff; }
/* A long address or email in a 144px column on a phone would otherwise push the
   page sideways. */
.site-footer__contact { overflow-wrap: anywhere; }
.site-footer__contact p + p { margin-top: 6px; }
.site-footer__contact a:hover { color: #fff; }

/* The week. Day on the left, hours hard against the right, so the times line up
   into a column somebody can read down instead of a run of unaligned pairs. */
.site-footer__hours > div {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 3px 0;
}
.site-footer__hours dt { color: rgb(255 255 255 / .5); }
.site-footer__hours dd { text-align: right; font-variant-numeric: tabular-nums; }

/* Today is the row anybody actually came for. */
.site-footer__hours .is-today dt,
.site-footer__hours .is-today dd { color: #fff; font-weight: 650; }

/* Three layouts put the footer on paper instead of on ink. Their overrides live
   with the layout further down the file; these are the two blocks that did not
   exist when those were written, kept here with the rest of the footer.

   The day names take the same ink as the times. On a dark footer there is room
   to set them a shade behind and still clear 4.5:1, but measured on paper
   --ink-3 came out at 3.4:1 on split, 4.05 on editorial and 4.35 on minimal, so
   a whole column of the week failed. Today's row is what carries the hierarchy
   on these three, and it does it with weight and full ink rather than by making
   the other six harder to read. */
:is([data-layout="editorial"], [data-layout="split"], [data-layout="minimal"]) .site-footer__heading { color: var(--ink-2); }
:is([data-layout="editorial"], [data-layout="split"], [data-layout="minimal"]) .site-footer__hours dt { color: var(--ink-2); }
:is([data-layout="editorial"], [data-layout="split"], [data-layout="minimal"]) .site-footer__hours .is-today dt,
:is([data-layout="editorial"], [data-layout="split"], [data-layout="minimal"]) .site-footer__hours .is-today dd { color: var(--ink); }
.site-footer__legal { display: flex; flex-wrap: wrap; gap: 6px 20px; font-size: 12.5px; color: rgb(255 255 255 / .5); }
.site-footer__by { margin-left: auto; }
.site-footer__by a:hover { color: #fff; }

.nexvy-credit { display: inline-flex; align-items: center; gap: 6px; color: inherit; text-decoration: none; }
.nexvy-credit:hover span { text-decoration: underline; text-underline-offset: 3px; }
.nexvy-credit__mark { width: 15px; height: auto; flex: none; }

/* The basket, checkout, order and booking pages have no site footer, so the
   credit gets a quiet line of its own under the page. */
.shopfoot { padding: 28px 16px calc(28px + env(safe-area-inset-bottom)); text-align: center; font-size: 12.5px; color: var(--ink-3); }
.shopfoot .nexvy-credit:hover { color: var(--ink); }

/* ------------------------------------------------------- mobile call bar --- */

.callbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 95;
  display: flex;
  gap: 10px;
  padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
  background: rgb(255 255 255 / .93);
  backdrop-filter: saturate(180%) blur(14px);
  border-top: 1px solid var(--line);
  /* It is a layer over the page, not a strip cut off the bottom of it. The
     shadow is what says the page continues underneath. */
  box-shadow: 0 -14px 34px -26px rgb(var(--primary-rgb) / .9);
  transform: translateY(120%);
  transition: transform .28s cubic-bezier(.2, .7, .3, 1);
}
.callbar.is-visible { transform: none; }
/* Two buttons at almost the same width read as a choice, and the bar is not a
   choice: it exists so that one thumb makes the phone ring. Directions shrinks
   to the word it has to say and the call takes everything else.

   A percentage basis cannot do this. "Vägbeskrivning" is fourteen characters
   and its own minimum width was already wider than any share worth giving it,
   so the size has to come off the type rather than off the box. */
.callbar .btn { flex: 1 1 auto; }
.callbar .btn--outline {
  flex: 0 1 auto;
  font-size: 13.5px;
  padding-inline: 14px;
  /* --line is a hairline for separating things, and it measures 1.24:1 against
     the bar it is drawn on. Here it is not a separator, it is the entire edge
     of a control, and the only thing saying where the tap target stops. In ink
     it measures 3.4 to 3.9:1 on every layout, which is the floor a control edge
     has to clear. */
  border-color: var(--ink-3);
}
.callbar .btn--outline svg { width: 16px; height: 16px; }

/* ------------------------------------------------------------- assistant --- */

.chat { position: fixed; right: 16px; bottom: 16px; z-index: 96; }
/*
   Lifted only while there is a call bar under it to clear.

   The bar slides in at two thirds of a screen scrolled, so at the top of the
   page there is nothing there and the 92px was reserving room for a bar that
   had not arrived. What it did instead was park the bubble across the hero's
   address line on every phone: measured on rakstugan at 360x740 the bubble
   covered both items of the trust row, so the last fact on the first screen
   was behind it. Sitting at the corner until the bar appears clears the row by
   29px and still never collides with the bar.

   Bounded above by the width the bar itself stops at. The script keeps
   toggling is-visible on a desktop, where the bar is display:none, so without
   the bound the bubble would jump 72px up the screen on scroll for a bar that
   is not drawn.
*/
@media (max-width: 859px) {
  body.has-callbar:has(.callbar.is-visible) .chat { bottom: 92px; }
}
.chat__fab {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 12px 18px 12px 14px;
  min-height: 50px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 650;
  font-size: 15px;
  box-shadow: 0 14px 30px -12px rgb(var(--accent-rgb) / .9), 0 2px 6px rgb(0 0 0 / .15);
  transition: transform .16s ease;
}
.chat__fab:hover { transform: translateY(-1px); }

/*
   A circle on a phone, a labelled pill from a tablet up.

   131px of pill parked at the fold of a 360px screen is a third of the width
   of the page, and what it lands on is the last line of the hero: measured at
   360x740 it covered the address on Holmgren, Trattoria and Ostergarden. At
   52px it clears the first two outright.

   The label is taken out of the picture, not out of the button: the span still
   carries the button's accessible name, so a screen reader is told the same
   thing it was told before. */
@media (max-width: 559px) {
  .chat__fab {
    gap: 0;
    padding: 0;
    width: 52px;
    justify-content: center;
  }
  .chat__fab > span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
.chat__fab svg { width: 20px; height: 20px; }
.chat.is-open .chat__fab { display: none; }

.chat__panel {
  width: min(380px, calc(100vw - 32px));
  max-height: min(600px, calc(100vh - 32px));
  display: flex;
  flex-direction: column;
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 30px 70px -30px rgb(var(--primary-rgb) / .7), 0 4px 14px rgb(0 0 0 / .12);
  overflow: hidden;
}
.chat__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}
.chat__title { font-weight: 700; font-size: 15px; }
.chat__sub { font-size: 12.5px; color: var(--ink-3); margin-top: 1px; }
.chat__close { width: 36px; height: 36px; display: grid; place-items: center; border-radius: var(--radius); color: var(--ink-2); }
.chat__close:hover { background: var(--line); }
.chat__close svg { width: 18px; height: 18px; }
.chat__log {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
  display: grid;
  gap: 10px;
  align-content: start;
  min-height: 220px;
  scroll-behavior: smooth;
}
.chat__msg {
  max-width: 88%;
  padding: 10px 14px;
  border-radius: var(--radius);
  font-size: 14.5px;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.chat__msg--bot { background: var(--surface); border: 1px solid var(--line); justify-self: start; border-bottom-left-radius: 4px; }
.chat__msg--me { background: var(--accent); color: var(--accent-ink); justify-self: end; border-bottom-right-radius: 4px; }
.chat__msg--wait { color: var(--ink-3); font-size: 13px; justify-self: start; padding-left: 4px; }
.chat__form { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--line); }
.chat__form input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 16px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 12px;
}
.chat__form input:focus { outline: none; border-color: var(--accent); }
.chat__send { width: 44px; height: 44px; display: grid; place-items: center; flex: none; border-radius: var(--radius); background: var(--accent); color: var(--accent-ink); }
.chat__send svg { width: 18px; height: 18px; }
.chat__note { padding: 0 14px 12px; font-size: 11.5px; line-height: 1.45; color: var(--ink-3); }

/* ------------------------------------------------------------- reveal ----- */

/*
   THE ORDER HERE IS LOAD BEARING. A section is only hidden underneath the
   "anim" class, and show.blade.php adds that class from inside the observer's
   own first callback, never before observing.

   Without that, a browser where IntersectionObserver exists and silently never
   fires renders a paying customer's website completely blank. That is not a
   hypothetical: it was found by testing. Do not move the hiding out of the
   .anim scope.
*/
/* WHAT MOVES. A photograph arriving is a photograph arriving. A paragraph
   arriving is a paragraph that was not there when the reader looked, and a
   page doing it to sixty-three elements is a page that cannot be skimmed:
   every heading a reader scrolls past has to be waited for.

   So the default is that nothing moves, and pictures opt in. A site that
   wants the old behaviour says so with the revealText furniture flag, which
   is off everywhere unless a document turns it on. */
.anim .reveal { opacity: 1; transform: none; }

.anim figure.reveal,
.anim .reveal:is(.hero__figure, .about__media, .feature-pair__media, .gallery-strip, .map),
.anim body[data-furniture~="revealText"] .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .6s cubic-bezier(.2, .7, .3, 1), transform .6s cubic-bezier(.2, .7, .3, 1);
  transition-delay: var(--delay, 0ms);
}
.anim .reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
  .anim .reveal { opacity: 1; transform: none; }
}

/* ==========================================================================
   Layouts
   --------------------------------------------------------------------------
   Everything above is "classic". Each block below restates only what differs.
   ========================================================================== */

/* The dark layout has a block of its own at the foot of this file. It used to
   live here as nine rules, which is why it read as a recolour of the block
   above rather than as a design. */

/* ----------------------------------------------------------- editorial --- */
/* THE OPENING SPREAD.

   The type sits in a column on the left and the photograph runs off the right
   edge of the window. That is the one thing this hero has that no other hero
   in the file has, and it is what the rest of the layout is composed against:
   everything else on an editorial page is held inside a measure, so the
   picture is the only object allowed past it.

   What it replaces was a photograph in a box with a second box offset behind
   it in the accent colour. A hairline frame hanging sixteen pixels off the
   corner of a picture is a decoration, and a decoration is the thing this
   register cannot carry: a spread is made by where the picture is cropped and
   how far it runs, not by what is drawn around it.

   The rest of the layout is at the end of this file, under "editorial". Only
   the hero lives up here, beside the other hero modifiers it has to beat. */

.hero--editorial {
  align-items: center;
  min-height: 0;
  max-height: none;
  /* Computed, not a magic 120px. The rail header is 92px and the example bar
     pushes it down another 34, so a flat number cleared the default bar and
     ran the eyebrow and the top of the photograph under every other one.
     --header-h is declared once per variant per breakpoint and --header-top
     is the example bar, so this cannot fall out of date. */
  padding-top: calc(var(--header-top) + var(--header-h) + var(--hero-clear));
  padding-bottom: clamp(40px, 6vw, 80px);
}
.hero--editorial .hero__inner { max-width: none; }
/* A headline that means something at the size it is set. The old clamp
   crossed the base hero's, so the layout with the shorter measure had the
   SMALLER headline: 73.6px against 75.2px at 1280. Held to thirteen
   characters the line breaks where a feature's headline breaks and the size
   has somewhere to go. */
.hero--editorial h1 {
  font-size: clamp(2.6rem, 7.8vw, 5rem);
  line-height: 1.02;
  max-width: 14ch;
}
.hero--editorial .hero__sub {
  max-width: 42ch;
  font-size: clamp(1.06rem, 2.3vw, 1.24rem);
  line-height: 1.62;
}

/* The picture escapes the column to the right edge of the window. Same
   expression the marquee and the filmstrip use, so a 1180px page and a
   1920px one both land on the same twenty pixel margin. */
@media (min-width: 860px) {
  .hero--editorial .hero__grid {
    /* An editorial spread is composed on its feet, not on its middle. The
       text column is shorter than the picture, and centring the two left the
       picture floating with a ragged margin above and below the words. */
    align-items: end;
    grid-template-columns: minmax(0, .92fr) minmax(0, 1fr);
    gap: clamp(40px, 5vw, 80px);
  }
  .hero--editorial .hero__figure {
    margin-right: calc(-1 * max(20px, calc((100vw - 1180px) / 2 + 20px)));
  }
  .hero--editorial .hero__inner { padding-bottom: clamp(6px, 1vw, 14px); }
}

/* On a phone there is no spread, so the picture runs off both edges instead
   of one and the crop opens out: a 4/4.2 plate at 335px is 352px of
   photograph between the buttons and the fold. */
@media (max-width: 859px) {
  .hero--editorial .hero__figure {
    margin-inline: -20px;
    margin-top: clamp(28px, 6vw, 40px);
  }
  .hero--editorial .hero__figure img { aspect-ratio: 4 / 3.1; }
}
/* Wider than it was and therefore shorter. The picture used to be half of a
   1140px column at 4/4.2; running it off the right edge makes it 702px at
   1440, and the same crop would have been 737px tall, which is a first screen
   nobody can see the bottom of. A long crop is also what a spread wants: the
   photograph is the width of the page, not the height of it. */
.hero--editorial .hero__figure img { aspect-ratio: 4 / 3.1; }

/* --------------------------------------------------------------- split --- */
/* The split layout is written in one block at the foot of this file, with
   every selector scoped to [data-layout="split"], for the reason the atelier
   block states: a plain .hero--split rule here is (0,1,0) and loses to the
   860px and 1080px media queries below, so half the layout would have had to
   be maintained in two places. What is left here is nothing. */


/* =============================================================== 560px ==== */

@media (min-width: 560px) {
  .hero__actions .btn { flex: 0 0 auto; }
  .services { grid-template-columns: repeat(2, 1fr); }
  .features { grid-template-columns: repeat(2, 1fr); }
  .review { flex-basis: 60%; }
  .gallery { grid-template-columns: repeat(3, 1fr); gap: 12px; }
  .gallery figure:first-child { grid-column: span 1; grid-row: span 2; }
  .gallery figure:first-child img { aspect-ratio: 2 / 3.06; }
  .gallery--2 { grid-template-columns: repeat(2, 1fr); }
  .gallery--2 figure:first-child { grid-row: span 1; }
  .gallery--2 figure:first-child img { aspect-ratio: 4 / 3; }
  .gallery--2 img { aspect-ratio: 4 / 3; }
  .bfield-pair { grid-template-columns: 1fr 1fr; }
  .cta-band__inner { grid-template-columns: 1fr auto; }
  .cta-band .btn--accent { justify-self: end; }
}

/* =============================================================== 860px ==== */

@media (min-width: 860px) {
  body { font-size: 17px; }
  body.has-callbar { padding-bottom: 0; }
  /* No bar at this width, so the footer stops reserving room for one. */
  body.has-callbar .site-footer { padding-bottom: 40px; }
  body.has-callbar .chat { bottom: 20px; }

  .brand__meta { display: block; }
  .nav-toggle { display: none; }
  .mobile-nav { display: none; }
  .callbar { display: none; }

  .header-inner { min-height: 84px; gap: 26px; }
  .nav { display: flex; }
  .header-actions .btn { display: inline-flex; }

  .services { grid-template-columns: repeat(3, 1fr); }
  .service { flex-direction: column; gap: 16px; padding: 28px 26px; }

  .features { grid-template-columns: repeat(4, 1fr); }
  .feature { flex-direction: column; }
  .steps { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
  .step { flex-direction: column; }

  .menu-groups { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(40px, 6vw, 80px); }

  .faq-grid { grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); gap: 48px; align-items: start; }
  .faq-grid .section-head { margin-bottom: 0; }

  .booking { grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); gap: 48px; }

  .about {
    grid-template-columns: 1fr 1.12fr;
    gap: 52px;
    align-items: center;
  }
  .about__media img { aspect-ratio: 4 / 4.7; }

  .contact { grid-template-columns: 1fr 1fr; gap: 20px; }
  .contact-actions { margin-top: auto; padding-top: 28px; }

  /* The rail becomes a grid. Grid rather than CSS columns so the reviews stay in
     the order Places returned them and any leftover space lands at the end
     instead of as a hole in the middle. The cards stretch to the tallest of
     the row so their foot rules line up; left to their own heights, three
     reviews of unequal length end three rules at three different places and
     the row reads as a mistake. */
  .reviews {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    align-items: stretch;
    overflow: visible;
    margin-inline: 0;
    padding: 0;
  }
  .review { flex-basis: auto; }
  .reviews-hint { display: none; }

  /* One review is not a row of cards. Left in the grid it draws a third of a
     band and leaves the other two thirds empty, which reads as two cards that
     failed to load rather than as the one review the business has. Given the
     whole width it would be a banner, so it takes a reading measure and
     stops. */
  .reviews:has(.review:only-child) { grid-template-columns: minmax(0, 620px); }

  .hero__grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(36px, 5vw, 72px); }
}

/* ============================================================== 1080px ==== */

@media (min-width: 1080px) {
  .status-pill { display: flex; }
  /* The dark hero used to be classic's, so it took a top padding here to clear
     the fixed bar. It no longer has one: the photograph is a plate that runs
     up under the bar and the words begin on the black beneath it, so every
     number that positioned that hero lives in the dark block at the foot of
     this file. */
  .reviews { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  /* What three columns do with a number of reviews that is not three.

     Five is the common case, and three plus two leaves the bottom right
     corner of the band empty. An empty cell at the end of a row of cards is
     the same tell as a gallery built for four with two pictures in it: the
     page looks like it is waiting for content that never arrives.

     Six columns with every card across two of them is the same three up row,
     and it lets the pair that is left start half a column in, so they sit
     under the middle of the row above instead of hanging off its left edge.
     Four goes to two columns rather than three plus one orphan. Two does the
     same, for the same reason. */
  .reviews:has(.review:nth-child(2):last-child),
  .reviews:has(.review:nth-child(4):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .reviews:has(.review:nth-child(5):last-child) { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .reviews:has(.review:nth-child(5):last-child) > .review { grid-column: span 2; }
  .reviews:has(.review:nth-child(5):last-child) > .review:nth-child(4) { grid-column: 2 / span 2; }
  .gallery { gap: 14px; }
}

/* The band between the two column grid and the three column one. An odd number
   of reviews ends on a half empty row here for the same reason five ended on
   one above, and the answer is the same shape: the last card takes the row
   rather than leaving the cell beside it blank. Bounded above because at
   1080px the counting rules take over and a card spanning two of three
   columns would break the row they build. */
@media (min-width: 860px) and (max-width: 1079px) {
  .reviews:has(.review:nth-child(odd):last-child) > .review:last-child:not(:only-child) {
    grid-column: span 2;
  }
  /* A card twice the width of its neighbours is still a card, but the words
     inside it are now on a line nobody wants to read across. The measure is
     held where the other cards hold it and the card keeps the room. */
  .reviews:has(.review:nth-child(odd):last-child) > .review:last-child:not(:only-child) .review__text {
    max-width: 62ch;
  }
}

/* The hidden attribute must win over the panel display, or the panel opens by itself. */
.chat__panel[hidden] { display: none; }

/* --------------------------------------------------------- example bar --- */
/* On showcased sites only: one line saying the business is invented. The
   fixed header moves down by its height so nothing is covered. */

/* The height is one custom property declared on the body, and every offset
   below reads it, including --header-top further down.

   It used to be a hard 34px on the bar and four hardcoded numbers with 34
   baked into them further down, and the span was clamped to two lines. The
   Swedish sentence is three lines at 11px in a 375px viewport, so on a phone
   the bar read "Företaget är påhittat och omdömena är exempel. Sida..." and
   stopped: the clause that survived was the admission and the clause that was
   cut was "Sidan är riktig.", which is the claim the bar exists to make.

   The bar is auto height with padding now, and min-height turns the declared
   number into the height it actually has: as long as the number is at or above
   what the sentence needs, the bar is exactly that tall and every offset below
   is exact rather than approximately right. The numbers are measured, not
   guessed, and there are three of them because the sentence needs one line,
   two lines or three lines depending on how much width it has. See the bands
   below. */
.example-bar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 101;
  min-height: var(--example-bar, 34px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 4px 12px;
  padding: 7px 12px;
  /* The site's own darkest ground, not the agency's green. Painted in a
     brand colour that belongs to somebody else, this strip was the most
     saturated object on every page it appeared on, sitting directly above
     the business's own name and out-shouting it. --deep and --on-deep are
     the pair the dark sections already use, so the contrast is one that has
     been measured rather than a second one to keep in step. */
  --on-deep: #fff;
  background: var(--deep);
  color: var(--on-deep);
  font-family: var(--font);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
}
.example-bar a { text-decoration: underline; white-space: nowrap; }

/* One number, declared on the body, inherited by the bar and read by every
   offset, so the page below can never be pushed down by an amount the bar is
   not actually using.

   THE THREE BANDS, MEASURED. A flex row of a sentence and a link, 7px of
   padding each side. Heights taken in the browser on eight showcased sites,
   one per body face in the catalogue, in both languages, because the face is
   the site's own and the sentence wraps where that face runs out of room.

     760px and up    one line     34.0 needed, 34 declared
     561 to 759px    two lines    48.0 needed, 48 declared
     560px and down  three rows   56.6 needed, 58 declared

   The two clauses of the sentence wrapped onto two lines and the link onto a
   third is the widest the bar ever gets: every face measured agreed to the
   pixel at 320px and at 375px, so the 1.4px of slack on the last band is
   rounding and not a guess. The old file declared 34px everywhere and 54px
   below 560, so the bar was taller than its own number in two of the three
   bands: at 700px the fixed header sat 14px inside it, and on a phone the
   header overlapped it by 2.5px while the heroes that clear --header-top
   started 22px too high. */
body.has-example-bar {
  --example-bar: 34px;
  /* The header variants position the whole masthead off --header-top, and it
     used to carry its own copy of 34px, which is how it stayed at 34 while the
     bar underneath it grew. It is the same number, so it reads the same
     property. */
  --header-top: var(--example-bar);
}
body.has-example-bar .site-header { top: var(--example-bar); }
body.has-example-bar .mobile-nav { padding-top: calc(90px + var(--example-bar)); }
/* The dark hero is not in this list either, and for the same reason as the
   split one: its photograph is a plate that starts at the top of the document
   and is supposed to run up behind both the bar and the header, so there is
   nothing here for the bar to push down. */
/* The split hero is not in this list. It clears the bar by reading
   --header-top and --header-h in its own block, which is the same expression
   on every header variant and on a showcased site as on a plain one, so there
   is no second copy of the number here to fall out of date. */
@media (max-width: 759px) {
  body.has-example-bar { --example-bar: 48px; }
}
@media (max-width: 560px) {
  .example-bar { font-size: 11px; gap: 3px 8px; }
  body.has-example-bar { --example-bar: 58px; }
}

/* ========================================================================
   STRUCTURAL VARIANTS

   Everything above this line is the base: the page every generated site
   drew when the only thing that changed between two sites was the colour.
   Everything below it is what makes two sites different shapes.

   A variant is dealt per site by App\Content\Variants, seeded on the slug,
   and arrives here either as a data attribute on <body> (data-v-gallery=
   "masonry") or as a block class the section template emits (.svc-list).
   The first option of every list is the base above, which is why there is
   no rule here for data-v-header="bar" or for the card grids.
   ======================================================================== */

/* ---------------------------------------------------- header --- */
/* ==========================================================================
   Header variants: stack, centred, rail, minimal
   --------------------------------------------------------------------------
   'bar' is the header every site shipped with and nothing here touches it.
   The other four are keyed on the data attribute the renderer prints on
   <body>, so a site keeps its header for as long as it keeps its slug.

   ONE NUMBER, ONE PLACE. The header is fixed, so everything underneath it is
   positioned by hand: the hero's top padding, the drawer's, and the anchor
   offset. Those all read --header-h, which is declared once per variant per
   breakpoint below. Change a header's height there and the page under it
   follows. --header-top is the example bar, which pushes the whole header
   down on showcased sites.

   WHAT THE SCRIPT KNOWS. Nothing new. It toggles .nav-open on <body> and
   .is-stuck on the header, and every variant is built out of those two, so
   show.blade.php did not have to change and the drawer keeps working
   everywhere, including on desktop under 'minimal'.
   ========================================================================== */

body {
  --header-top: 0px;
  --header-h: 74px;
}
/* --header-top is the example bar. It is declared with the bar's own height,
   up in the example bar block, so the two can never disagree. */

@media (min-width: 860px) {
  body { --header-h: 84px; }
}

/* The gap each hero leaves between the bottom of the bar and its first line.
   Stated as a clearance rather than as a padding so a taller header can add
   itself to it without either number being written down twice. The order
   below matches demo.css: a layout modifier wins over --noimage, because
   that is which of the two sets the padding there. */
.hero { --hero-clear: 34px; }
.hero--noimage { --hero-clear: 76px; }
.hero--editorial,
.hero--bold { --hero-clear: 46px; }
.hero--minimal { --hero-clear: 56px; }
/* The atelier hero opens on an eyebrow at 12px and then a headline that runs
   the full measure. It needs more air over it than any of the others, because
   there is nothing beside the headline for the eye to land on first. */
.hero--atelier { --hero-clear: 64px; }

@media (min-width: 860px) {
  .hero { --hero-clear: 24px; }
  .hero--noimage { --hero-clear: 66px; }
  .hero--editorial,
  .hero--bold { --hero-clear: 36px; }
  .hero--minimal { --hero-clear: 46px; }
  .hero--atelier { --hero-clear: 58px; }
}

/* Only the heroes whose text starts at the top can be covered by a taller
   header. The classic and dark heroes hold their text against the bottom of a
   92svh block, and the picture behind it is supposed to run up under the bar,
   so they are deliberately left alone.

   The second selector is the same rule again for the showcased sites. Their
   example bar rules in demo.css carry exactly the specificity of the first
   one, and a tie is settled by file order, which is not something this file
   should depend on. */
/* The bold hero is not in this list because it clears the bar on EVERY header
   variant, in its own scope, rather than only on the two tall ones. It used to
   be here and to carry a hardcoded 120px of its own on top, which won, so the
   clearance it declares was never the clearance it got: measured at 375px the
   largest headline on the site started eleven pixels under a fixed bar. */
/* .hero--minimal is not in this list. The minimal layout draws that hero and
   its header pool is minimal and rail, so the two tall variants named here can
   never appear above it; the rule was matching nothing and the clearance it
   claimed to set was coming from a literal further down. It clears the bar in
   its own scope now, on every header it can actually be dealt. */
body:is([data-v-header="stack"], [data-v-header="centred"]) :is(.hero--noimage, .hero--editorial, .hero--atelier),
body.has-example-bar:is([data-v-header="stack"], [data-v-header="centred"]) :is(.hero--noimage, .hero--editorial, .hero--atelier) {
  padding-top: calc(var(--header-top) + var(--header-h) + var(--hero-clear));
}

/* The split hero is not in this list either, and for the same reason: its own
   block clears --header-top plus --header-h on every header variant rather
   than only on the two tall ones, so there is nothing left here to special
   case. */

/* The drawer is a full screen panel with the header floating on top of it, so
   its first link has to clear the header it opened from. */
body:is([data-v-header="stack"], [data-v-header="centred"]) .mobile-nav,
body.has-example-bar:is([data-v-header="stack"], [data-v-header="centred"]) .mobile-nav {
  padding-top: calc(var(--header-top) + var(--header-h) + 20px);
}

/* Anchor jumps. html is the scroller and the variant lives on body, so the
   offset has to be read across. Where :has is missing the page still lands on
   the right section, a few pixels high. */
@media (min-width: 860px) {
  html:has(body[data-v-header="centred"]) { scroll-padding-top: 154px; }
  html:has(body[data-v-header="rail"]) { scroll-padding-top: 108px; }
  /* stack collapses its strip the moment the page moves, so by the time any
     jump lands the header is one row again and 88px is already right. */
}

/* ----------------------------------------------------------------- stack ---
   A thin utility strip carrying the status, the address, the number and the
   social links, then a taller row with the brand and the nav. The strip rolls
   up as soon as the page moves, so a phone gets its screen back after the
   first scroll and the anchor offset stays what it was.
   -------------------------------------------------------------------------- */

[data-v-header="stack"] {
  --hdr-strip: 44px;
  --hdr-row: 62px;
  --header-h: calc(var(--hdr-strip) + var(--hdr-row));
}

@media (min-width: 860px) {
  [data-v-header="stack"] {
    --hdr-strip: 38px;
    --hdr-row: 78px;
  }
}

[data-v-header="stack"] .header-utility {
  /* Positioned, or the header's own scrim gradient paints over the strip. */
  position: relative;
  z-index: 1;
  height: var(--hdr-strip);
  overflow: hidden;
  background: rgb(var(--primary-rgb) / .94);
  color: rgb(255 255 255 / .8);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.2;
  transition: height .3s ease;
}
[data-v-header="stack"] .site-header.is-stuck .header-utility { height: 0; }

[data-v-header="stack"] .header-utility__inner {
  display: flex;
  align-items: stretch;
  gap: 12px;
  height: var(--hdr-strip);
  min-width: 0;
}
[data-v-header="stack"] .header-utility__side {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
[data-v-header="stack"] .header-utility__side--end {
  margin-left: auto;
  gap: 2px;
  flex: none;
}

[data-v-header="stack"] .header-utility .status-pill {
  display: flex;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: inherit;
  color: inherit;
}
/* The address is the first thing to go. Below a tablet the strip is the status
   and the number, which are the two things somebody standing outside wants. */
[data-v-header="stack"] .header-utility__where { display: none; }

@media (min-width: 720px) {
  [data-v-header="stack"] .header-utility__where {
    display: block;
    padding-left: 12px;
    border-left: 1px solid rgb(255 255 255 / .22);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}
/* No status line on this site, so nothing to divide from. */
@media (min-width: 720px) {
  [data-v-header="stack"] .header-utility__where:first-child {
    padding-left: 0;
    border-left: 0;
  }
}

[data-v-header="stack"] .header-utility__tel,
[data-v-header="stack"] .header-utility__social {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Stretched to the strip, which is 44px tall where there are thumbs. */
  align-self: stretch;
  gap: 8px;
  padding-inline: 10px;
  color: #fff;
  white-space: nowrap;
  transition: color .2s ease;
}
[data-v-header="stack"] .header-utility__tel:hover,
[data-v-header="stack"] .header-utility__social:hover { color: var(--accent); }
[data-v-header="stack"] .header-utility__tel svg { width: 15px; height: 15px; }
[data-v-header="stack"] .header-utility__social { min-width: 40px; padding-inline: 6px; }
[data-v-header="stack"] .header-utility__social svg { width: 17px; height: 17px; }

/* The brand row. The number and the status have already been said above it,
   so the row itself is only the wordmark and the nav. */
[data-v-header="stack"] .header-inner { min-height: var(--hdr-row); }
[data-v-header="stack"] .header-actions .btn,
[data-v-header="stack"] .header-actions .status-pill { display: none; }

@media (min-width: 860px) {
  [data-v-header="stack"] .brand__mark { width: 48px; height: 48px; font-size: 15px; }
  [data-v-header="stack"] .brand__name { font-size: 19px; }
  [data-v-header="stack"] .nav { gap: 2px; }
  [data-v-header="stack"] .nav a { font-size: 15px; padding: 10px 15px; }

  /* The strip rolls up on the first scroll and took the phone number with it,
     so from the second screen onwards this header was the only one of the five
     with no way to call from the bar. The row carries it once the strip has
     gone, and gives it back the moment the reader returns to the top. */
  [data-v-header="stack"] .site-header.is-stuck .header-actions .btn { display: inline-flex; }
}

/* --------------------------------------------------------------- centred ---
   The wordmark on its own line with the nav beneath it, which is how a salon
   or a florist with a name worth looking at builds a header. The actions are
   taken out of the flow so the brand centres on the window rather than on
   whatever is left over beside them.
   -------------------------------------------------------------------------- */

[data-v-header="centred"] {
  --hdr-row1: 74px;
  --hdr-row2: 0px;
  --header-h: 74px;
}

@media (min-width: 860px) {
  [data-v-header="centred"] {
    /* Row one holds the stacked wordmark: the monogram, the name and the city
       on three lines. The type sizes below are set against this number, so the
       row cannot be pushed taller than what --header-h promises. */
    --hdr-row1: 88px;
    --hdr-row2: 50px;
    --header-h: 138px;
  }
}

[data-v-header="centred"] .header-inner {
  flex-wrap: wrap;
  justify-content: center;
  gap: 0;
  min-height: calc(var(--hdr-row1) + var(--hdr-row2));
}
[data-v-header="centred"] .brand {
  flex: 1 0 100%;
  justify-content: center;
  align-items: center;
  margin-right: 0;
  min-height: var(--hdr-row1);
  /* Room for the toggle, and the same room again on the other side so the
     wordmark is centred on the window and not on the gap. */
  padding-inline: 56px;
  text-align: center;
}
[data-v-header="centred"] .brand > span { justify-items: center; }
[data-v-header="centred"] .brand__name { line-height: 1.15; }
[data-v-header="centred"] .brand__meta {
  display: block;
  font-size: 11px;
  line-height: 1.4;
  letter-spacing: .18em;
  text-transform: uppercase;
}

/* display:contents lets the three actions position themselves against the
   header row instead of against each other. */
[data-v-header="centred"] .header-actions { display: contents; }
[data-v-header="centred"] .header-actions > * {
  position: absolute;
  top: calc((var(--hdr-row1) - 44px) / 2);
  height: 44px;
}
[data-v-header="centred"] .header-actions .status-pill {
  left: 20px;
  align-items: center;
}
[data-v-header="centred"] .header-actions .btn,
[data-v-header="centred"] .nav-toggle { right: 20px; }
/*
   SHARED. The number set as a line of type rather than as a filled pill
   arrived after this variant was written, so .header-tel was the one child of
   .header-actions with no side named. position: absolute with neither left
   nor right leaves an element at its static position, which on a centred
   header is the middle of the row: the phone number was drawn straight
   through the business name. It takes the right edge like the pill it
   replaces, and steps clear of the toggle at the widths where both show.
*/
[data-v-header="centred"] .header-actions .header-tel {
  right: 76px;
  display: flex;
  align-items: center;
}
@media (min-width: 860px) {
  [data-v-header="centred"] .header-actions .header-tel { right: 20px; }
}

/*
   SHARED, and the other half of the same fault.

   The generic rule that drops the number below 480px, where the fixed call
   bar is already carrying it across the whole width of the screen, is
   body.has-callbar .header-tel at (0,2,1). The rule above is (0,3,0), so on
   this variant alone the number came back, and on a centred header it is
   absolutely positioned against the right edge with the wordmark centred
   behind it: measured at 375px the two were drawn through each other.
*/
@media (max-width: 480px) {
  body.has-callbar[data-v-header="centred"] .header-actions .header-tel { display: none; }
}

@media (min-width: 860px) {
  [data-v-header="centred"] .brand { flex-direction: column; gap: 8px; padding-inline: 180px; }
  [data-v-header="centred"] .brand__mark { width: 40px; height: 40px; }
  [data-v-header="centred"] .brand__name { font-size: 19px; letter-spacing: 0; }

  [data-v-header="centred"] .nav {
    flex: 1 0 100%;
    justify-content: center;
    align-items: center;
    min-height: var(--hdr-row2);
    gap: 4px;
    border-top: 1px solid rgb(255 255 255 / .18);
  }
  [data-v-header="centred"] .nav a {
    font-size: 12.5px;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    padding: 14px;
    color: rgb(255 255 255 / .9);
  }
  [data-v-header="centred"] .is-stuck .nav,
  [data-v-header="centred"].hero-light .nav { border-top-color: var(--line); }
  [data-v-header="centred"] .is-stuck .nav a,
  [data-v-header="centred"].hero-light .nav a { color: var(--ink-2); }

  /* Stacking the wordmark over the nav costs 138px, which is right for the top
     of the page and is a sixth of a laptop screen to keep for the rest of it.
     Once the page has moved the brand lies down into a row and the header ends
     up close to the other four. The clearances above are all measured against
     the tall state, which is the state the page loads in, so nothing that reads
     --header-h has to know this happens.

     The nav row survives the collapse. A centred header is chosen for sites
     whose nav is the point of it, and hiding that on scroll would be trading
     the wrong thing for the space. */
  [data-v-header="centred"] .site-header.is-stuck {
    --hdr-row1: 58px;
    --hdr-row2: 46px;
  }
  [data-v-header="centred"] .site-header.is-stuck .brand {
    flex-direction: row;
    gap: 12px;
  }
  [data-v-header="centred"] .site-header.is-stuck .brand > span { justify-items: start; }
  [data-v-header="centred"] .site-header.is-stuck .brand__name { font-size: 17px; }
  [data-v-header="centred"] .site-header.is-stuck .nav a { padding: 12px 14px; }
  [data-v-header="centred"] .header-inner,
  [data-v-header="centred"] .brand { transition: min-height .3s ease; }
}

@media (prefers-reduced-motion: reduce) {
  [data-v-header="centred"] .header-inner,
  [data-v-header="centred"] .brand { transition: none; }
}

/* ------------------------------------------------------------------ rail ---
   Brand left, nav right, and nothing else in the bar. The number lives on the
   right edge of the window instead, which keeps it reachable on every screen
   of the page without a button competing with the headline.
   -------------------------------------------------------------------------- */

@media (min-width: 860px) {
  [data-v-header="rail"] { --header-h: 92px; }
  [data-v-header="rail"] .header-inner { min-height: var(--header-h); }
}

[data-v-header="rail"] .header-actions .btn { display: none; }
[data-v-header="rail"] .nav { gap: 0; }
[data-v-header="rail"] .nav a {
  position: relative;
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-transform: var(--heading-case);
  /* 44px of link to hit, with the rule drawn close under the word rather than
     at the bottom of the padding. */
  padding: 11px 0;
  margin-inline: 14px;
  border-radius: 0;
}
[data-v-header="rail"] .nav a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 8px;
  height: 1px;
  background: currentColor;
  opacity: 0;
  transition: opacity .2s ease;
}
[data-v-header="rail"] .nav a:hover { background: none; }
[data-v-header="rail"] .nav a:hover::after { opacity: 1; }

.phone-rail {
  display: none;
  position: fixed;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 95;
  align-items: center;
  gap: 12px;
  padding: 22px 12px;
  writing-mode: vertical-rl;
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-right: 0;
  border-radius: var(--radius) 0 0 var(--radius);
  box-shadow: 0 18px 44px -30px rgb(var(--primary-rgb) / .9);
  font-size: 13.5px;
  font-weight: 650;
  letter-spacing: .06em;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}
.phone-rail svg { width: 16px; height: 16px; color: var(--accent); transition: color .2s ease; }
.phone-rail:hover {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
.phone-rail:hover svg { color: currentColor; }

/* It needs a column of its own to hang in. Below this the call bar at the
   bottom of the screen is already carrying the number. */
@media (min-width: 1080px) {
  .phone-rail { display: flex; }
}

/* --------------------------------------------------------------- minimal ---
   Brand left, one accent CTA right, and every link behind the drawer at every
   width. The drawer is the same panel the phone gets, opened by the same
   button and the same script, laid out for a wide screen.
   -------------------------------------------------------------------------- */

[data-v-header="minimal"] .status-pill { display: none; }

/* The drawer takes the scrollbar away while it is open, and on a desktop that
   is a visible jump. Reserving the gutter costs a few pixels and holds the
   page still. */
html:has(body[data-v-header="minimal"]) { scrollbar-gutter: stable; }

@media (min-width: 860px) {
  [data-v-header="minimal"] .nav { display: none; }
  [data-v-header="minimal"] .nav-toggle { display: grid; }
  [data-v-header="minimal"] .mobile-nav {
    display: grid;
    /* Started rather than centred. A site with eight sections and a short
       window would otherwise centre the list and push its first link up
       behind the header, where scrolling cannot reach it. */
    align-content: start;
    justify-items: start;
    gap: 0;
    padding: calc(var(--header-top) + var(--header-h) + 32px)
             max(20px, calc((100vw - 1180px) / 2 + 20px)) 48px;
  }
  [data-v-header="minimal"] .mobile-nav a {
    font-size: clamp(26px, 3vw, 38px);
    padding: 6px 0;
    border-bottom-width: 0;
    opacity: .82;
    transition: opacity .18s ease;
  }
  [data-v-header="minimal"] .mobile-nav a:hover { opacity: 1; }
  [data-v-header="minimal"] .mobile-nav__foot {
    display: flex;
    align-items: center;
    gap: 20px;
    margin-top: 32px;
  }
  [data-v-header="minimal"] .mobile-nav__foot .btn { width: auto; }
}

/* ================================================================ 360px ==== */
/* The narrowest screen anyone shows up on. Nothing may overflow it and every
   tap target stays at 44px. */

@media (max-width: 420px) {
  /* The strip truncates the status rather than pushing the number off the
     edge. Both stay tappable at the strip's full 44px. */
  [data-v-header="stack"] .header-utility { font-size: 12px; }
  [data-v-header="stack"] .header-utility__inner { gap: 8px; }
  [data-v-header="stack"] .header-utility__where { display: none; }
  [data-v-header="stack"] .header-utility__tel { padding-inline: 8px; }
  [data-v-header="stack"] .header-utility__social { display: none; }

  /* A truncated business name is worse than no monogram, and the centred
     header is a wordmark first. */
  [data-v-header="centred"] .brand { padding-inline: 52px; }
  [data-v-header="centred"] .brand__mark { display: none; }

  [data-v-header="rail"] .nav a { margin-inline: 8px; }
}

@media (prefers-reduced-motion: reduce) {
  [data-v-header="stack"] .header-utility,
  .phone-rail,
  .phone-rail svg,
  [data-v-header="minimal"] .mobile-nav a { transition: none; }
}

/* ---------------------------------------------------- services-features --- */
/* ==========================================================================
   Structural variants: services (list, rows, index) and features (strip,
   numbered). The first option of each set, services 'cards' and features
   'grid', is the page the sites already ship and is not touched here or in
   demo.css.

   WHY THESE USE THEIR OWN CLASS NAMES. demo.css restyles .service and
   .feature five more times, once per layout: editorial turns services into a
   numbered rule-separated list, minimal strips the cards, bold puts a two
   pixel border on everything. A variant reusing those class names would have
   to undo all of it, and an editorial page drawing the 'index' variant would
   have printed two sets of numerals. So each new variant emits its own block,
   inherits nothing, and only opts back into a layout's character where that
   is actually wanted (the few [data-layout] rules at the end of this file).

   Colours are tokens only. Never a literal, or the day somebody picks the
   dark layout it turns into white on white.
   ========================================================================== */

/* ==================================================== services: list ====== */
/* A price list. Name and price on one line, the description under it, a
   hairline between the rows and nothing else. Two columns once there is room
   for two readable measures, which is not at 560: half of a phone-plus screen
   is too narrow for a service name and a price on the same line. */

.svc-list {
  display: grid;
  column-gap: clamp(28px, 5vw, 64px);
}

.svc-list__item {
  padding: 15px 0 17px;
  border-bottom: 1px solid var(--line);
}
.svc-list__item:first-child { border-top: 1px solid var(--line); }

.svc-list__row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 2px 14px;
}

.svc-list__name {
  font-size: 1.14rem;
  letter-spacing: -0.012em;
  min-width: 0;
}

/* The minutes go between the name and the number, which is where a customer
   who has ever used Bokadirekt expects to find them. Small and quiet: it is a
   qualifier on the price, not a second price. Quiet stops at --ink-2, which
   is the palest of the text tokens that clears 4.5:1 on every site. */
.svc-list__time {
  flex: none;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.svc-list__price {
  /* Pushed right on its own rather than by a spacer, so a name long enough to
     wrap takes the price down with it instead of squeezing it. */
  margin-left: auto;
  flex: none;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.14rem;
  color: var(--accent-strong);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.svc-list__desc {
  margin-top: 4px;
  max-width: 54ch;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink-2);
}

/* Three services is a trade, not a salon, and three entries dealt into two
   columns leaves one on a row of its own with a hairline that stops halfway
   across the page. Under four it stays one column and takes the room it saved
   as air and size. */
.svc-list:not(:has(> :nth-child(4))) .svc-list__item { padding: 20px 0 22px; }
.svc-list:not(:has(> :nth-child(4))) .svc-list__name { font-size: clamp(1.2rem, 3vw, 1.4rem); }
.svc-list:not(:has(> :nth-child(4))) .svc-list__price { font-size: clamp(1.2rem, 3vw, 1.4rem); }
.svc-list:not(:has(> :nth-child(4))) .svc-list__desc { max-width: 62ch; font-size: 15.5px; }

/* ==================================================== services: rows ====== */
/* Few, big, full width. Zebra banding rather than a card each, because at
   this size a card outline reads as a box round the whole section. The band
   bleeds into the wrap padding so it runs edge to edge on a phone while the
   text stays on the same left margin as every other section. */

.svc-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 22px;
  padding: clamp(22px, 4vw, 36px) 20px;
  margin-inline: -20px;
  border-top: 1px solid var(--line);
}
.svc-row:last-child { border-bottom: 1px solid var(--line); }
.svc-row:nth-child(even) { background: var(--surface); }

.svc-row__icon {
  display: grid;
  place-items: center;
  flex: none;
  width: clamp(54px, 11vw, 74px);
  aspect-ratio: 1;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-ink);
}
.svc-row__icon svg {
  width: 54%;
  height: 54%;
  stroke-width: 1.5;
}

.svc-row__body {
  flex: 1 1 220px;
  min-width: 0;
}

.svc-row__name {
  font-size: clamp(1.25rem, 3.4vw, 1.8rem);
  letter-spacing: -0.02em;
}

.svc-row__desc {
  margin-top: 8px;
  max-width: 54ch;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--ink-2);
}

/* The price with the minutes under it, as one right hand block. On a narrow
   screen the block wraps to its own line and stays right aligned, which is why
   it is not simply the third cell of a grid. */
.svc-row__meta {
  margin-left: auto;
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}

/* Set in the text colour, like the menu prices and for the same two reasons.
   A right hand column of nine accent coloured figures is read as nine links
   before any of the service names are; and --accent-strong is a mix of the
   site's own accent, so on the darker brand palettes it lands as low as 2.95
   to 1 against the zebra band, which this size does not excuse. Size and
   weight are what make the number findable here. */
.svc-row__price {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(1.1rem, 2.6vw, 1.45rem);
  line-height: 1.15;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.svc-row__time {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Six or more of these is a very long page, so the same design gets quieter
   rather than turning into something else. Browsers without :has get the
   generous version at any count, which is long but never broken. */
.svc-rows:has(> :nth-child(6)) .svc-row { padding-block: clamp(16px, 2.6vw, 24px); }
.svc-rows:has(> :nth-child(6)) .svc-row__icon { width: clamp(46px, 8vw, 56px); }
.svc-rows:has(> :nth-child(6)) .svc-row__name { font-size: clamp(1.15rem, 2.6vw, 1.4rem); }
.svc-rows:has(> :nth-child(6)) .svc-row__desc { margin-top: 5px; font-size: 15px; }

/* =================================================== services: index ====== */
/* The editorial index: 01 02 03 down the left, the name in display type, the
   description held to a narrow measure beside it. The numeral is small and
   tracked out, not a poster numeral, because the name is the loud thing here. */

.svc-index__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: clamp(14px, 3vw, 26px);
  padding-block: clamp(20px, 3.4vw, 30px);
  border-top: 1px solid var(--line);
}
.svc-index__item:last-child { border-bottom: 1px solid var(--line); }

.svc-index__num {
  grid-column: 1;
  /* Spans both rows so the numeral hangs beside the whole entry. An item with
     no description simply leaves the second row at zero height. */
  grid-row: 1 / span 2;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.9;
  letter-spacing: .06em;
  color: var(--accent-strong);
  font-variant-numeric: tabular-nums;
}

.svc-index__head {
  grid-column: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}

.svc-index__name {
  font-size: clamp(1.3rem, 4vw, 1.75rem);
  font-weight: 600;
  letter-spacing: -0.02em;
}

/* Price and minutes on one line under the name, the way a barber's card sets
   them: the number first, then how long you are in the chair for it. */
.svc-index__meta {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 2px 10px;
}

.svc-index__price {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.12rem;
  color: var(--accent-strong);
  font-variant-numeric: tabular-nums;
}

.svc-index__time {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
/* Only between the two, never in front of a lone duration. */
.svc-index__price + .svc-index__time::before {
  content: '\00b7';
  margin-right: 10px;
}

.svc-index__desc {
  grid-column: 2;
  margin-top: 10px;
  max-width: 44ch;
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink-2);
}

/* Three entries in an index looks like the start of a page rather than a
   section, so at that count it gets more air and a larger name. */
.svc-index:not(:has(> :nth-child(4))) .svc-index__item { padding-block: clamp(26px, 4.4vw, 40px); }
.svc-index:not(:has(> :nth-child(4))) .svc-index__name { font-size: clamp(1.45rem, 4.6vw, 2.1rem); }

/* Seven or more and it becomes a directory, so it tightens. */
.svc-index:has(> :nth-child(7)) .svc-index__item { padding-block: clamp(14px, 2.4vw, 20px); }
.svc-index:has(> :nth-child(7)) .svc-index__name { font-size: clamp(1.15rem, 3vw, 1.4rem); }
.svc-index:has(> :nth-child(7)) .svc-index__desc { margin-top: 6px; }

/* ==================================================== features: strip ===== */
/* One band of facts between two heavier sections. No cards, no chips behind
   the icons, hairlines doing all of the separating. */

.feat-strip {
  display: grid;
  border-block: 1px solid var(--line);
}

.feat-strip__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 12px;
  padding: 16px 0;
}
.feat-strip__item + .feat-strip__item { border-top: 1px solid var(--line); }

.feat-strip__icon {
  grid-column: 1;
  grid-row: 1 / span 2;
  color: var(--accent-strong);
  padding-top: 2px;
}
.feat-strip__icon svg { width: 19px; height: 19px; }

.feat-strip__title {
  grid-column: 2;
  font-size: 0.97rem;
  letter-spacing: -0.01em;
}

.feat-strip__body {
  grid-column: 2;
  margin-top: 3px;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--ink-2);
}

/* ================================================= features: numbered ===== */
/* Large numerals, a rule over each, the fact underneath. No icon is drawn:
   the template does not emit one for this variant even though the document
   still carries it. Separation is by top rule only, never a side rule, so the
   grid can wrap at any item count without a hairline stranded mid row. */

.feat-num {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: clamp(22px, 3vw, 32px) clamp(24px, 3vw, 40px);
}

.feat-num__item {
  border-top: 1px solid var(--line);
  padding-top: 13px;
}

.feat-num__n {
  display: block;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(2rem, 5.5vw, 2.8rem);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--accent-strong);
  font-variant-numeric: tabular-nums;
  margin-bottom: 12px;
}

.feat-num__title {
  font-size: 1.02rem;
  letter-spacing: -0.01em;
}

.feat-num__body {
  margin-top: 5px;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink-2);
}

/* ================================================= features: the count ==== */
/*
   A fix to the grid every site starts with, not a preference.

   The card grid was pinned at four columns from 860 up, and the documents do
   not carry four facts. Thirteen of them carry three, which drew three cards
   and then a quarter of a row of nothing, and five carry five, which drew a
   full row and one card marooned under it. That is the section reading as
   broken rather than as designed, so the column count follows the item count
   instead of the other way round.

   Five is the one figure with no rectangle in it. It runs three then two over
   a six column grid, the two set wider, which is the arrangement that squares
   up and the one a person would have drawn.

   The header sits closer to its list here than a section head normally does:
   this band is the quiet one between two heavy sections and its heading should
   not carry the same weight as theirs.
*/

.section-head--compact { margin-bottom: clamp(24px, 3vw, 32px); }

@media (min-width: 860px) {
  .features { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  /* Two facts across half the page each, rather than half the page empty. */
  .features:not(:has(> :nth-child(3))) { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Four tiles evenly on four, and so does eight. Seven has no rectangle
     either, and four columns leaves it one gap at the end rather than two. */
  .features:has(> :nth-child(4)):not(:has(> :nth-child(5))),
  .features:has(> :nth-child(7)) { grid-template-columns: repeat(4, minmax(0, 1fr)); }

  /* The four across card measures 26 characters if you measure the text block,
     and that box is not the line: the icon already sits above the words at
     this width, and align-items leaves the block at the width of its own
     longest line rather than the card's. Stretching it changes no line break
     in either document that carries four facts, so nothing here does. */

  .features:has(> :nth-child(5)):not(:has(> :nth-child(6))) {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
  .features:has(> :nth-child(5)):not(:has(> :nth-child(6))) > .feature { grid-column: span 2; }
  .features:has(> :nth-child(5)):not(:has(> :nth-child(6))) > .feature:nth-child(n + 4) { grid-column: span 3; }

  /* The numbered variant has the same arithmetic problem from a different
     direction: its auto fit lands on four columns at 252px, which strands the
     fifth item under a full row and runs the body at 34 characters. Three
     columns is six in two clean rows, five as three then two, and a measure
     half as long again. */
  .feat-num:has(> :nth-child(5)):not(:has(> :nth-child(7))) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* =============================================================== 560px ==== */

@media (min-width: 560px) {
  /* Two columns of facts. The hairlines are placed by position, not by
     :not(:first-child), because a wrapped row must not carry a side rule on
     its first item. The reset uses the same sibling selector it is undoing,
     or it loses to it on specificity and every item keeps a top rule. */
  .feat-strip__item { padding: 20px 22px; }
  .feat-strip__item + .feat-strip__item { border-top: 0; }
  .feat-strip__item:nth-child(odd) { padding-left: 0; }
  .feat-strip__item:nth-child(even) { padding-right: 0; border-left: 1px solid var(--line); }
  .feat-strip__item:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .feat-strip { grid-template-columns: 1fr 1fr; }
}

/* =============================================================== 860px ==== */

@media (min-width: 860px) {
  /* Two price lists side by side, from four items up. Rows stretch to the
     height of the tallest item in the row, so the hairlines line up across the
     two columns. Under four it stays one column, or the last item sits alone
     beside an empty cell. */
  .svc-list:has(> :nth-child(4)) { grid-template-columns: 1fr 1fr; }
  .svc-list:has(> :nth-child(4)) > .svc-list__item:nth-child(2) { border-top: 1px solid var(--line); }
  .svc-list__name { font-size: 1.18rem; }

  /* The index gets its third column: name left, description in a narrow
     measure beside it. The block is held to a measure rather than run to the
     full wrap, or the description ends up marooned at the right edge with a
     lake of white between it and the name it belongs to. */
  .svc-index { max-width: 62rem; }
  .svc-index__item {
    grid-template-columns: clamp(52px, 5.5vw, 78px) minmax(0, 1fr) minmax(0, 25rem);
    align-items: start;
  }
  .svc-index__num { grid-row: 1; }
  .svc-index__desc {
    grid-column: 3;
    grid-row: 1;
    margin-top: 0;
    max-width: none;
  }

  /* One row of facts, all of them, separated by side rules. Only up to five:
     beyond that each column is too narrow to read and the two column form
     from 560 is left in place. */
  .feat-strip:not(:has(> :nth-child(6))) {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
  }
  .feat-strip:not(:has(> :nth-child(6))) .feat-strip__item {
    padding: 22px clamp(16px, 2vw, 26px);
    border-top: 0;
    border-left: 1px solid var(--line);
  }
  .feat-strip:not(:has(> :nth-child(6))) .feat-strip__item:first-child {
    padding-left: 0;
    border-left: 0;
  }
  .feat-strip:not(:has(> :nth-child(6))) .feat-strip__item:last-child { padding-right: 0; }
}

/* ============================================================== 1080px ==== */

@media (min-width: 1080px) {
  .svc-list { column-gap: 72px; }
  .svc-row { gap: 18px 32px; }
  .feat-num { gap: 34px 44px; }
}

/* ============================================================== layouts === */
/* The variants are layout neutral by design. These are the few places where
   a layout's own character has to reach them, matching what demo.css already
   does to the cards and the card grid. */

/* ---------------------------------------------------- reviews-gallery --- */
/* ==========================================================================
   Structural variants: reviews and gallery
   --------------------------------------------------------------------------
   Implements  reviews  quote, marquee, column
               gallery  masonry, filmstrip, feature

   The first option of each list (reviews "cards", gallery "grid") is the
   design the sites ship with today and is not touched here, so a site dealt
   that variant renders byte for byte what it rendered before.

   Two conventions in this file differ from demo.css and both are deliberate.
   Each variant keeps its own media queries next to it rather than in a shared
   breakpoint block at the end, because a variant is only ever read as a whole.
   And selectors carry both the data attribute and the block class, for example
   [data-v-gallery="filmstrip"] .gallery.gallery--strip, so they outrank the
   per layout rules in demo.css ([data-layout="minimal"] .gallery and friends)
   on specificity rather than on which file happens to be concatenated last.
   ========================================================================== */

/* The distance from the edge of the content column to the edge of the window.
   A strip that runs past both edges of the page uses it twice: once negative
   to escape the column, once positive so its first item still lines up with
   the heading above it. Same expression the split hero uses. */
.marquee,
.gallery-strip,
.gallery--pair { --bleed: max(20px, calc((100vw - 1180px) / 2 + 20px)); }

/* ===================================================== reviews: quote ===== */
/* One review set as display type. The others keep their score and their name
   on a line each, so the section still shows how many people were asked. */

[data-v-reviews="quote"] .review-quote {
  max-width: 900px;
  margin: 0;
}

.review-quote__mark {
  display: block;
  font-family: var(--font-heading);
  font-size: clamp(3.2rem, 10vw, 5.4rem);
  font-weight: var(--heading-weight-strong);
  line-height: .62;
  /* Ornament, not text. It sits below the contrast floor on purpose so it
     reads as a mark on the page rather than as something to be read. */
  color: var(--accent);
  opacity: .5;
}

/* The score sits under the name in the caption now, not on its own line above
   the quote, so it is small and it belongs to the person rather than to the
   section. */
[data-v-reviews="quote"] .review-quote__stars { margin: 6px 0 4px; }

[data-v-reviews="quote"] .review-quote__text {
  margin: 18px 0 0;
  font-family: var(--font-heading);
  font-size: clamp(1.3rem, 4.4vw, 2.35rem);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: var(--heading-track);
  color: var(--ink);
  text-wrap: balance;
}

[data-v-reviews="quote"] .review-quote__author {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  margin-top: clamp(24px, 3.5vw, 34px);
}

[data-v-reviews="quote"] .review-quote__when {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* The remaining reviews, reduced to a ledger. Hairlines rather than cards,
   because a row of cards under a pull quote competes with it. */
[data-v-reviews="quote"] .review-lines {
  max-width: 900px;
  margin-top: clamp(30px, 4.5vw, 48px);
  border-top: 1px solid var(--line);
}

/* A row used to be a score and a name. It now carries the review itself:
   the pull quote above is one person, and dropping what everybody else wrote
   turned the section into a display-size compliment over a row of stars with
   the words taken out. See LEGAL.md. */
[data-v-reviews="quote"] .review-line {
  padding: 16px 2px;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
}

[data-v-reviews="quote"] .review-line__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 14px;
}

[data-v-reviews="quote"] .review-line__name { font-weight: 650; }

[data-v-reviews="quote"] .review-line__when {
  margin-left: auto;
  font-size: 14px;
  color: var(--ink-2);
}

/* Quieter than the pull quote, and never shorter than what was written. */
[data-v-reviews="quote"] .review-line__text {
  margin: 7px 0 0;
  max-width: 74ch;
  line-height: 1.6;
  color: var(--ink-2);
}

/* Nothing here scrolls sideways, so the swipe hint would be a lie. */
[data-v-reviews="quote"] .reviews-hint { display: none; }

@media (min-width: 860px) {
  [data-v-reviews="quote"] .review-quote__mark { font-size: 6rem; }
  [data-v-reviews="quote"] .review-line { padding: 17px 2px; font-size: 15.5px; }
}

/* =================================================== reviews: marquee ===== */
/* One strip that scrolls itself, past both edges of the page. The cards are
   the shipped review cards; only the container is new. */

[data-v-reviews="marquee"] .marquee {
  position: relative;
  margin-inline: calc(-1 * var(--bleed));
  padding-block: 4px;
  overflow: hidden;
  /* Fades the two ends into the band rather than cutting them off square, so
     the strip reads as continuous. No fallback needed: a browser without mask
     support simply gets hard ends. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);
}

[data-v-reviews="marquee"] .marquee:focus-visible { outline-offset: -3px; }

[data-v-reviews="marquee"] .marquee__track {
  display: flex;
  width: max-content;
  will-change: transform;
  animation: cai-marquee var(--marquee-time, 30s) linear infinite;
}

/* Both of these are required, not decoration. Hover so a reader can stop the
   strip to finish a review, focus-within so a keyboard user is not carried
   away from whatever they just focused. */
[data-v-reviews="marquee"] .marquee:hover .marquee__track,
[data-v-reviews="marquee"] .marquee:focus-within .marquee__track { animation-play-state: paused; }

/* The gutter is a margin rather than a gap because the loop only lands
   seamlessly when every card occupies exactly the same width including its
   gutter. With gap, the track is one gutter short of a whole number of cards
   and the strip jumps once per lap. */
[data-v-reviews="marquee"] .marquee .review {
  flex: 0 0 min(78vw, 340px);
  margin-right: 14px;
}

@keyframes cai-marquee {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(var(--marquee-shift, -50%), 0, 0); }
}

/* Nothing to swipe while the strip is moving by itself. */
[data-v-reviews="marquee"] .reviews-hint { display: none; }

/* The strip is decoration that moves on its own, which is exactly what this
   query exists to switch off. It becomes a plain row the reader scrolls
   themselves, and the duplicate cards go away with the loop that needed them
   so nobody scrolls through the same three reviews four times. The hint comes
   back, because now there really is something to swipe. */
@media (prefers-reduced-motion: reduce) {
  [data-v-reviews="marquee"] .marquee {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--bleed);
    padding-inline: var(--bleed);
    /* A scrollbar the reader can see. Once the strip has stopped moving the
       only thing saying there is more to the right is the bar and the hint,
       so unlike the moving version this one is styled to be noticed. */
    scrollbar-width: thin;
    scrollbar-color: var(--accent) var(--line);
    -webkit-mask-image: none;
            mask-image: none;
  }
  [data-v-reviews="marquee"] .marquee::-webkit-scrollbar { height: 6px; }
  [data-v-reviews="marquee"] .marquee::-webkit-scrollbar-track { background: var(--line); border-radius: 99px; }
  [data-v-reviews="marquee"] .marquee::-webkit-scrollbar-thumb { background: var(--accent); border-radius: 99px; }
  [data-v-reviews="marquee"] .marquee__track {
    width: max-content;
    animation: none;
    transform: none;
    will-change: auto;
  }
  [data-v-reviews="marquee"] .marquee .review[aria-hidden="true"] { display: none; }
  [data-v-reviews="marquee"] .reviews-hint { display: block; }
}

/* Three cards at 340px do not fill a desktop window, so on a wide screen the
   stopped strip was a scroller with nothing to scroll, a tab stop that went
   nowhere, and a hint that said swipe under a row that could not move. Above
   this width it stops pretending to be a strip and becomes the card grid the
   other variants use, which is the honest shape for what is left. */
@media (prefers-reduced-motion: reduce) and (min-width: 860px) {
  [data-v-reviews="marquee"] .marquee {
    margin-inline: 0;
    padding-inline: 0;
    overflow: visible;
  }
  [data-v-reviews="marquee"] .marquee__track {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
    gap: 16px;
    width: auto;
  }
  [data-v-reviews="marquee"] .marquee .review {
    flex: none;
    margin-right: 0;
  }
  [data-v-reviews="marquee"] .reviews-hint { display: none; }
}

/* ==================================================== reviews: column ===== */
/* A single narrow column, hairline ruled, no cards at all. The quiet one. */

[data-v-reviews="column"] .reviews {
  display: block;
  max-width: 640px;
  margin-inline: 0;
  padding: 0;
  overflow: visible;
  border-top: 1px solid var(--line);
}

[data-v-reviews="column"] .reviews .review {
  display: block;
  flex: none;
  padding: clamp(22px, 4vw, 30px) 0;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
}

[data-v-reviews="column"] .reviews .review__stars { margin: 5px 0 3px; }

/* The quiet variant earns its quiet from measure and leading, not from small
   type, so the review is set a step above the card variant rather than below
   it. Held to 640px it stays inside a comfortable line length at that size. */
[data-v-reviews="column"] .reviews .review__text {
  font-size: 1.12rem;
  line-height: 1.7;
  color: var(--ink);
}

[data-v-reviews="column"] .reviews .review__author {
  justify-content: flex-start;
  gap: 10px;
  margin-top: 16px;
  padding-top: 0;
  border-top: 0;
}

/* The initial in a circle is the loudest thing on a card and this variant is
   not a card. It is decorative and already hidden from assistive technology,
   so dropping it costs nothing. */
[data-v-reviews="column"] .reviews .review__avatar { display: none; }

[data-v-reviews="column"] .wrap .rating-summary {
  max-width: 640px;
  padding: 0 0 22px;
  background: none;
  border: 0;
  border-radius: 0;
}

[data-v-reviews="column"] .reviews-hint { display: none; }

/* ==================================================== gallery: masonry ==== */
/* Columns of unequal height. Multi column rather than a grid of row spans:
   the reading order a screen reader follows is the source order, which is the
   order the eye follows down one column and on to the next, and no row of
   images can leave a hole under a short one.

   The heights are set here rather than taken from the files because the
   photographs a generated site gets are usually all the same shape, and three
   identical rectangles in three columns is the grid we already have. */

[data-v-gallery="masonry"] .gallery {
  display: block;
  columns: 2;
  column-gap: 10px;
}

[data-v-gallery="masonry"] .gallery figure {
  position: relative;
  margin: 0 0 10px;
  break-inside: avoid;
  aspect-ratio: 1 / 1;
}

[data-v-gallery="masonry"] .gallery figure:nth-child(3n+1) { aspect-ratio: 4 / 5; }
[data-v-gallery="masonry"] .gallery figure:nth-child(3n+3) { aspect-ratio: 5 / 4; }

@media (min-width: 860px) {
  [data-v-gallery="masonry"] .gallery { columns: 3; column-gap: 14px; }
  [data-v-gallery="masonry"] .gallery figure { margin-bottom: 14px; }

  /* Most generated sites have two or three photographs. Three columns would
     leave one of them empty, or put one picture in each and call a row a
     wall, so the count class the template already prints decides. */
  [data-v-gallery="masonry"] .gallery--2,
  [data-v-gallery="masonry"] .gallery--3 { columns: 2; }
}

/* ================================================== gallery: filmstrip ==== */
/* One strip, edge to edge, snapped. Three things make it usable: the tab stop
   and label in the template, a scrollbar that is styled to be seen rather
   than hidden, and the hint under it. */

[data-v-gallery="filmstrip"] .gallery-strip {
  margin-inline: calc(-1 * var(--bleed));
  padding: 0 var(--bleed) 14px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--bleed);
  scrollbar-width: thin;
  scrollbar-color: var(--accent) var(--panel-line);
}

/* The strip runs to both window edges, so an outline drawn outside it would
   be drawn off screen. */
[data-v-gallery="filmstrip"] .gallery-strip:focus-visible { outline-offset: -3px; }

/* The ring on a band that stayed dark.

   The site-wide focus ring is the accent, which is chosen to sit on paper. On
   the dark gallery ground it can fall under the 3:1 a focus indicator owes a
   keyboard: measured across the demos that keep these bands dark it runs from
   7:1 down to 1.8:1, and nine of the twenty three are under three. The hero
   already answers this with --accent-on-dark, the accent lifted towards white,
   which measures 7:1 or better on every one of them.

   The two layouts named here redraw .section--dark as a light band, so they
   keep the ring they have; a layout added later gets the safe branch. Split
   was the third name and has been taken out of it: its dark bands are dark
   again, so it owes the keyboard the same lifted accent every other dark band
   owes it. */
body:not([data-layout="editorial"], [data-layout="minimal"])
  .section--dark .gallery-strip:focus-visible {
  outline-color: var(--accent-on-dark);
}

[data-v-gallery="filmstrip"] .gallery-strip::-webkit-scrollbar { height: 6px; }
[data-v-gallery="filmstrip"] .gallery-strip::-webkit-scrollbar-track {
  background: var(--panel-line);
  border-radius: 99px;
}
[data-v-gallery="filmstrip"] .gallery-strip::-webkit-scrollbar-thumb {
  background: var(--accent);
  border-radius: 99px;
}

[data-v-gallery="filmstrip"] .gallery.gallery--strip {
  display: flex;
  gap: 12px;
  width: max-content;
  padding: 0;
}

[data-v-gallery="filmstrip"] .gallery--strip figure {
  position: relative;
  flex: 0 0 min(72vw, 520px);
  margin: 0;
  aspect-ratio: 4 / 3;
  scroll-snap-align: start;
}

.gallery-hint {
  margin-top: 14px;
  font-size: 14px;
  color: var(--on-deep-2, var(--ink-2));
}

/* ==================================================== gallery: feature ==== */
/* One photograph carrying the section and the rest as a band beneath it. The
   band is a fixed height with columns that fill the width, so one leftover
   photograph reads as a deliberate wide strip instead of a second hero, and
   five of them wrap onto a second row instead of turning into slivers. */

[data-v-gallery="feature"] .gallery.gallery--feature {
  display: block;
}

[data-v-gallery="feature"] .gallery__lead {
  margin: 0 0 10px;
  aspect-ratio: 4 / 3;
}

[data-v-gallery="feature"] .gallery__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  grid-auto-rows: clamp(130px, 26vw, 260px);
  gap: 10px;
}

[data-v-gallery="feature"] .gallery__row figure { margin: 0; }

/* The band is a grid, and so was the wall this variant replaces, so the rule
   that makes the first tile of that wall two rows tall reaches the first
   photograph in here as well and gives it double the height of its
   neighbours. It has to be put back. */
[data-v-gallery="feature"] .gallery__row figure:first-child {
  grid-row: auto;
  grid-column: auto;
}

@media (min-width: 620px) {
  [data-v-gallery="feature"] .gallery__lead { aspect-ratio: 16 / 9; }
}

@media (min-width: 860px) {
  [data-v-gallery="feature"] .gallery__lead { margin-bottom: 14px; aspect-ratio: 21 / 9; }
  [data-v-gallery="feature"] .gallery__row { gap: 14px; }
}

/* ===================================================== gallery: the pair == */
/* What a gallery does when it only has two photographs, which is most of them.

   None of the four variants had an answer. A two tile grid is a wall with the
   rest of the wall missing, a two card strip never overflows so it cannot be
   swiped while still saying swipe, and the feature lead plus one leftover
   turns the leftover into a letterbox offcut. All three read as unfinished
   because all three are shapes built for more pictures than exist.

   So the template hands one or two photographs to this instead, whatever
   variant the site was dealt, and the answer is the one every gallery wall in
   the world uses for a pair: hang them large, at matching height, with a
   single gap between them. Run to the window edges they are roughly twice the
   area they had in the column, which is the difference between two pictures
   the business is showing you and two pictures filling a slot.

   It sits after the other three because it has to beat them on the cascade
   without reaching for a specificity fight it cannot lose later.

   Flex rather than grid, and that is the whole reason this block is short.
   The wall it replaces spans its first tile across two columns, the masonry
   variant runs .gallery as a multi column block, and both of those are keyed
   to selectors that reach a figure in here as easily as anywhere else. In a
   flex container a column span is simply not a property that exists, so the
   pair inherits none of it and needs no rule undoing any of it. */

[data-v-gallery] .gallery.gallery--pair {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-inline: calc(-1 * var(--bleed));
}

/* Both classes on the container, so this ties the masonry variant's
   nth-child heights on specificity and beats them on order. Without it a site
   dealt masonry drew its pair at the 4 by 5 portrait that variant gives every
   first figure, and the second photograph stretched to match it: two columns
   almost 800px tall where the rule below asks for 420. */
[data-v-gallery] .gallery.gallery--pair figure {
  position: relative;
  flex: 1 1 100%;
  margin: 0;
  aspect-ratio: 4 / 3;
  /* A rounded corner against the window edge reads as a mistake rather than
     as a radius, so a bled photograph squares off. */
  border-radius: 0;
}

@media (min-width: 740px) {
  [data-v-gallery] .gallery.gallery--pair { gap: 10px; }
  /* Equal halves of whatever the window is, and the whole of it when there is
     only one photograph. Wider than tall once they are side by side: the
     source photographs are landscape, and cropping a landscape into a 4 by 3
     box throws away the ends of the room. */
  [data-v-gallery] .gallery.gallery--pair figure {
    flex: 1 1 0;
    aspect-ratio: 3 / 2;
  }
}

@media (min-width: 1180px) {
  [data-v-gallery] .gallery.gallery--pair { gap: 12px; }
}

/* ================================================== gallery: the photos === */
/* Three of the four variants size the frame and let the photograph fill it,
   which means pinning the image to the frame rather than giving it a ratio of
   its own. Done this way the ratio rules in demo.css, including the ones on
   the first tile, cannot reach past it, and the intrinsic width and height on
   the tag survive untouched, so nothing on the page moves while a photo
   loads. Every :first-child selector below is here to outrank one of those. */

[data-v-gallery="masonry"] .gallery figure img,
[data-v-gallery="masonry"] .gallery figure:first-child img,
[data-v-gallery="filmstrip"] .gallery figure img,
[data-v-gallery="filmstrip"] .gallery figure:first-child img,
[data-v-gallery="feature"] .gallery figure img,
[data-v-gallery="feature"] .gallery figure:first-child img,
[data-v-gallery] .gallery.gallery--pair figure img,
[data-v-gallery] .gallery.gallery--pair figure:first-child img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  object-fit: cover;
}

/* ---------------------------------------------------- about-steps-faq --- */
/* ==========================================================================
   Structural variants: about, steps, faq
   --------------------------------------------------------------------------
   Implements, keyed on the data attributes <body> already carries:

     about  overlay   full bleed photograph, the text on a panel over it
            stat      no photograph, a band of real numbers over the prose
     steps  timeline  one vertical line with the steps hung off it
            numbered  very large numerals, two columns, no line
     faq    open      every answer showing, question as a heading
            twocol    the same in two columns on a wide screen

   The first option of each part (split, row, accordion) is the page as it
   shipped and is not touched here.

   Same rules as demo.css: every colour a theme token, the one exception being
   white on the dark panel, which is how --on-deep is written too, and nothing
   that assumes --radius is bigger than 0. This file is concatenated
   after demo.css, so an equally specific rule here wins on order; where a
   layout block has to be beaten, the selector carries one more class on
   purpose rather than an !important.
   ========================================================================== */

/* ================================================== about: overlay ======= */
/*
   A photograph nobody vetted, with text on top of it.

   The fetcher returns whatever the business happens to have, bright or dark,
   so the panel under the words does not try to be clever about it: it is the
   site's own primary colour at an alpha high enough that the composite is the
   primary colour for contrast purposes, which is the same ground the hero and
   the dark bands already put white text on. The photograph reads through the
   panel as texture, and reads properly everywhere the panel is not.
*/

.about-overlay {
  --panel-ink: #fff;
  --panel-ink-2: rgb(255 255 255 / .88);
  --panel-ground: linear-gradient(150deg, rgb(var(--primary-rgb) / .97), rgb(var(--primary-rgb) / .93));
  --panel-edge: rgb(255 255 255 / .14);

  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: center;
  min-height: clamp(420px, 62vh, 680px);
  /* More air above than below on a phone, so the photograph reads as a
     photograph the panel is sitting on rather than as a border around it. */
  padding-block: clamp(96px, 13vw, 128px) clamp(72px, 12vw, 128px);
  background: var(--deep);
}

/*
   Two layouts deliberately have no dark bands anywhere: editorial recolours
   the gallery and contact sections light and minimal drops them entirely.
   Handing those pages one dark slab in the middle would undo that, so there
   the panel is the card colour and the ink scale is the page's own.

   Split used to be the third name here. It is not one any more: it keeps the
   dark gallery and contact bands, because a paper page whose only ground
   change was 1.04:1 had no structure left at all, and it can no longer be
   dealt about=overlay, so this rule would never have fired for it again.
*/
[data-layout="editorial"] .about-overlay {
  --panel-ink: var(--ink);
  --panel-ink-2: var(--ink-2);
  --panel-ground: var(--card);
  --panel-edge: var(--line);
}

.about-overlay__media {
  position: absolute;
  inset: 0;
  z-index: -2;
}
.about-overlay__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Only there so the exposed part of the photograph belongs to the same page
   as the panel. The panel does its own contrast, not this. */
.about-overlay__wash {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(to right, rgb(var(--primary-rgb) / .78) 0%, rgb(var(--primary-rgb) / .4) 60%, rgb(var(--primary-rgb) / .28) 100%),
    linear-gradient(to bottom, rgb(var(--primary-rgb) / .26), rgb(var(--primary-rgb) / .48));
}

.about-overlay__panel {
  position: relative;
  max-width: 620px;
  padding: clamp(26px, 5.4vw, 46px);
  border: 1px solid var(--panel-edge);
  border-radius: var(--radius);
  background: var(--panel-ground);
  color: var(--panel-ink);
  box-shadow: 0 40px 70px -50px rgb(var(--primary-rgb) / .9);
}

.about-overlay .about__body h2 { color: var(--panel-ink); }
.about-overlay .about__body p { color: var(--panel-ink-2); }

/* The eyebrow is a <p>, and on this site the paragraph rules win over
   .eyebrow, so it takes the body colour whether or not anyone says so. Say so,
   and pin it to the panel's own ink: both accent mixes are chosen to sit on
   the page ground, and neither clears 4.5:1 on a panel this dark. */
.about-overlay .about__body p.eyebrow { color: var(--panel-ink-2); }

@media (min-width: 860px) {
  .about-overlay__panel { max-width: 56%; }
}

@media (min-width: 1080px) {
  .about-overlay__panel { max-width: 50%; }
}

/* ===================================================== about: stat ======= */
/*
   The version with no photograph. It has to hold the section on type alone,
   so the numbers are set as large as the heading and given the full measure,
   with the prose kept to a readable column underneath.

   Which numbers appear is the template's decision, and it only ever draws
   figures the content document really contains.
*/

.about--stat { display: block; max-width: 940px; }

.about-stats {
  display: grid;
  margin-block: clamp(30px, 4.5vw, 44px);
  border-bottom: 1px solid var(--line);
}

.about-stat {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 18px;
  padding-block: clamp(16px, 2.8vw, 22px);
  border-top: 1px solid var(--line);
}

.about-stat__value {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(2.1rem, 6.4vw, 3.1rem);
  line-height: 1;
  letter-spacing: var(--heading-track);
  color: var(--ink);
  white-space: nowrap;
  font-variant-numeric: lining-nums tabular-nums;
}

.about-stat__label {
  text-align: right;
  font-size: 13.5px;
  font-weight: 650;
  line-height: 1.4;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* The prose reads as a continuation of the heading, so its first paragraph is
   always the lead. The template says which paragraph that is; the treatment
   itself is shared with the other two shapes, further down. */
.about__body--prose { max-width: 66ch; }

@media (min-width: 720px) {
  /* One row whatever the count is, two or three, each column an equal share.
     Auto flow rather than a fixed count so neither ever wraps to a stray. */
  .about-stats {
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    border-top: 1px solid var(--line);
    border-bottom: 0;
  }
  .about-stat {
    display: block;
    padding: clamp(22px, 3vw, 30px) clamp(20px, 3vw, 32px) clamp(22px, 3vw, 30px) 0;
    border-top: 0;
  }
  .about-stat + .about-stat {
    padding-left: clamp(20px, 3vw, 32px);
    border-left: 1px solid var(--line);
  }
  .about-stat__label {
    display: block;
    margin-top: 12px;
    text-align: left;
  }
}

/* ============================================== about: the shape it starts in */
/*
   Two corrections to the split, which is what forty of the forty-five sites
   are dealt. Both are fixes rather than preferences, so they sit on the base.

   THE LEAD. Six of these documents run to three or four paragraphs and the
   rest run to two. At one size a four paragraph column is a wall with no way
   into it, so the template marks the first paragraph from the third onward and
   it is set a step up and in full strength ink. The colour is inherited rather
   than named: the split takes the page's own ink, the overlay takes the white
   its panel is already using, and neither needs its own rule.

   NO PHOTOGRAPH. A document with no image was still handed the two column
   grid, so the prose sat in the left half and the right half was empty. Where
   there is no picture the text takes the width and is held to a measure
   instead, which is the only thing the second column was doing for it.
*/

.about__body p.about__lead {
  /* The floor matters as much as the ceiling. At the old one a phone drew the
     lead a third of a pixel larger than the paragraph under it, which is not a
     hierarchy, it is a rounding error. */
  font-size: clamp(1.18rem, 2.2vw, 1.34rem);
  line-height: 1.5;
  color: inherit;
}

@media (min-width: 860px) {
  /* The stat shape is excluded by name. It never has a photograph either, but
     it is holding a band of numbers at the full width and must keep it. */
  .about:not(.about--stat):not(:has(.about__media)) {
    grid-template-columns: minmax(0, 1fr);
    max-width: 66ch;
  }
}

/* ============================================== steps: the shape it starts in */
/*
   What shipped was four equal cards across the page, and it had two faults
   that are not matters of taste.

   Six steps in a four column grid left two dead cells at the end of the second
   row, which reads as a section with items missing. And the body inside a
   275px card ran at 36 characters a line, well under the 45 that is the floor
   for prose anybody is expected to read.

   Both are fixed here rather than in the variants, because both are wrong on
   every site. The cards go with them: a process is a sequence, and four boxes
   of equal weight read as four unrelated facts. What is left is one rule per
   row with the numbers sitting on it, which is how a process has been set
   since long before any of this.

   Below 860 the steps are still a stack of cards, which is the right shape for
   a phone and the one measure was never a problem in.
*/

/* On a phone the disc and the body were sharing a 320px card, and the text was
   left running at 28 characters a line. The number goes above the title
   instead and the paragraph gets the whole width of the card. */
[data-v-steps="row"] .steps .step { flex-direction: column; gap: 14px; }

@media (min-width: 860px) {
  [data-v-steps="row"] .steps {
    /* The diameter of .step__num, so the disc can be pulled up onto the rule
       without either value being written twice. The timeline variant declares
       the same thing for the same reason. */
    --step-dot: 40px;
    /* Two up. At the 1180 wrap that is a 70 character measure, and four steps
       and six steps, which is all but two of these documents, both square up. */
    grid-template-columns: repeat(2, minmax(0, 1fr));
    /* No column gap, so the rule over a row runs unbroken across it. The
       padding inside each step does the separating instead. */
    gap: 0;
  }

  /* Three fills a row of three exactly. Five has no rectangle anywhere and
     reads better as three then two than as two, two and a stray. Six is left
     on two columns, where it is three clean rows at the wider measure rather
     than two cramped ones. */
  [data-v-steps="row"] .steps:has(> :nth-child(3)):not(:has(> :nth-child(4))),
  [data-v-steps="row"] .steps:has(> :nth-child(5)):not(:has(> :nth-child(6))) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  [data-v-steps="row"] .steps .step {
    align-items: stretch;
    gap: 16px;
    /* Nothing above the number: the disc is pulled up onto the rule instead,
       so the row reads as one line the steps hang off rather than as four
       separate beginnings. */
    padding: 0 clamp(24px, 3vw, 44px) clamp(30px, 3.6vw, 44px) 0;
    background: transparent;
    border: 0;
    border-top: 1px solid var(--line);
    border-radius: 0;
    box-shadow: none;
  }

  [data-v-steps="row"] .steps .step__num { margin-top: calc(var(--step-dot) / -2); }
  [data-v-steps="row"] .steps .step h3 { font-size: 1.12rem; }
  [data-v-steps="row"] .steps .step p { margin-top: 8px; }

}

/* ================================================== steps: timeline ====== */
/*
   One line down the page with the numbers sitting on it. The line is drawn per
   step rather than once behind the list, so it stops at the last number
   instead of running off into the padding.
*/

[data-v-steps="timeline"] .steps {
  /* The diameter of .step__num in demo.css. The line is placed off this, so
     the two have to be changed together or the line stops meeting the discs. */
  --step-dot: 40px;
  gap: 0;
  max-width: 760px;
  grid-template-columns: minmax(0, 1fr);
}

[data-v-steps="timeline"] .steps .step {
  position: relative;
  flex-direction: row;
  align-items: flex-start;
  gap: clamp(16px, 3vw, 24px);
  padding: 0 0 clamp(26px, 4vw, 40px);
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
[data-v-steps="timeline"] .steps .step:last-child { padding-bottom: 0; }

[data-v-steps="timeline"] .steps .step:not(:last-child)::before {
  content: '';
  position: absolute;
  top: calc(var(--step-dot) + 8px);
  bottom: 6px;
  left: calc(var(--step-dot) / 2 - 1px);
  width: 2px;
  background: var(--line);
}

/* The number is the only thing on the line, so it keeps its filled disc and
   the text block drops to meet its optical centre. */
[data-v-steps="timeline"] .steps .step > div { padding-top: 7px; }
[data-v-steps="timeline"] .steps .step h3 { font-size: 1.14rem; }

/* ================================================== steps: numbered ===== */
/*
   No line and no card. The numeral is the ornament, set at heading scale in
   the accent, and the pairs sit in two columns from the point the text still
   has a sensible measure beside it.
*/

[data-v-steps="numbered"] .steps {
  gap: clamp(24px, 4vw, 38px) clamp(30px, 5vw, 64px);
  grid-template-columns: minmax(0, 1fr);
}

[data-v-steps="numbered"] .steps .step {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: clamp(14px, 2.4vw, 22px);
  padding: clamp(18px, 2.6vw, 26px) 0 0;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
}

[data-v-steps="numbered"] .steps .step__num {
  display: block;
  width: auto;
  height: auto;
  border-radius: 0;
  background: none;
  /* --accent-strong rather than --accent: the numeral has to hold up on the
     tinted band even when the site's accent is a pale one. */
  color: var(--accent-strong);
  font-size: clamp(2.6rem, 7.5vw, 4.2rem);
  font-weight: var(--heading-weight-strong);
  line-height: .82;
  letter-spacing: -0.045em;
  font-variant-numeric: lining-nums tabular-nums;
}

[data-v-steps="numbered"] .steps .step h3 { font-size: 1.14rem; }

@media (min-width: 700px) {
  [data-v-steps="numbered"] .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Bold draws every edge on the page at two pixels in full ink. These two
   variants have no boxes left to thicken, so the rules take it instead. */
[data-layout="bold"][data-v-steps="numbered"] .steps .step,
[data-layout="bold"] .faq--plain .faq__row { border-top: 2px solid var(--ink); }

/* The rule that closes the list has to be the same rule as the ones above it,
   or bold ends a stack of heavy black lines on a pale hairline. */
[data-layout="bold"] .faq--plain { border-bottom: 2px solid var(--ink); }

/* ============================================= faq: open and twocol ====== */
/*
   No <details>, so nothing to open and nothing to script. The question is a
   real h3 under the section's h2, which is the order a crawler and a screen
   reader both want, and the whole thing prints as it stands.
*/

/* A rule over every row and none under the last one left the list looking cut
   off rather than finished, so the block closes itself. */
.faq--plain { display: grid; gap: 0; border-bottom: 1px solid var(--line); }

.faq__row {
  padding-block: clamp(20px, 3vw, 26px);
  border-top: 1px solid var(--line);
  break-inside: avoid;
}

/* Question and answer were within a tenth of each other in size, which on a
   page of eight of them is a wall with no shape. The question takes a real
   step up and the answer keeps the smaller body size, so a reader scanning
   for the one that applies to them can find it without reading the rest. */
.faq__q {
  font-size: clamp(1.14rem, 1.9vw, 1.24rem);
  font-weight: 650;
  line-height: 1.28;
}

.faq__a {
  margin-top: 10px;
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--ink-2);
  max-width: 66ch;
}

/* ==================================================== faq: accordion ===== */
/*
   The third shape had the same size fault as the other two and was left with
   it: a 16.2px summary over a 15.5px answer is a 1.04 step, which is not a
   hierarchy. It takes the size the open and twocol question takes, so a reader
   moving between two of these sites is reading one page in two shapes rather
   than two pages. Held a shade tighter at the top of the range, because a
   summary carries the chevron on the same line and a long question must not
   push it onto a second.
*/
.faq__item summary {
  font-size: clamp(1.1rem, 1.8vw, 1.18rem);
  line-height: 1.3;
}

/* The keyboard ring was drawn and then thrown away. The summary fills its card
   exactly, the card clips to its padding box to keep the open state inside the
   radius, and the shipped ring sits three pixels outside the summary, so every
   pixel of it landed in the clipped region: tabbing through a FAQ moved the
   focus with nothing on screen to say where it had gone. Turned inward, which
   is what the marquee and the filmstrip already do for the same reason. */
.faq__item summary:focus-visible { outline-offset: -3px; }

@media (min-width: 860px) {
  /* Two columns of answers need the whole measure, so the heading goes back
     above them instead of sitting in its own column beside them. */
  [data-v-faq="twocol"] .faq-grid { grid-template-columns: minmax(0, 1fr); gap: clamp(32px, 4vw, 48px); }
  [data-v-faq="twocol"] .faq { max-width: none; }

  .faq--twocol {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(36px, 5vw, 72px);
    align-items: start;
  }

  /* One rule cannot close two columns of different lengths. Under seven
     questions the shorter column ends 166px above the line drawn beneath the
     block, so its last answer hangs in the gap with nothing under it. Each
     column closes under its own last question instead: the bottom two children
     are one per column at every count, because the rows fill left then right.
     Bold takes the same weight here as it does on the rules above. */
  .faq--twocol { border-bottom: 0; }
  .faq--twocol .faq__row:nth-last-child(-n + 2) { border-bottom: 1px solid var(--line); }

  [data-layout="bold"] .faq--twocol { border-bottom: 0; }
  [data-layout="bold"] .faq--twocol .faq__row:nth-last-child(-n + 2) {
    border-bottom: 2px solid var(--ink);
  }
}

/* The heading beside a list of eight answers wants to travel with them, and it
   cannot: html and body both carry overflow-x: hidden so that no client site
   can ever scroll sideways, and an overflow other than visible on an ancestor
   is what turns position: sticky off. Nothing here tries it, rather than
   leaving a rule in the file that quietly does nothing. */

/* ---------------------------------------------------- contact-menu-booking --- */
/* ==========================================================================
   Structural variants: contact, menu, booking
   --------------------------------------------------------------------------
   Implements contact "centred" and "aside", menu "cards" and "ledger", and
   booking "panel" and "inline". The first option of each set (contact "split",
   menu "columns", booking "form") is the page the sites shipped with and has
   no rules here at all, which is the only way to be sure it did not move.

   These three sections carry the phone number, the price list and the form, so
   every rule below is written to fail towards the original rather than towards
   a broken one: an unsupported selector leaves the shipped layout standing.

   Colours come from the theme tokens, never a literal. Inside contact that
   includes --panel-line, which .section--dark sets and a layout that would
   rather have the band light redefines.
   ========================================================================== */

/* ======================================================= contact: centred ===
   One narrow column down the middle of the dark band. The details lead (the
   template emits them first for this variant) and the week sits beneath them,
   so the page answers "how do I reach you" before "when are you open".
   The panels lose their boxes: two bordered cards stacked in a 560px column
   read as a broken two-column layout rather than as one considered column. */

/* The heading centres itself: the template asks for .section-head--centre and
   .is-centred, both of which the base stylesheet already draws. A rule here on
   .section-head or .eyebrow would land on every section of the page, since the
   variant attribute sits on <body>. */

[data-v-contact="centred"] .contact {
  grid-template-columns: minmax(0, 1fr);
  max-width: 560px;
  margin-inline: auto;
  gap: 0;
  text-align: center;
}

[data-v-contact="centred"] .panel {
  padding: 0;
  background: none;
  border: 0;
}
[data-v-contact="centred"] .panel + .panel {
  margin-top: 38px;
  padding-top: 34px;
  border-top: 1px solid var(--panel-line);
}
[data-v-contact="centred"] .panel h3 { margin-bottom: 26px; }
/* The panel is a column flex container, so the open or closed pill stretches
   to its full width unless it is told to stop. */
[data-v-contact="centred"] .contact-status { align-self: center; }

/* Icon above the label rather than beside it: a left icon on a centred line
   drags the whole block off the axis of the column. */
[data-v-contact="centred"] .contact-line {
  flex-direction: column;
  align-items: center;
  gap: 9px;
}
[data-v-contact="centred"] .contact-line + .contact-line {
  margin-top: 26px;
  padding-top: 26px;
  border-top: 1px solid var(--panel-line);
}
[data-v-contact="centred"] .contact-line svg {
  width: 22px;
  height: 22px;
  margin-top: 0;
}
[data-v-contact="centred"] .contact-line dd {
  margin-top: 5px;
  font-size: 18px;
}

[data-v-contact="centred"] .contact-actions {
  margin-top: 32px;
  padding-top: 0;
}
@media (min-width: 560px) {
  [data-v-contact="centred"] .contact-actions { grid-template-columns: 1fr 1fr; }
}

/* The hours stay a two column reading: day on the left, time on the right.
   Centring them would turn a table into a poem. The negative inline margin
   lets the highlighted row bleed past the text edge so it reads as a marker
   on the column rather than as an indent. */
[data-v-contact="centred"] .hours { text-align: left; }
[data-v-contact="centred"] .hours__row {
  padding-inline: 12px;
  margin-inline: -12px;
}

[data-v-contact="centred"] .map {
  max-width: 720px;
  margin: 42px auto 0;
}

/* ========================================================= contact: aside ===
   The week is the main block and the details are a narrow rail beside it. The
   hours lose their box and become an editorial list with rules between the
   days, which is what gives the rail something to be raised against. */

[data-v-contact="aside"] .panel--hours {
  padding: 0;
  background: none;
  border: 0;
}
[data-v-contact="aside"] .panel--hours h3 { margin-bottom: 16px; }
/* Same as the centred column: without this the pill runs the width of the
   main block, which at this width is most of the page. */
[data-v-contact="aside"] .contact-status { align-self: flex-start; }

[data-v-contact="aside"] .hours { gap: 0; }
[data-v-contact="aside"] .hours__row {
  padding: 15px 12px;
  border-bottom: 1px solid var(--panel-line);
  border-radius: 0;
  font-size: 16px;
}
[data-v-contact="aside"] .hours__row:last-child { border-bottom: 0; }
[data-v-contact="aside"] .hours__row.is-today { border-radius: var(--radius); }

[data-v-contact="aside"] .panel--find {
  background: rgb(var(--accent-rgb) / .1);
  border-color: rgb(var(--accent-rgb) / .32);
}

[data-v-contact="aside"] .map { margin-top: 44px; }
[data-v-contact="aside"] .map iframe { aspect-ratio: 21 / 7; }

@media (min-width: 860px) {
  [data-v-contact="aside"] .contact {
    grid-template-columns: minmax(0, 1fr) minmax(0, 330px);
    gap: 46px;
    /* Not stretch: a rail the height of the row has no room left to stick in. */
    align-items: start;
  }

  /* Clears the fixed header, which is 84px tall once the page is scrolled. */
  [data-v-contact="aside"] .panel--find {
    position: sticky;
    top: 104px;
  }

  /* A document with no opening hours leaves one panel behind, and a 330px
     column with nothing beside it is not a design. */
  [data-v-contact="aside"] .contact > .panel:only-child {
    grid-column: 1 / -1;
    max-width: 520px;
  }
}

/* ========================================================= menu: columns ===
   The variant every menu shipped with. It drew two separators between the same
   two things: leader dots across the gap and a hairline under the row. Printed
   menus pick one, and the dots are the one that says menu rather than table,
   so the rule comes off and the air between the lines does that work instead.
   The hairline stays in the cards variant, where there are no dots. */

[data-v-menu="columns"] .menu-item {
  padding: 11px 0;
  border-bottom: 0;
}
/* A course heading needs more space above it than the line below it, or the
   groups run together into one list. */
[data-v-menu="columns"] .menu-group__name { margin-bottom: 10px; }
[data-v-menu="columns"] .menu-item__desc { margin-top: 4px; }

/* =========================================================== menu: cards ===
   Each group is its own card, so a long list of groups reads as a set of
   boards rather than as one column that never ends. The card edge already
   separates the name from the price, so the dotted leader stops drawing and
   stays on only as the spacer that pushes the price right. */

/* min() inside the minmax, or the track keeps its floor on a narrow phone and
   pushes the card past the edge of the column it is supposed to sit in. */
[data-v-menu="cards"] .menu-groups {
  /* start, not the stretch a grid gives by default: a group of one drink next
     to a group of four dishes was being stretched to the height of the four
     and read as a card somebody forgot to finish. */
  align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(min(290px, 100%), 1fr));
  gap: 18px;
}
[data-v-menu="cards"] .menu-group {
  padding: clamp(22px, 3vw, 30px);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* Block rather than inline-block, so the accent rule under the name runs the
   width of the card and reads as the card's header. */
[data-v-menu="cards"] .menu-group__name {
  display: block;
  padding-bottom: 14px;
  margin-bottom: 0;
  font-size: 1.16rem;
}
[data-v-menu="cards"] .menu-group__desc { margin: 12px 0 0; }
[data-v-menu="cards"] .menu-list { margin-top: 8px; }
[data-v-menu="cards"] .menu-item__lead { border-bottom-style: none; }
/* No dots to run the eye across here, so the number carries a little more
   weight instead. */
[data-v-menu="cards"] .menu-item__price { font-weight: 700; }

/* ========================================================== menu: ledger ===
   A printed menu card: one narrow sheet, group names centred, the item on the
   left, leader dots across the gap, the price on the right. The prices are set
   in tabular figures inside a fixed minimum column so every number lands on
   the same right hand axis whatever the item above it was called. */

[data-v-menu="ledger"] .menu-groups {
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(34px, 4vw, 48px);
  max-width: 720px;
  margin-inline: auto;
  padding: clamp(26px, 5vw, 54px) clamp(20px, 4vw, 48px);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

[data-v-menu="ledger"] .menu-group__name {
  display: block;
  padding-bottom: 0;
  margin-bottom: 16px;
  border-bottom: 0;
  text-align: center;
  font-size: 1.2rem;
}
[data-v-menu="ledger"] .menu-group__name::after {
  content: '';
  display: block;
  width: 42px;
  height: 2px;
  margin: 13px auto 0;
  background: var(--accent);
}
[data-v-menu="ledger"] .menu-group__desc {
  margin: -8px 0 16px;
  text-align: center;
  font-style: italic;
}

/* A printed menu rules the groups, not every single line. */
[data-v-menu="ledger"] .menu-item {
  padding: 9px 0;
  border-bottom: 0;
}
[data-v-menu="ledger"] .menu-item__name { font-weight: 600; }
[data-v-menu="ledger"] .menu-item__lead { opacity: .75; }
[data-v-menu="ledger"] .menu-item__price {
  min-width: 4.5ch;
  text-align: right;
  color: var(--ink);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
[data-v-menu="ledger"] .menu-item__desc {
  margin-top: 2px;
  max-width: none;
  font-style: italic;
}

[data-v-menu="ledger"] .menu-note {
  max-width: 720px;
  margin-inline: auto;
  text-align: center;
}

/* ======================================================== booking: panel ===
   The form raised on a coloured band, centred under its own heading. The band
   is the accent laid over the page at low opacity rather than a token, because
   it has to read as a band on all six layouts: --accent-soft is mixed towards
   white on a light page and towards the primary on a dark one, where it ends
   up within a shade of the page and disappears. A wash this thin moves the
   ground under --ink by too little to touch its contrast either way.

   :has keeps this out of the template. A browser without it leaves the section
   on --surface, which is the band the site shipped with, so the fallback is
   the original page rather than an unreadable one. */

[data-v-booking="panel"] .section:has(> .wrap > .booking) { background: rgb(var(--accent-rgb) / .12); }

[data-v-booking="panel"] .booking {
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(28px, 4vw, 40px);
  justify-items: center;
}
[data-v-booking="panel"] .booking__intro {
  max-width: 640px;
  text-align: center;
}
[data-v-booking="panel"] .booking__lede,
[data-v-booking="panel"] .booking__note { margin-inline: auto; }

[data-v-booking="panel"] .booking__card {
  width: 100%;
  max-width: 660px;
  padding: clamp(24px, 4vw, 40px);
  /* An accent edge rather than --line: on the dark layout the card and the
     band are both tints of the primary and a neutral hairline vanishes. */
  border-color: rgb(var(--accent-rgb) / .3);
  box-shadow: 0 40px 80px -50px rgb(var(--primary-rgb) / .8);
}

/* ======================================================= booking: inline ===
   The form as one horizontal bar under the heading. Every short field sits on
   a single row on a wide screen and the row folds to a stack on a phone, which
   auto-fit does on its own from one rule.

   The message box and the button cannot live in a 170px column, so they take
   the lines beneath. Labels stay above their inputs: this is a booking form,
   not a search box, and a placeholder is not a label. */

[data-v-booking="inline"] .booking {
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(24px, 3vw, 34px);
}
[data-v-booking="inline"] .booking__lede { max-width: 62ch; }
[data-v-booking="inline"] .booking__card { padding: clamp(20px, 3vw, 28px); }

/* 170px is the narrowest an input can be and still show a typed phone number.
   auto-fit rather than a fixed count because the service select is only in the
   form when the document lists services. */
[data-v-booking="inline"] .bform {
  grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr));
  column-gap: 14px;
  align-items: end;
}

/* The pair wrapper exists to sit phone beside email in the tall form. Here the
   row already does that, so the two fields join it directly. */
[data-v-booking="inline"] .bfield-pair { display: contents; }

/* The message is the last label in the form and is the only field too tall for
   the row. */
[data-v-booking="inline"] .bform > p,
[data-v-booking="inline"] .bform > button,
[data-v-booking="inline"] .bform > label:last-of-type { grid-column: 1 / -1; }

/* Order, not markup, because the only thing that moves is the hint under the
   phone and email pair, which nothing can focus. Tab order and reading order
   are the document's and stay untouched. */
[data-v-booking="inline"] .bfield__hint {
  order: 1;
  margin-top: 0;
}
[data-v-booking="inline"] .bform > label:last-of-type { order: 2; }
[data-v-booking="inline"] .bform > button {
  order: 3;
  width: auto;
  min-width: 240px;
  justify-self: start;
}
[data-v-booking="inline"] .bform__privacy { order: 4; }


/* ====================================================== booking: slots ==== */
/* The real booking engine, as opposed to the request form beside it. Every
   day and every time is in the document; the script collapses them to one day
   at a time and this styles both states, because with no script running the
   whole calendar is on the page as a stack of labelled fieldsets and it has to
   be readable that way too. */

.slotbook { display: grid; gap: 16px; }

.slotbook__field { display: grid; gap: 6px; }
.slotbook__field > label { font-size: 14px; font-weight: 650; }

.slotbook__field input,
.slotbook__field select,
.slotbook__field textarea {
  font: inherit;
  /* 16px is the floor at which iOS Safari stops zooming the page on focus. */
  font-size: 16px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
  width: 100%;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.slotbook__field input:focus,
.slotbook__field select:focus,
.slotbook__field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgb(var(--accent-rgb) / .2);
}
.slotbook__field textarea { resize: vertical; min-height: 60px; }

/* The day rail. It scrolls sideways on a phone rather than wrapping into four
   rows of stubs, and the whole strip is one tab stop with the buttons inside
   it, so a keyboard walks the days in order. */
.slotbook__days {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-bottom: 4px;
  margin-inline: calc(var(--radius) * -1);
  padding-inline: var(--radius);
}

.slotbook__day {
  flex: none;
  scroll-snap-align: start;
  display: grid;
  gap: 2px;
  justify-items: center;
  /* 44px is the smallest a finger reliably hits. */
  min-width: 76px;
  min-height: 56px;
  padding: 9px 12px;
  font: inherit;
  font-size: 14px;
  font-weight: 650;
  line-height: 1.25;
  color: var(--ink-2);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}
.slotbook__day span { font-size: 12px; font-weight: 500; color: var(--ink-3); }
.slotbook__day:hover { border-color: var(--accent); }
.slotbook__day.is-on {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
}
.slotbook__day.is-on span { color: inherit; opacity: .8; }

.slotbook__times {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}

/* With the script running the day rail names the day, so the legend would say
   it twice. It stays in the document for screen readers and for the no-script
   page, where it is the only thing separating one day from the next. */
.slotbook__times legend {
  width: 100%;
  padding: 0;
  margin-bottom: 8px;
  font-size: 14px;
  font-weight: 650;
}
.slotbook.is-enhanced .slotbook__times legend {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The radio itself is the control, so it keeps its focus ring rather than
   being replaced by a div that cannot be tabbed to. */
.slotbook__time { position: relative; }
.slotbook__time input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.slotbook__time span {
  display: grid;
  place-items: center;
  /* 44px stays: it is the smallest a finger reliably hits, and these are
     mostly tapped. The width comes down because "09:30" does not need 72px
     and fifteen of them across a form is what made the block a wall. */
  min-width: 62px;
  min-height: 44px;
  padding: 0 8px;
  font-size: 15px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}
.slotbook__time input:hover + span { border-color: var(--accent); }
.slotbook__time input:focus-visible + span {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.slotbook__time input:checked + span {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
}

/* The parts of the day. Fifteen times in one block is a wall and a reader has
   to work out where the morning ends; three labelled rows is the same
   information with none of that work. The label is aria-hidden because the
   time on each button already says which part of the day it is, and a screen
   reader does not need to be told twice. */
.slotbook__part + .slotbook__part { margin-top: 14px; }

.slotbook__partname {
  margin: 0 0 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.slotbook__row { display: flex; flex-wrap: wrap; gap: 8px; }

.slotbook__who { display: grid; gap: 14px; }

.slotbook__error {
  margin: 0;
  font-size: 14px;
  font-weight: 650;
  color: var(--bad-ink);
}

.slotbook__empty,
.slotbook__privacy { margin: 0; font-size: 13px; color: var(--ink-3); }

/* Off screen rather than display:none: some bots skip anything hidden outright. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

@media (min-width: 620px) {
  .slotbook__who { grid-template-columns: 1fr 1fr; }
  .slotbook__who .slotbook__field:first-child { grid-column: 1 / -1; }
}

/* ============================================== the customer's booking ==== */
/* Their own page, in the client's theme rather than ours, because the
   appointment is with the business and not with the agency. */

.bookingpage__wrap { max-width: 620px; }
.bookingpage__wrap h1 { margin-bottom: 20px; }
.bookingpage__wrap h2 { margin: 36px 0 12px; font-size: 1.1rem; }

.bookingpage__flash {
  padding: 14px 16px;
  margin-bottom: 24px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
}
.bookingpage__flash p { margin: 4px 0 0; color: var(--ink-2); }

.bookingcard {
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
}
.bookingcard.is-cancelled { opacity: .62; }

.bookingcard__when {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin: 0 0 16px;
}
.bookingcard__when b { font-size: 1.25rem; }
.bookingcard__when span {
  font-size: 1.25rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--accent-strong);
}

.bookingcard__facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 18px;
  margin: 0 0 18px;
  font-size: 15px;
}
.bookingcard__facts dt { color: var(--ink-3); }
.bookingcard__facts dd { margin: 0; font-weight: 650; }

.bookingcard__state { margin: 0; font-weight: 650; color: var(--ink-3); }

.bookingpage__where { margin: 18px 0 0; color: var(--ink-2); font-size: 15px; }
.bookingpage__where a { margin-left: 10px; }
.bookingpage__keep { margin: 28px 0 20px; font-size: 13px; color: var(--ink-3); }

.bookinglist { list-style: none; margin: 0; padding: 0; }
.bookinglist li {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 14px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
}
.bookinglist li.is-cancelled { color: var(--ink-3); }
.bookinglist li.is-cancelled b { text-decoration: line-through; }
.bookinglist b { font-variant-numeric: tabular-nums; }
.bookinglist span { color: var(--ink-2); }
.bookinglist em { font-style: normal; font-size: 13px; color: var(--ink-3); }
.bookinglist a { margin-left: auto; font-size: 14px; }

/* The booking page has no hero for the header to sit over, and no scroll
   script to tell it so. The demo header starts transparent with a dark scrim
   because it is drawn on top of a photograph, and left in that state on a page
   that begins with white it is a grey smear with white text in it. Put it
   straight into the state the demo pages reach on the first scroll. */
.bookingpage .site-header {
  position: sticky;
  background: var(--page);
  border-bottom-color: var(--line);
}
.bookingpage .site-header::before { display: none; }
.bookingpage .brand__name { color: var(--ink); }
.bookingpage .brand__meta { color: var(--ink-3); }

/* Nothing is fixed over the top of it any more, so the page does not need the
   offset that clears a fixed bar. */
.bookingpage main { padding-top: clamp(28px, 5vw, 52px); }

/* ------------------------------------------------------------- the closer -- */
/* Every page ends by asking. Split across five pages, four of them used to run
   out with a footer, because the one cta section a document might carry lived
   on whichever page it had been filed under and only five of thirty-eight
   documents carried one at all. This is built from what every site has. */

.closer {
  border-top: 1px solid var(--line);
  background: var(--surface);
}

/* On a dark page the band cannot take --deep: that is the footer's ground, and
   the ask and the small print under it came out as one unbroken black run with
   nothing between them but a hairline at 1.1:1. The lifted surface puts the
   closer between the page above it and the footer below it, which is the only
   place a closing band can be if it is going to read as one.

   It is stated before the two rules under it so that a page ending on an alt
   section can still overrule it: on dark those three grounds are #22201e,
   #161412 and #0f0e0c, so whichever pair meets, they differ. */
/* Dark answers this in its own block at the foot of the file, where the
   closer stops being a fifth band of the same black and becomes a signature. */

/* The closer sits on --surface, and so does .section--alt, so a page whose last
   section is an alt one ended with the ask dissolved into it behind a hairline.
   Flip the ground when they would otherwise match. The two layouts listed
   second gives --alt a ground of its own already, so on it the flip is what
   would cause the collision rather than what fixes it. Bold answers the same
   question in its own scope and with its own two grounds. */
.section--alt + .closer { background: var(--page); }

.closer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(20px, 4vw, 44px);
  padding-block: clamp(44px, 7vw, 84px);
}

/* The last thing on the page is the ask, and it was set smaller than every
   heading above it. It is now a section heading like the rest, which is the
   least a closing band can be. */
.closer h2 { font-size: clamp(1.6rem, 3.8vw, 2.4rem); }
.closer p { margin: 10px 0 0; color: var(--ink-2); max-width: 46ch; }
.closer .status-pill {
  display: inline-flex;
  margin-bottom: 14px;
  color: var(--ink-2);
}

.closer__actions { display: flex; flex-wrap: wrap; gap: 12px; }
/* The primary action carries the weight the band is there for. */
.closer__actions .btn--accent { min-height: 58px; padding: 16px 30px; font-size: 16.5px; }
/* The secondary one is the only control in this band whose edge is the whole of
   it, and --line measured 1.27:1 against the ground behind it. Same floor as
   the call bar, same reason. */
.closer__actions .btn--outline { border-color: var(--ink-3); }

/* Side by side they are two shapes; stacked they were two different widths,
   which is just untidy. On a phone they are one column the width of the page. */
@media (max-width: 559px) {
  .closer__actions { width: 100%; }
  .closer__actions .btn { flex: 1 0 100%; }
}

/* ---------------------------------------------------------- the page head -- */
/* How a sub-page opens. The home page has the hero: a photograph, a headline,
   two buttons. A sub-page has none of that and must not pretend to, because a
   second full-bleed hero on every page is exactly what a template does. Name
   the business, name the page, say what is on it, get out of the way. */

.pagehead {
  /* The clearance used to be the literal 74px the shipped 'bar' header was,
     written before the header variants landed and never re-read afterwards.
     The stack variant is 116px and the centred one 138px, so on those the
     breadcrumb, which is the first line of every sub-page and a link, was
     drawn twenty-seven pixels behind the fixed bar. --header-h is declared
     once per variant per breakpoint and --header-top already carries the
     example bar, so the two hand-maintained numbers become one expression
     that cannot fall out of date. */
  padding-top: calc(var(--header-top) + var(--header-h) + clamp(36px, 7vw, 84px));
  padding-bottom: clamp(24px, 4vw, 44px);
  border-bottom: 1px solid var(--line);
  background: var(--page);
}

/*
   Not tracked caps.

   It was 13px uppercase at 650, which is character for character the same
   recipe as the section .eyebrow that lands about forty pixels below it. So
   every sub-page opened with a caps label, a heading and a line of lede,
   immediately followed by a caps label, a heading and a line of lede. Reading
   it as a breadcrumb instead of a label breaks the rhyme, and a breadcrumb is
   what it actually is: the business name, linked home.
*/
.pagehead__eyebrow {
  margin: 0 0 16px;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  /* --ink-3 is the natural weight for a line like this and it does not hold
     here: measured on white it lands between 3.61 and 4.48 across the light
     themes, and this line is a link, so 4.5 is the floor and not a target.
     --ink-2 is the next step up and its worst in the set is 5.39. */
  color: var(--ink-2);
}
.pagehead__eyebrow a { color: inherit; text-decoration: none; }
.pagehead__eyebrow a:hover { color: var(--accent-strong); text-decoration: underline; }

.pagehead h1 {
  font-size: clamp(2.2rem, 7vw, 4rem);
  max-width: 18ch;
}

.pagehead__lede {
  margin: 16px 0 0;
  max-width: 46ch;
  font-size: clamp(1.02rem, 1.6vw, 1.15rem);
  line-height: 1.55;
  color: var(--ink-2);
}

/*
   A masthead, not a stack.

   Everything was flush left in about two thirds of the measure with the right
   third empty, which is the shape of the section heads below it and the reason
   two heads in a row read as one repeated thing. Setting the name against the
   line about it, both sitting on the same foot, is what a printed page does
   with a running head and it costs nothing but a grid.
*/
@media (min-width: 860px) {
  .pagehead > .wrap {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
    column-gap: clamp(40px, 6vw, 96px);
    align-items: end;
  }
  .pagehead__eyebrow { grid-column: 1 / -1; }
  .pagehead h1 { grid-column: 1; max-width: none; }
  /* Dropped onto the headline's last baseline rather than its box, which is
     what stops the two columns looking merely bottom-aligned. */
  .pagehead__lede { grid-column: 2; margin: 0 0 .5em; }
}

/* The header on a sub-page has no photograph under it, so it starts solid
   rather than transparent over a scrim. Same reasoning as the booking page. */
body:not(.has-hero) .site-header {
  background: var(--page);
  border-bottom-color: transparent;
}
body:not(.has-hero) .site-header::before { display: none; }
body:not(.has-hero) .brand__name { color: var(--ink); }
body:not(.has-hero) .brand__meta { color: var(--ink-3); }
body:not(.has-hero) .nav a { color: var(--ink-2); }
body:not(.has-hero) .nav a:hover { color: var(--ink); }
body:not(.has-hero) .nav a[aria-current="page"] { color: var(--accent-strong); }
body:not(.has-hero) .nav-toggle { color: var(--ink); }

/* The current page, marked in the bar. On a five page site a reader who
   cannot tell which page they are on will use the browser's back button
   instead of the navigation. */
.nav a[aria-current="page"] {
  color: var(--accent);
  font-weight: 700;
}

/* ============================================================== the shop ==== */
/* Products, a basket and a checkout on a client's own site. No card is ever
   taken on a demo; see ShopController for why. */

.shop {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: clamp(16px, 2.4vw, 28px);
}

.product {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  overflow: hidden;
}

.product__media { aspect-ratio: 4 / 3; overflow: hidden; background: var(--surface); }
.product__media img { width: 100%; height: 100%; object-fit: cover; }

.product__body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 16px;
  /* Pushes the button to the bottom whatever the description length, so a row
     of cards has its buttons on one line rather than a ragged edge. */
  flex: 1;
}
.product__body h3 { font-size: 1.02rem; }
.product__desc { margin: 0; font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.product__price { margin: 2px 0 10px; font-weight: 700; font-variant-numeric: tabular-nums; }
.product__body form { margin-top: auto; }
.product__ask { margin: auto 0 0; font-size: 14px; color: var(--ink-3); }

/* ------------------------------------------------ basket and checkout ----- */

.shoppage { max-width: 720px; }
.shoppage h1 { margin-bottom: 20px; }
.shoppage h2 { margin: 32px 0 12px; font-size: 1.1rem; }

/* Said on every page of the flow, not only at the end. Somebody who fills in
   an address believing it will be delivered has been misled by the time the
   confirmation admits otherwise. */
.shoppage__notice {
  margin: 0 0 24px;
  padding: 10px 14px;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  font-size: 14px;
  color: var(--ink-2);
  background: var(--surface);
}

.shoppage__empty { color: var(--ink-2); }

.cartlines { list-style: none; margin: 0 0 18px; padding: 0; border-top: 1px solid var(--line); }

.cartline {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
}

.cartline__media { flex: none; width: 64px; aspect-ratio: 1; border-radius: var(--radius); overflow: hidden; }
.cartline__media img { width: 100%; height: 100%; object-fit: cover; }

.cartline__body { flex: 1; min-width: 0; }
.cartline__body b { display: block; }
.cartline__unit { font-size: 14px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.cartline__qty input {
  width: 68px;
  min-height: 44px;
  padding: 8px 10px;
  font: inherit;
  font-size: 16px;
  text-align: center;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.cartline__total { flex: none; font-weight: 700; font-variant-numeric: tabular-nums; }

.cartlines--summary .cartline { padding: 10px 0; }

.carttotal {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 14px 0;
  border-bottom: 2px solid var(--ink);
  font-size: 1.1rem;
}
.carttotal b { font-size: 1.3rem; font-variant-numeric: tabular-nums; }

.cartactions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
.cartactions .btn--accent { margin-left: auto; }

/* Announced but not drawn. Used for the quantity labels, which a sighted
   reader gets from the column and a screen reader needs said. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The hero eyebrow sits on a photograph, not on paper. --accent-strong is
   darkened for text on a light page, which made it near invisible over a dark
   hero image on the classic and bold layouts. */
body:not(.hero-light) .hero .eyebrow,
body:not(.hero-light) .hero--bold .eyebrow { color: var(--accent-on-dark); }

/*
   Except on the two heroes where the photograph runs under the words.

   Everywhere else the ground is a flat block of the primary and a lifted
   accent holds. On classic and dark it is whatever picture the business
   happened to send, and nobody vetted it: sampled off the rendered canvas, the
   label measured 3.98:1 over Rakstugan's photograph and 3.05:1 over the
   near-white clinic interior on Tandlakarna, against a 4.5 floor for a 12px
   label. The scrim cannot be deepened far enough without turning the picture
   into a colour wash.

   So the words take the hero's own white, which measured 6.5:1 on the same
   photograph, and the accent stays in the rule beside them. The rule is
   decorative and the words next to it say what it marks, so nothing is lost by
   it being the only coloured thing in the line.
*/
   Classic is out of this pair. Its locality line is no longer drawn on a
   photograph at all: the band ends and the masthead begins on the page's own
   paper, where --accent-strong is the token that was measured for exactly
   this job and holds at 4.5:1 on every palette in the set. */
/* And dark is out of it now too. Its locality line is not drawn on a
   photograph any more either: the plate ends and the words begin on the page's
   own black, where the accent is measured rather than sampled off whatever
   picture arrived. The dark block at the foot of this file says so. */

/* A product whose photograph has not been fetched yet. It keeps its place in
   the grid, drawn as a tinted field with the product's own initial, so a row
   of cards stays a row rather than becoming a ragged edge with a broken-image
   icon in it. */
.product__media--none {
  display: grid;
  place-items: center;
  background:
    linear-gradient(135deg, rgb(var(--accent-rgb) / .16), rgb(var(--accent-rgb) / .05));
}
.product__media--none span {
  font-family: var(--font-heading);
  font-size: clamp(2rem, 5vw, 3rem);
  font-weight: var(--heading-weight, 700);
  color: rgb(var(--accent-rgb) / .5);
  letter-spacing: var(--heading-track);
}

/* The rest of a long part, behind a disclosure. A dentist selling half hour
   appointments has nineteen openings in one afternoon, which at five buttons a
   row on a phone is four rows for one part. Nobody reads the thirty-seventh
   time; they take one of the first few or they change the day. */
.slotbook__more { margin-top: 8px; }

.slotbook__more summary {
  display: inline-block;
  padding: 6px 2px;
  font-size: 14px;
  font-weight: 650;
  color: var(--accent-strong);
  cursor: pointer;
  /* The row of times below is the affordance; a marker as well is noise. */
  list-style: none;
}
.slotbook__more summary::-webkit-details-marker { display: none; }
.slotbook__more summary:hover { text-decoration: underline; }
.slotbook__more[open] summary { margin-bottom: 8px; }

/* ============================================================== atelier ====
   Editorial minimalism: whitespace, hairline rules, a restrained palette.

   The register an architecture practice, a law firm or a serious studio sets
   its own site in, and the one thing the six layouts above could not do. Four
   decisions carry it, and every one of them is a subtraction.

   1. THE ACCENT IS A NEUTRAL. This is the whole reason the block exists. Every
      other layout assumes theme.accent is a colour and puts it in text: the
      eyebrow, the current page in the navigation, the star row. A taupe or a
      warm grey there is a label nobody can read.

      Measured on the taupe #cdb5a7 against a white page, which is what the
      three derived tokens actually come out as:

        --accent-ink      #141414 at 9.69:1 on the accent. Holds. A pale
                          neutral is exactly the case readableInk gets right,
                          so a filled control keeps black text on it.
        --accent-on-dark  #e9dfd7, near white, and never below 10:1 on any of
                          the dark bands. Holds, and needs nothing.
        --accent-strong   #83746b at 4.492:1 on white. Does NOT hold. It is
                          under the 4.5 a 12px label owes a reader, and the
                          eyebrow, the service icons, the review initials and
                          the star row all name it.

      So --accent-strong, and only that one, is restated below for this scope.
      The raw accent keeps grounds, rules and fills, where a pale neutral is
      exactly what is wanted, and everything read as text takes an accent mixed
      far enough into the page's own ink to hold at any accent the schema will
      accept. Theme::cssVariables is untouched: the other six layouts are all
      built on saturated accents and moving the derivation would move all
      forty-four sites at once.

      The raw accent is still not a text colour here, so the two places the
      stylesheet used it as one, the current page in the navigation and the
      star fill, are pointed somewhere else further down.

   2. HAIRLINES INSTEAD OF CARDS. One pixel of --line separates things, and
      nothing here carries a fill, a shadow, or more than 3px of radius.

   3. PORTRAIT PHOTOGRAPHY. 4:5 on the about photograph and on both sides of
      the alternating pair, which is the crop a building, a room and a person
      are all actually photographed in. The gallery keeps its own squares,
      because a wall of pictures is a different job.

   4. AIR, AND A HEADLINE THAT IS ACTUALLY A HEADLINE. Sections run to 132px
      rather than 118, and the front page opens on type at up to 5.4rem set at
      400 rather than the 700 the pairing asked for. A display face at 400 is
      a different typeface from the same face at 700, and this layout wants the
      quiet one.

   Specificity note: nearly every selector here is [data-layout="atelier"] X,
   which is (0,2,0) and therefore beats the plain (0,1,0) rules inside the
   860px and 1080px media queries above at every width. Anything that has to
   change WITH the viewport is written into this block's own media query at the
   end, never up here.
   ========================================================================= */

body[data-layout="atelier"] {
  /*
     SQUARE, WHATEVER THE DOCUMENT ASKED FOR.

     This used to clamp to 3px, which raised a document that had declared
     "radius": "none" as well as lowering one that asked for eighteen. Three
     pixels of rounding on a photograph is not a compromise between the two,
     it is a visible softness on every corner of a layout whose whole argument
     is the printed page, and it read as a picture frame that had not quite
     been squared up. A practice's own paper has right angles.
  */
  --radius: 0px;

  /*
     A MISSING CUT MUST FAIL, NOT BE FAKED.

     --font-heading can resolve to a display face that ships one weight and no
     italic. Asking such a face for 600 gets a browser-synthesised bold, which
     is the smeared fake the whole type pass was about. With synthesis off the
     heading simply stays at the weight the face has, which is the honest
     answer and is also the register this layout wants.
  */
  font-synthesis: none;

  /* Text, icons and marks that want to be warm rather than grey. 38 per cent
     of the accent against the page's own ink: at the palest accent the schema
     would accept this still lands near 5:1 on paper, and with the taupe it is
     6.8:1. The eyebrow, the service and feature icons, the review initials,
     the large numerals and every small link that takes an accent already name
     this token, so none of them is touched again below. */
  --accent-strong: color-mix(in srgb, var(--accent) 38%, var(--ink));

  /* The alternate ground. --surface is a grey tint of the primary and reads as
     an off-white panel; sand is the accent laid over the page, so the quiet
     band is the same family as the rest of the site. */
  --sand: color-mix(in srgb, var(--accent) 24%, var(--page));

  /*
     TWO MORE HAIRLINE WEIGHTS, because one is not enough for a layout with no
     fills to fall back on.

     --line is 1.16:1 on paper and 1.08:1 on sand. As a long rule across a
     column that is exactly right: the eye reads it as a printed rule and the
     length carries it. As a 42px ring around a service icon or a step number
     it disappears, and a mark with an invisible edge does not read as quiet,
     it reads as a border that failed to load.

     --line-mark  1px of ink at 32 per cent, 2.04:1 on paper and 1.74:1 on
                  sand. Decoration around something that carries its own
                  meaning (the numeral, the initial, the icon), so the floor
                  that applies is legibility, not 3:1.
     --line-edge  1px of ink at 55 per cent, 4.0:1 on paper and 3.35:1 on
                  sand. The boundary of a form control, which IS a user
                  interface component and does owe a reader 3:1 on the ground
                  it sits on. Both numbers are measured against the two
                  grounds a field can actually land on in this layout.
  */
  --line-mark: color-mix(in srgb, var(--ink) 32%, var(--page));
  --line-edge: color-mix(in srgb, var(--ink) 55%, var(--page));

  /* From the layout, not from the pairing. A 5rem headline at 700 is a
     poster, and a 5rem headline in capitals is a wall. h3 and h4 go back up
     to 600 below, because a service name at 400 stops being a heading. */
  --heading-weight: 400;
  --heading-case: none;
  --heading-track: -0.015em;
}

/* The pairing knows which weights its display face actually ships; the layout
   does not. --heading-weight-strong is the heaviest cut on disk, so a service
   name stops being a paragraph without anyone asking a 400-only face for a
   bold it has not got. */
[data-layout="atelier"] h3,
[data-layout="atelier"] h4 { font-weight: var(--heading-weight-strong); letter-spacing: -0.005em; }

/* ------------------------------------------------------- atelier: rhythm --- */

[data-layout="atelier"] .section { padding: clamp(72px, 10vw, 132px) 0; }
[data-layout="atelier"] .section--tight { padding: clamp(52px, 7vw, 88px) 0; }
[data-layout="atelier"] .section--alt { background: var(--sand); }

/*
   THE SEAM BETWEEN TWO SECTIONS ON THE SAME GROUND.

   There is a rule near the top of this file that halves the padding and draws
   a hairline where a document files two alt sections or two plain sections
   next to each other, because otherwise the two read as one very tall band
   with a hole in it. That rule is (0,2,0) and so is the .section padding
   above, so the later of the two wins and the later of the two is this block:
   the atelier layout was quietly cancelling the fix and paying for it twice
   over, since its own padding is the largest in the file.

   Measured on the fee page, where the price list and the six stages are both
   alt sections: the seam was 264px of unbroken sand. It is 152px now, with
   the hairline the shared rule was already drawing on top of it.
*/
[data-layout="atelier"] .section--alt + .section--alt,
[data-layout="atelier"] .section:not(.section--alt, .section--dark) + .section:not(.section--alt, .section--dark) {
  padding-top: clamp(48px, 6vw, 76px);
}
[data-layout="atelier"] .section--alt:has(+ .section--alt),
[data-layout="atelier"] .section:not(.section--alt, .section--dark):has(+ .section:not(.section--alt, .section--dark)) {
  padding-bottom: clamp(48px, 6vw, 76px);
}

/* ------------------------------------------ atelier: how a section opens --- */
/*
   THE ONE THING EVERY LAYOUT IN THIS FILE DID IDENTICALLY.

   A section opened with a tracked eyebrow behind a short mark, a serif h2 and
   a grey line of lede, stacked inside a 640px column. Drawn once it is a
   heading. Drawn fifteen times across five pages it is the stamp: the reader
   cannot tell the fee page from the gallery page from the front page except
   by reading the words, because the furniture above the words is the same
   object every time.

   A practice's own paper opens a section with a rule across the measure and
   the heading hung under it, and it sets the standfirst BESIDE the heading
   rather than under it, because that is what a column of type is for. So the
   rule runs the full width, the eyebrow goes, and the head splits.

   THE EYEBROW GOES. A page is allowed one, and the hero and the page head
   already carry it: "MAJORNA, GÖTEBORG" over the front page headline and the
   practice's name over every sub-page title. Every other one on the page was
   repeating the navigation label immediately above a heading that said the
   same thing in larger type.

   Scoped to a head that is a direct child of .wrap. The FAQ nests its head
   inside one column of a two column grid, and splitting that again leaves a
   300px heading next to a 300px paragraph.
*/
[data-layout="atelier"] .section-head { max-width: none; margin-bottom: clamp(38px, 5vw, 60px); }
/* Every eyebrow inside a section, not only the ones in a section head: the
   about pair, the free text block and the gallery each print their own, and
   the about page was opening four blocks in a row with one. What is left is
   the hero's, which names the district, and the page head's breadcrumb, which
   is not an eyebrow at all. One per page. */
[data-layout="atelier"] .section .eyebrow { display: none; }
[data-layout="atelier"] .wrap > .section-head {
  border-top: 1px solid var(--ink);
  padding-top: clamp(16px, 2.2vw, 26px);
}
/* The same rule, on the ground it is actually drawn on. */
[data-layout="atelier"] .section--dark .wrap > .section-head { border-top-color: rgb(255 255 255 / .55); }
/* Inside the FAQ's own column the head keeps its stack and takes a measure
   that stops the heading running the full width of a narrow column. */
[data-layout="atelier"] .faq-grid .section-head { max-width: 30ch; }
/* And at the section's own size a three word heading broke over three lines in
   a 300px column, so inside that column it comes down a step. */
[data-layout="atelier"] .faq-grid .section-head h2 { font-size: clamp(1.6rem, 3.2vw, 2.2rem); }

[data-layout="atelier"] .section-head h2,
[data-layout="atelier"] .about__body h2,
[data-layout="atelier"] .booking__intro h2 { font-size: clamp(1.9rem, 4.6vw, 3.1rem); line-height: 1.06; }
[data-layout="atelier"] .section-head h2.h2--small { font-size: clamp(1.4rem, 3vw, 1.9rem); }
/* Measure only. Restating the colour here would be (0,3,0) and would land
   after .section--dark .section-head p, which is the rule that turns the
   subtitle and the eyebrow white on the dark bands: with the colour repeated
   the gallery and contact heads came out in body ink on near black, 1.9:1. */
[data-layout="atelier"] .section-head p { max-width: 62ch; }

/* The two eyebrows a page keeps: the locality over the front page headline
   and the practice's name over every sub-page title. Both trade the 2px
   accent bar for a hairline. A 26x2 block of colour is a card's mark; a 34x1
   rule is a printed page's. */
[data-layout="atelier"] .eyebrow { letter-spacing: .2em; font-weight: 600; }
[data-layout="atelier"] .eyebrow::before { width: 34px; height: 1px; background: var(--ink-3); }

/* .rule, in the reference, is 1px of line and nothing else. */
[data-layout="atelier"] .about__rule {
  width: 72px; height: 1px;
  background: var(--line);
  margin: 26px 0;
}

/* --------------------------------------------------------- atelier: type --- */

[data-layout="atelier"] .about__body p,
[data-layout="atelier"] .prose p { line-height: 1.72; }
[data-layout="atelier"] .about__body,
[data-layout="atelier"] .prose { max-width: 64ch; }

/* ------------------------------------------------------ atelier: buttons --- */

/*
   A filled button in a pale neutral has no edge. #cdb5a7 against white is
   1.95:1, under the 3:1 a control boundary owes a reader, so the accent
   cannot be the fill here. The primary control is the page's own ink, which
   is what the reference does too, and the accent arrives on hover: the button
   turns from black to taupe and keeps black text on it at 9.7:1. The border
   stays on ink through the hover so the edge never drops below 3:1.
*/
/*
   AND A CAPITAL LABEL HAS TO BE ABLE TO WRAP.

   The uppercase setting widens a label by about a third, and the shared .btn
   carries white-space: nowrap. A flex item with min-width: 0 and unwrappable
   content overflows its track rather than shrinking, so any document whose
   ctaLabel ran past about twenty-five characters pushed the hero actions off
   the right of a 375px screen. Nothing in the schema caps that label, so the
   fix cannot be "keep the labels short": the button wraps, balances its two
   lines, and the tracking comes down to .08em so the wrap point comes later.
*/
[data-layout="atelier"] .btn {
  border-radius: var(--radius);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 16px 28px;
  white-space: normal;
  text-wrap: balance;
}
[data-layout="atelier"] .btn:hover { transform: none; }
/*
   The fixed call bar is the exception, and it has to be.

   It holds two buttons side by side across the whole width of a phone, and
   capitals with a tenth of an em between the letters do not fit there: at
   360px "Vägbeskrivning" ran 55 pixels past the right edge of the screen. The
   bar keeps the sentence setting, which is also the right register for a
   control that is following the reader down the page rather than sitting in
   the composition.
*/
[data-layout="atelier"] .callbar .btn {
  text-transform: none;
  letter-spacing: -0.005em;
  font-size: 15px;
  padding: 13px 16px;
}
[data-layout="atelier"] .btn--accent {
  --btn-bg: var(--ink);
  --btn-ink: var(--page);
  border: 1px solid var(--ink);
  box-shadow: none;
}
[data-layout="atelier"] .btn--accent:hover {
  background: var(--accent);
  color: var(--accent-ink);
}
[data-layout="atelier"] .btn--outline { border-color: var(--ink-3); }
[data-layout="atelier"] .btn--outline:hover { background: transparent; border-color: var(--ink); }

/*
   AND ON THE DARK BANDS THE SAME DECISION INVERTS.

   Pointing the primary control at --ink is right everywhere the ground is
   paper and wrong in the two places it is not. The gallery band and the
   contact band are --deep, which is #1c1a17 on this document, and the button
   was #1b1916: one point of contrast, a button you can only find because the
   panel behind it happens to be a shade lighter. This is the one place the
   neutral accent is the right fill rather than the wrong one, and it is the
   same argument the closing band already makes: 8.4:1 as an edge against the
   dark, 9.7:1 for the black label sitting on it.

   The outlined button beside it borrows the panel's own hairline, which is
   white at 12 per cent and 1.3:1 against the ground. A divider inside a panel
   can be that quiet. The edge of a control cannot.
*/
[data-layout="atelier"] .section--dark .btn--accent {
  --btn-bg: var(--accent);
  --btn-ink: var(--accent-ink);
  border-color: var(--accent);
}
[data-layout="atelier"] .section--dark .btn--accent:hover {
  background: var(--page);
  color: var(--ink);
  border-color: var(--page);
}
[data-layout="atelier"] .section--dark .btn--ghost { border-color: rgb(255 255 255 / .45); }
[data-layout="atelier"] .section--dark .btn--ghost:hover { border-color: rgb(255 255 255 / .8); }

/* The current page in the navigation is text, so it cannot be the raw accent
   either. Weight and the ink do the marking; the accent would be a pale grey
   word among darker ones, which reads as disabled rather than as current. */
[data-layout="atelier"] .nav a[aria-current="page"] { color: var(--ink); }

/* A meaningful graphic, so it holds 3:1 rather than sitting at the accent's
   1.95:1 on paper. On the dark bands the raw accent is already well clear. */
[data-layout="atelier"] .stars__fill { color: var(--accent-strong); }
[data-layout="atelier"] .section--dark .stars__fill,
[data-layout="atelier"] .hero:not(.hero--light) .stars__fill { color: var(--accent); }

/* --------------------------------------------------------- atelier: hero --- */

/*
   The headline is not inside a column.

   It runs the full measure, a hairline closes it, and only then does the page
   split into the photograph and the buttons. No other layout we own opens
   this way: classic hides the words in the picture, editorial and split set
   them beside it, minimal centres them. A practice whose name is the product
   puts the name first and the picture second, and this is that page.
*/
.hero--atelier {
  display: block;
  min-height: 0;
  max-height: none;
  /* Every other light hero holds its text in a column and can afford to start
     under a flat 108px. This one opens on a 12px eyebrow at the very top of
     the measure, so it clears the bar the way the sub-page heads do, from the
     bar's own height rather than from a number that happens to work for the
     default header. The stack and centred variants restate this above at a
     higher specificity with the same expression, which is harmless. */
  padding-top: calc(var(--header-top) + var(--header-h) + var(--hero-clear));
  padding-bottom: clamp(40px, 6vw, 76px);
  border-bottom: 1px solid var(--line);
}
.hero--atelier h1 {
  font-size: clamp(2.5rem, 8vw, 5.4rem);
  /* 1.0 was solid leading, and solid leading is only safe in a language whose
     capitals are flat on top. Swedish puts a ring on Å and two dots on Ä and
     Ö, and at 86px a headline that breaks with a descender above one of them
     has the two touching. 1.04 is 3px of clearance and still reads as a
     headline set tight rather than as a paragraph. */
  line-height: 1.04;
  max-width: 17ch;
}
.hero--atelier .hero__head {
  padding-bottom: clamp(22px, 3vw, 34px);
  border-bottom: 1px solid var(--line);
  margin-bottom: clamp(26px, 3.6vw, 40px);
}
.hero--atelier .hero__inner { max-width: none; align-self: start; }
.hero--atelier .hero__sub {
  margin-top: 0;
  font-size: clamp(1.06rem, 2.2vw, 1.24rem);
  line-height: 1.7;
  max-width: 46ch;
}
.hero--atelier .hero__actions { margin-top: clamp(26px, 4vw, 36px); align-items: center; }
/*
   One button and one link, not two buttons.

   Two tracked capital labels of unequal length stacked down the left of a
   column is the shape of a form, and the Swedish second label is regularly
   twenty characters, which is enough to break the row on its own. The
   reference sets its second action as an underlined word for the same reason.
   The link keeps the button's 52px minimum height, so the tap target is
   unchanged on a phone.
*/
.hero--atelier .btn--ghost {
  --btn-bg: transparent;
  --btn-ink: var(--ink);
  border: 0;
  padding: 14px 2px;
  backdrop-filter: none;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
}
.hero--atelier .btn--ghost:hover { background: transparent; color: var(--accent-strong); }
.hero--atelier .hero__figure img {
  aspect-ratio: 4 / 5;
  border-radius: var(--radius);
}
/* The meta row goes full width under both columns, which is where the rule
   through it finally has something to be a rule across. It carries the
   container the row measures itself against, because .hero__inner, which
   normally carries it, is no longer the row's parent here. */
.hero--atelier .hero__foot {
  container-type: inline-size;
  container-name: heroinner;
  margin-top: clamp(28px, 4vw, 44px);
}
.hero--atelier .hero__foot .trust { margin-top: 0; }
/* An empty foot on a document with no rating, no hours and no address would
   otherwise still draw its top margin. */
.hero--atelier .hero__foot:empty { display: none; }

/* ------------------------------------------- atelier: the alternating pair --- */

/*
   Image one side, prose the other, and the side swaps on every repeat. See
   about.blade.php for which repeat is which; the flip is placement, not
   order, so the photograph is first in the source on both sides and a phone
   meets every block the same way round.
*/
[data-layout="atelier"] .feature-pair { display: grid; gap: clamp(28px, 4vw, 44px); }
[data-layout="atelier"] .feature-pair__media { margin: 0; }
[data-layout="atelier"] .feature-pair__media img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--radius);
}
[data-layout="atelier"] .feature-pair__body { align-self: center; max-width: 54ch; }

/* The split about keeps the same portrait crop when a page is dealt one. */
[data-layout="atelier"] .about__media img { aspect-ratio: 4 / 5; }

/* ---------------------------------------------------- atelier: the lists --- */

/*
   THERE ARE NO CARDS, AND NOW THERE IS NOTHING LEFT TO CONVERT.

   This part of the block used to restyle .service, .svc-row, .step, .review
   and .faq__item, which are the FIRST option of each variant list: the shape
   a site lands on roughly one time in three. Anything else the seed dealt
   arrived here unstyled and rendered as the generic card-and-accent page the
   layout exists to avoid. That is now fixed at the source, in
   Variants::BY_LAYOUT, which narrows this layout to the shapes that survive
   with no fills to fall back on, and every rule below is written against a
   shape this layout can actually be dealt. Rules for shapes it cannot be
   dealt have been deleted rather than left to rot.
*/

/* ----- services: the ruled list, and the printed index ----- */

/* The list variant sets a name, a price and a description per row. On paper
   that is a schedule, so the row loses its side padding, the rule moves to
   the top of the entry, and the name goes up a size. */
[data-layout="atelier"] .svc-list { border-top: 1px solid var(--line); }
[data-layout="atelier"] .svc-list__item {
  padding: clamp(20px, 3vw, 30px) 0;
  border-bottom: 1px solid var(--line);
}
[data-layout="atelier"] .svc-list__name { font-size: clamp(1.2rem, 3vw, 1.5rem); }
/* Figures in the text colour and in tabular widths, so a column of prices
   lines up digit under digit the way a fee schedule does. Set in the accent
   they read as a column of links and get scanned before any of the names. */
[data-layout="atelier"] .svc-list__price,
[data-layout="atelier"] .svc-index__price {
  color: var(--ink);
  font-variant-numeric: tabular-nums lining-nums;
  font-weight: var(--heading-weight-strong);
}
[data-layout="atelier"] .svc-list__desc,
[data-layout="atelier"] .svc-index__desc { max-width: 52ch; }

/* The index numeral is a folio, not a display figure: small, tracked, in the
   quiet ink, hanging in a fixed left column so every name starts on the same
   vertical. Set in the accent at the shared size it became the loudest thing
   in a section whose subject is the names beside it. */
[data-layout="atelier"] .svc-index__num {
  color: var(--ink-3);
  font-family: var(--font);
  font-weight: 500;
  font-size: 0.8rem;
  letter-spacing: .1em;
  line-height: 2.6;
}
[data-layout="atelier"] .svc-index__item { column-gap: clamp(20px, 4vw, 56px); }
[data-layout="atelier"] .svc-index__name { font-weight: var(--heading-weight-strong); }

/* ----- features: facts on hairlines ----- */

/*
   The forced four column grid is gone. It was (0,2,0) and sat after the base
   block, so it beat the count-aware rules there and stranded a seventh item
   alone on a second row. The base grid already knows that three items want
   three columns, five want a five track and six want three: this layout only
   needs the cards taken off them, and at 560px and up the base rules do the
   rest.
*/
[data-layout="atelier"] .features { gap: 0 clamp(24px, 3vw, 40px); }
[data-layout="atelier"] .feature {
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  padding: 18px 0 24px;
  gap: 12px;
}
[data-layout="atelier"] .feature__icon {
  width: auto; height: auto;
  background: transparent;
  border-radius: 0;
  color: var(--accent-strong);
}
[data-layout="atelier"] .feature__icon svg { width: 18px; height: 18px; }

/* The numbered variant sets its figure at up to 4.2rem in the accent, which
   on a page of hairlines is the one loud object in the composition. Here it
   is a folio like the index's: the fact is the content and the number is only
   its address. */
[data-layout="atelier"] .feat-num__n {
  font-family: var(--font);
  font-weight: 500;
  font-size: 0.8rem;
  letter-spacing: .1em;
  line-height: 2.2;
  color: var(--ink-3);
}

/* ----- process, as information rather than as a diagram ----- */

/*
   A NUMBERED CIRCLE ON A VERTICAL LINE IS A DIAGRAM OF A PROCESS, NOT A
   PROCESS.

   The timeline variant is out of this layout's pool for that reason. What is
   left reads as a schedule of stages: a folio, the stage, what happens in it,
   and a rule over each. Nothing is drawn that a printed page could not print.
*/
[data-layout="atelier"] .steps .step {
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
}
[data-layout="atelier"] .steps .step__num {
  width: auto; height: auto;
  display: block;
  background: transparent;
  border: 0;
  border-radius: 0;
  color: var(--ink-3);
  font-family: var(--font);
  font-weight: 500;
  font-size: 0.8rem;
  letter-spacing: .1em;
  line-height: 1.5;
  margin-top: 0;
}
[data-layout="atelier"] .steps .step h3 { font-size: 1.12rem; }
/* The row variant stacks the folio over the stage and puts sixteen pixels
   between them, which was tuned for a forty pixel disc. A line of small
   capitals wants to sit close under the rule it hangs from. */
[data-layout="atelier"][data-v-steps="row"] .steps .step { gap: 6px; }

/* ----- what people wrote ----- */

/*
   THE TEXT OF A REVIEW IS NOT DISPLAY TYPE.

   This rule used to set the review in var(--font-heading), which resolves to
   a face Theme.php's own catalogue marks DISPLAY ONLY: six of them are
   missing either a second weight or an italic, and a 1.12rem running
   paragraph in a 400-only high contrast serif is thin at reading size. The
   quiet comes from the measure and the leading instead, which is where it
   should have come from: forty-six characters and 1.72, against sixty-four
   and 1.72 for the prose elsewhere on the page.
*/
[data-layout="atelier"] .reviews .review {
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
}
[data-layout="atelier"] .reviews .review__text {
  font-size: 1.06rem;
  line-height: 1.72;
  max-width: 46ch;
}
/* The name is a caption under a quotation, so it is set as one: small,
   tracked, in the quiet ink, with the score beside it rather than over it. */
[data-layout="atelier"] .review__name,
[data-layout="atelier"] .review-line__name {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-2);
}
[data-layout="atelier"] .reviews .review__author {
  align-items: center;
  gap: 14px;
}
[data-layout="atelier"] .reviews .review__author > div {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
[data-layout="atelier"] .reviews .review__stars { margin: 0; }

/* The line of type that replaced the scoreboard. It is a fact about the
   section, so it goes above the rule with the section head rather than
   floating between the head and the first quote. */
[data-layout="atelier"] .rating-line {
  font-size: 13px;
  letter-spacing: .04em;
  color: var(--ink-2);
  margin-bottom: clamp(20px, 3vw, 30px);
}

/* The pull quote keeps the display face, because a pull quote is the one
   place display type is doing the job it was cut for. What it loses is the
   floating quotation mark: an outsized ornament deliberately set below the
   contrast floor is a decoration on a layout that has no decorations. */
[data-layout="atelier"] .review-quote__mark { display: none; }
[data-layout="atelier"] .review-quote__text { margin-top: 0; }
[data-layout="atelier"] .review-quote {
  border-top: 1px solid var(--ink);
  padding-top: clamp(24px, 3.4vw, 38px);
}
[data-layout="atelier"] .review-lines { border-top-color: var(--line); }
[data-layout="atelier"] .review-line { border-bottom-color: var(--line); }

/* ----- questions ----- */

/* Both shapes this layout can be dealt are plain rows, so there is no
   <details> marker to restyle and nothing to open. The question takes the
   heading weight, the answer takes the prose measure, and a rule opens each. */
[data-layout="atelier"] .faq--plain { border-bottom: 1px solid var(--line); }
[data-layout="atelier"] .faq__row { border-top: 1px solid var(--line); }
[data-layout="atelier"] .faq__q { font-size: 1.06rem; }
[data-layout="atelier"] .faq__a { max-width: 58ch; }

/* ----- the areas served ----- */

[data-layout="atelier"] .chip {
  background: transparent;
  border-radius: 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: 8px 2px;
  color: var(--ink-2);
}
[data-layout="atelier"] .chip::before { background: var(--accent-strong); }
[data-layout="atelier"] .areas { gap: 10px clamp(20px, 3vw, 34px); }

/* ----- the last two objects on the site with an outline round them ----- */

/*
   A PANEL IS A CARD WITH THE WORD CARD TAKEN OUT OF ITS NAME.

   The booking form and the two blocks on the contact page kept a fill, a
   border and, on the form, a 60px drop shadow, which on a layout that draws
   nothing else with an edge made them the only raised things on the site. On
   the dark contact band they were worse than that: two rectangles a shade
   lighter than the ground behind them, which does not read as a panel, it
   reads as a border that failed to load.

   They become columns of a printed sheet: a rule over each, the label under
   it in the same small tracked capitals the fee schedule and the colophon
   use, and nothing else drawn at all.
*/
[data-layout="atelier"] .panel,
[data-layout="atelier"] .booking__card {
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  padding: clamp(18px, 2.6vw, 26px) 0 0;
  box-shadow: none;
}
[data-layout="atelier"] .section--dark .panel,
[data-layout="atelier"] .section--dark .booking__card { border-top-color: rgb(255 255 255 / .4); }
/* The raw accent is a pale neutral here, so a 13px label set in it measured
   about 2:1 on paper. Warmed into the page's own ink on the light grounds and
   left as the accent on the dark ones, where it is already well clear. */
[data-layout="atelier"] .panel h3 {
  color: var(--accent-strong);
  font-weight: 600;
}
[data-layout="atelier"] .section--dark .panel h3 { color: var(--accent); }

/* Today's row was a filled bar with a pill on it, which on a page with no
   other fill and no other pill was two pieces of furniture marking one line.
   Weight and full ink mark it instead, and the label becomes the tracked
   capitals every other small label on this layout is set in. */
[data-layout="atelier"] .hours__row.is-today { background: transparent; }
[data-layout="atelier"] .hours__today {
  padding: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
  font-weight: 600;
  letter-spacing: .14em;
  opacity: .7;
}
[data-layout="atelier"] .gallery figure { border-radius: var(--radius); }
[data-layout="atelier"] .gallery figure:hover img { transform: none; }
[data-layout="atelier"] .map { border-radius: var(--radius); }

/* ------------------------------------------ atelier: how a page closes --- */

/*
   TWO CLOSING BANDS THAT ARE NOT THE SAME BAND TWICE.

   A page ends with either the document's own cta section or the generic
   closer. Both are a heading on the left and a filled button on the right, so
   on a five page site the reader met the same slab five times and could not
   tell which of the two they were looking at.

   The cta band keeps the accent ground and stays the loud one: it is the only
   block of colour in the whole layout, and on a pale sand carrying the page's
   own ink at 9.7:1 that is exactly where a neutral accent earns its keep.

   The closer becomes its own thing: the page ground, an ink rule across the
   top of it, and the ask set as a line of type with the two actions under it
   rather than beside it. That is the colophon at the foot of a printed sheet,
   not a second call to action, and it stops the last two screens of every
   page being one shape drawn twice.
*/
[data-layout="atelier"] .cta-band h2 { font-size: clamp(1.8rem, 4vw, 2.8rem); }

[data-layout="atelier"] .closer,
[data-layout="atelier"] .section--alt + .closer { background: var(--page); }
[data-layout="atelier"] .closer { border-top: 0; }
[data-layout="atelier"] .closer__inner {
  display: block;
  border-top: 1px solid var(--ink);
  padding-top: clamp(22px, 3vw, 32px);
}
[data-layout="atelier"] .closer h2 { font-size: clamp(1.5rem, 3.2vw, 2.1rem); max-width: 20ch; }
[data-layout="atelier"] .closer p { max-width: 52ch; }
[data-layout="atelier"] .closer__actions { margin-top: clamp(24px, 3.4vw, 34px); }
/* Level with the heading, not oversized. The band is a footnote to the page
   above it and the cta band is the ask. */
[data-layout="atelier"] .closer__actions .btn--accent {
  min-height: 0;
  padding: 16px 28px;
  font-size: 14px;
}

/* ------------------------------------------- atelier: how a page opens --- */

/*
   FIVE PAGES THAT DO NOT OPEN THE SAME WAY.

   Variants are dealt per site, so every sub-page of one site gets the same
   page head: breadcrumb, title, one line of lede, on a masthead grid. That is
   right for the two pages whose lede is a real sentence about what is on
   them, and it is filler on the two that are a wall of photographs and a room
   full of people, where the shared lang string says something the title
   already said.

   So the picture pages open on type alone at nearly twice the size, with the
   line of lede dropped and the rule under the head doing the closing. It
   needs the page's name on the body element, which show.blade.php now prints
   for every layout.
*/
[data-layout="atelier"] .pagehead h1 { font-size: clamp(2.3rem, 7vw, 4.2rem); max-width: 20ch; }
[data-layout="atelier"] .pagehead { padding-bottom: clamp(30px, 5vw, 52px); }

[data-layout="atelier"]:is([data-page="gallery"], [data-page="about"]) .pagehead h1 {
  font-size: clamp(3rem, 11vw, 6.4rem);
  max-width: 14ch;
}
[data-layout="atelier"]:is([data-page="gallery"], [data-page="about"]) .pagehead__lede { display: none; }
[data-layout="atelier"]:is([data-page="gallery"], [data-page="about"]) .pagehead {
  padding-bottom: clamp(40px, 7vw, 88px);
  border-bottom-color: var(--ink);
}

/* ------------------------------------------- atelier: the fee schedule --- */

/*
   A FEE SCHEDULE, NOT A MENU CARD.

   The price section ships as a restaurant menu: the item on the left, a row
   of dots crossing the gap, the figure on the right, the description in
   italic underneath, and the whole thing centred in a 720px column. That is
   the correct design for a wine list and it is the wrong design for what an
   architect charges, which is a schedule somebody reads down a column of
   figures in and compares.

   What replaces it is a table. The group is named in the margin, the entries
   run in a column beside it, the price is a right hand column of its own in
   tabular figures so hundreds line up under hundreds, and the leader dots go:
   with the figures in a real column there is nothing left for the eye to be
   led across.

   The group name also loses the 2px accent bar the base rule draws under it.
   That bar is a card's mark rather than a page's, and a 2px bar of a pale
   neutral measures 2.07:1 on paper, which is a mark nobody can see anyway.
   The previous fix here restated only the border WIDTH and COLOUR against a
   `border-bottom: 0` shorthand, which had already reset the style to none, so
   it painted nothing at all while the accent bar it claimed to remove carried
   on being drawn by an ::after under a different selector.
*/
[data-layout="atelier"] .menu-groups {
  background: transparent;
  padding: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  /* One column, whatever the width. The shared rule puts the groups two
     abreast above 860px, which on this layout means a schedule with its own
     margin column inside half a page: every second name broke over two lines
     and the figures stopped being a column anybody could read down. A fee
     schedule is one list. */
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(36px, 5vw, 64px);
}
[data-layout="atelier"] .menu-group__name {
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  font-family: var(--font);
  color: var(--ink-2);
}
[data-layout="atelier"] .menu-group__name::after { display: none; }
[data-layout="atelier"] .menu-group__desc {
  font-style: normal;
  margin: 10px 0 0;
  max-width: 42ch;
}
/* The rule opens the whole group, not just the column of entries, so at the
   wider measure it runs across the name in the margin and the schedule beside
   it as one line. */
[data-layout="atelier"] .menu-group {
  border-top: 1px solid var(--ink);
  padding-top: clamp(14px, 2vw, 20px);
}
[data-layout="atelier"] .menu-list { margin-top: 14px; }
[data-layout="atelier"] .menu-item {
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
}
[data-layout="atelier"] .menu-item:last-child { border-bottom: 1px solid var(--line); }
[data-layout="atelier"] .menu-item__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: clamp(20px, 3vw, 40px);
  align-items: baseline;
}
[data-layout="atelier"] .menu-item__lead { display: none; }
[data-layout="atelier"] .menu-item__name { font-weight: 500; font-size: 1.02rem; }
[data-layout="atelier"] .menu-item__price {
  font-weight: 500;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: .01em;
}
[data-layout="atelier"] .menu-item__desc {
  font-style: normal;
  text-align: left;
  max-width: 54ch;
  margin-top: 5px;
}
[data-layout="atelier"] .menu-note { border-top-color: var(--line); }

/* ------------------------------------------------ atelier: the masthead --- */

/*
   A LETTERHEAD RATHER THAN AN APPLICATION BAR.

   The bar arrives with pill shaped navigation links, a blurred translucent
   ground once it sticks and a drop shadow under it, which is the chrome of an
   app and not of a practice's own paper. Here the name is set in the display
   face at the weight the pairing actually ships, the locality under it is a
   tracked label, the links are a running head in small capitals with no
   backgrounds behind them, and the stuck state is flat paper closed by a
   hairline. Nothing in it is translucent and nothing is raised.
*/
[data-layout="atelier"] .header-inner { min-height: 84px; gap: clamp(20px, 3vw, 40px); }
[data-layout="atelier"] .brand__name { font-weight: var(--heading-weight-strong); font-size: 18px; letter-spacing: -0.01em; }
[data-layout="atelier"] .brand__meta {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
}
[data-layout="atelier"] .nav { gap: clamp(14px, 2vw, 30px); }
[data-layout="atelier"] .nav a {
  border-radius: 0;
  padding: 8px 0;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
}
[data-layout="atelier"] .nav a:hover { background: none; }
[data-layout="atelier"] .site-header.is-stuck {
  background: var(--page);
  backdrop-filter: none;
  box-shadow: none;
  border-bottom-color: var(--line);
}
/* The drawer the minimal header opens is the same page, so it is set on the
   same paper: names in the display face, a hairline under each. */
[data-layout="atelier"] .mobile-nav a { letter-spacing: -0.015em; }

/* ------------------------------------------------ atelier: the colophon --- */

/*
   THE SITE ENDS ON PAPER, NOT ON A BLACK SLAB.

   The shared footer is a band of --deep with four columns of white at half
   opacity on it. Three layouts already turn it back onto a light ground and
   this is the fourth, because a practice's sheet does not finish with a black
   rectangle: it finishes with the imprint. An ink rule opens it, the name is
   set at reading size rather than as a second logo, and the labels over the
   columns take the same small tracked capitals as the fee schedule's groups,
   so the last thing on the page rhymes with something earlier on it rather
   than arriving from a different design.
*/
[data-layout="atelier"] .site-footer {
  background: var(--page);
  color: var(--ink-2);
  border-top: 1px solid var(--ink);
  padding: clamp(36px, 5vw, 56px) 0 40px;
}
[data-layout="atelier"] .site-footer__name { color: var(--ink); font-weight: var(--heading-weight-strong); }
[data-layout="atelier"] .site-footer__heading { color: var(--ink-2); font-weight: 600; letter-spacing: .16em; }
[data-layout="atelier"] .site-footer__top,
[data-layout="atelier"] .site-footer__legal { border-color: var(--line); }
[data-layout="atelier"] .site-footer__legal { color: var(--ink-2); }
[data-layout="atelier"] .site-footer__links a:hover,
[data-layout="atelier"] .site-footer__contact a:hover,
[data-layout="atelier"] .site-footer__by a:hover { color: var(--ink); }
[data-layout="atelier"] .site-footer__social a { color: var(--ink-2); }
[data-layout="atelier"] .site-footer__social a:hover { color: var(--ink); background: var(--line); }
[data-layout="atelier"] .site-footer__hours dt { color: var(--ink-2); }
[data-layout="atelier"] .site-footer__hours .is-today dt,
[data-layout="atelier"] .site-footer__hours .is-today dd { color: var(--ink); }

/* ------------------------------------------------- atelier: the controls --- */

/*
   WHERE A NEUTRAL ACCENT STOPS BEING USABLE ALTOGETHER.

   A form field is a user interface component, so its boundary owes a reader
   3:1 against whatever it sits on, and the shared rules give it --line at
   1.16:1 on paper and 1.08:1 on the sand band. On the six saturated layouts
   the focus state rescues it, because focus swaps the border to the accent
   and lays a ring of the accent at 20 per cent around it. Here the accent is
   #c1b2a3, so focus swapped an invisible edge for a slightly warmer invisible
   edge: 1.95:1 on paper, 1.8:1 on sand, and a halo nobody can see.

   So the field takes --line-edge unfocused (3.9:1 on paper, 3.3:1 on sand)
   and the page's own ink on focus, with a real outline rather than a tinted
   glow. The outline is drawn on :focus rather than :focus-visible because it
   is replacing a :focus rule, and the two would otherwise disagree about
   which is showing.
*/
[data-layout="atelier"] .bfield input,
[data-layout="atelier"] .bfield select,
[data-layout="atelier"] .bfield textarea {
  background: var(--page);
  border-color: var(--line-edge);
}
[data-layout="atelier"] .bfield input:focus,
[data-layout="atelier"] .bfield select:focus,
[data-layout="atelier"] .bfield textarea:focus {
  border-color: var(--ink);
  box-shadow: none;
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/*
   The two controls that float over the page rather than sitting in it.

   Both were filled with the raw accent, which is 2.07:1 against paper with no
   border to fall back on: a button with no edge. Their text was readable at
   9.7:1 and the button itself was not findable, which is the failure the
   neutral accent makes easy to miss. They take the same ink fill as the
   primary button, so the page has one filled control and two smaller copies
   of it rather than three different ideas.
*/
[data-layout="atelier"] .chat__fab,
[data-layout="atelier"] .chat__send {
  background: var(--ink);
  color: var(--page);
}
[data-layout="atelier"] .chat__fab {
  border-radius: var(--radius);
  box-shadow: 0 2px 14px rgb(0 0 0 / .18);
  font-weight: 600;
}
[data-layout="atelier"] .skip-link { background: var(--ink); color: var(--page); }

/* ------------------------------------------ atelier: the two column widths --- */

@media (min-width: 560px) {
  /* One column of facts on a phone, two above it. The hairline is a top rule
     only, so it wraps at any count without a rule stranded mid row. */
  [data-layout="atelier"] .features { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/*
   ON A PHONE THE WORDS COME BEFORE THE PICTURE.

   Below 860 the hero is one column in source order, and source order puts the
   photograph between the headline and the buttons. A 4:5 crop at 335px wide
   is 419px tall, which with the bar, the eyebrow, a two line headline and the
   rule under it put the top of the primary button past 800px on a 375x812
   screen: the one thing the page is asking the reader to do was below the
   fold on the page that asks it.

   The figure is not focusable and carries nothing a screen reader reads
   before the buttons, so reordering the boxes changes what is seen and not
   what is announced. The crop opens out at the same time, because a portrait
   plate is a composition on a spread and a phone has no spread.
*/
@media (max-width: 859px) {
  .hero--atelier .hero__inner { order: 1; }
  .hero--atelier .hero__figure { order: 2; margin-top: clamp(30px, 7vw, 44px); }
  .hero--atelier .hero__figure img { aspect-ratio: 4 / 3.4; }
}

@media (min-width: 860px) {
  [data-layout="atelier"] .feature { flex-direction: column; }

  /*
     A PORTRAIT PLATE, NOT HALF THE PAGE.

     The picture used to take exactly half the width at 4/3.6, which is the
     rectangle .hero--bold draws, byte for byte. So on the width where anybody
     judges a design, the quiet layout's photograph was the poster layout's
     photograph and the portrait crop this block is named for existed only on
     the about pair.

     Narrowing the picture's column to 0.78 of the text's is what buys the
     crop back: at the 1180 wrap that is a 460px plate, and 4:5 of 460 is
     575px tall, which is shorter than the 4/3.6 half-width picture it
     replaces. The reader gets a portrait photograph, a shorter hero and the
     buttons higher up the screen out of the same change.
  */
  .hero--atelier .hero__grid {
    grid-template-columns: minmax(0, .78fr) minmax(0, 1fr);
    gap: clamp(44px, 6vw, 88px);
    /* Both columns start on the same line. Centred, the standfirst floated in
       the middle of a 575px plate with two hundred pixels of nothing above it;
       bottom aligned it fell most of the way down the first screen. Started,
       the first line of the standfirst and the top edge of the photograph are
       the same rule, which is what makes the two columns read as a spread. */
    align-items: start;
  }
  .hero--atelier .hero__figure img { aspect-ratio: 4 / 5; }

  /* The head is the full measure; the standfirst and the actions are a column
     in the right hand track, so the headline is the only thing on the page
     that runs edge to edge. */
  /* Aligned at the foot, not at the head. Two blocks of type set from the same
     top edge are two columns that happen to start together; dropped onto the
     same baseline they are a masthead, which is what the sub-page head above
     already does and what makes the two read as one design rather than two. */
  [data-layout="atelier"] .wrap > .section-head {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    column-gap: clamp(40px, 6vw, 96px);
    align-items: end;
  }
  [data-layout="atelier"] .wrap > .section-head > h2 { grid-column: 1; }
  [data-layout="atelier"] .wrap > .section-head > p { grid-column: 2; margin: 0 0 .45em; }

  /* The fee schedule's group named in the margin, the entries in a column
     beside it. A wide left margin with the text column not filling the page
     is the whole shape of this layout, and the price list is the one place it
     can be literal about it. */
  [data-layout="atelier"] .menu-group {
    display: grid;
    grid-template-columns: minmax(0, .42fr) minmax(0, 1fr);
    /* Stated, or the entry column's spare height is shared out between the two
       rows and the group's note floats away from the name it belongs to. */
    grid-template-rows: auto 1fr;
    column-gap: clamp(32px, 5vw, 76px);
    align-items: start;
  }
  [data-layout="atelier"] .menu-group__name { grid-column: 1; grid-row: 1; }
  [data-layout="atelier"] .menu-group__desc { grid-column: 1; grid-row: 2; }
  [data-layout="atelier"] .menu-list { grid-column: 2; grid-row: 1 / span 2; margin-top: 0; }

  /*
     Top aligned, not centred.

     Centring is right when the two halves are about the same height, which is
     what the reference's own pairs are: two short paragraphs beside a
     portrait. A practice that writes four paragraphs about itself does not
     get that, and centring a 600px picture against 800px of prose leaves the
     picture floating with a hundred pixels of nothing above it and a hundred
     below, level with neither the eyebrow that opens the block nor the last
     line that closes it. Aligned at the top, the picture starts on the same
     line as the eyebrow and the block reads as one spread. */
  [data-layout="atelier"] .feature-pair {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: clamp(40px, 6vw, 88px);
    align-items: start;
  }
  [data-layout="atelier"] .feature-pair__body { align-self: start; }
  [data-layout="atelier"] .feature-pair--reverse .feature-pair__media { grid-column: 2; grid-row: 1; }
  [data-layout="atelier"] .feature-pair--reverse .feature-pair__body { grid-column: 1; grid-row: 1; }
}

/* ------------------------------------------------------------- projects --- */
/* Work this business has finished, one entry per job.

   The section that separates a firm that does the work from a firm that
   describes it. Everything here is a fact about one job, so the type is set to
   be read rather than admired: the facts in tabular figures on a hairline, the
   photograph subordinate to them in the ledger, equal to them in the sheet.

   No cards, no shadows, no radius the document did not ask for. A row of
   rounded white boxes is the shape of a template and the shape of nothing
   else. */

.projects { display: grid; }

/* --- ledger: a ruled list, the picture small and to one side --------------- */
.projects--ledger { gap: 0; }

.project-line {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  padding: clamp(22px, 3vw, 34px) 0;
  border-top: 1px solid var(--line);
}
.projects--ledger .project-line:last-child { border-bottom: 1px solid var(--line); }

.project-line__media {
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--surface);
}
.project-line__media img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4 / 3; display: block; }

.project-line__body h3 {
  font-size: clamp(1.15rem, 2.2vw, 1.45rem);
  line-height: 1.2;
}

/* The facts on one line, separated by a rule rather than by a bullet: a bullet
   between two words is a list of two things, and these are one fact in four
   parts. */
.project-line__facts,
.project-row__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-top: 8px;
  font-size: 14px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.project-line__facts span,
.project-row__facts span { display: inline-flex; align-items: center; }
.project-line__facts span + span::before,
.project-row__facts span + span::before {
  content: "";
  width: 1px;
  height: 11px;
  margin-right: 14px;
  background: var(--line);
}

.project-line__note {
  margin-top: 12px;
  max-width: 62ch;
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--ink-2);
}

@media (min-width: 760px) {
  .project-line { grid-template-columns: 240px 1fr; gap: clamp(24px, 3vw, 40px); align-items: start; }
}

/* --- sheet: one project per band, the portfolio spread -------------------- */
.projects--sheet { gap: clamp(52px, 7vw, 96px); }

.project { display: grid; gap: clamp(20px, 3vw, 34px); align-items: start; }
.project__media { margin: 0; overflow: hidden; border-radius: var(--radius); background: var(--surface); }
.project__media img { width: 100%; display: block; aspect-ratio: 3 / 2; object-fit: cover; }

.project__body h3 { font-size: clamp(1.4rem, 3vw, 2rem); line-height: 1.15; }
.project__body > p { margin-top: 14px; max-width: 58ch; font-size: 16px; line-height: 1.7; color: var(--ink-2); }

/* A definition list, because that is what it is: four labels and four values
   about one thing. Drawn as a table so the values line up down the column. */
.project__facts {
  display: grid;
  gap: 0;
  margin-top: 16px;
  border-top: 1px solid var(--line);
}
.project__facts > div {
  display: grid;
  grid-template-columns: minmax(96px, 26%) 1fr;
  gap: 14px;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
}
.project__facts dt {
  font-size: 12.5px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.project__facts dd { margin: 0; font-size: 15px; color: var(--ink); font-variant-numeric: tabular-nums; }

.project__drawing { margin: 22px 0 0; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--page); }
.project__drawing img { width: 100%; display: block; }

@media (min-width: 900px) {
  .project { grid-template-columns: 1.25fr 1fr; gap: clamp(32px, 4vw, 60px); }
  /* Alternating, so a run of them is a spread rather than a stack. */
  .projects--sheet .project:nth-child(even) .project__media { grid-column: 2; grid-row: 1; }
  .projects--sheet .project:nth-child(even) .project__body { grid-column: 1; grid-row: 1; }
}

/* --- index: the facts and no photographs ---------------------------------- */
.projects--index { gap: 0; list-style: none; counter-reset: proj; padding: 0; margin: 0; }

.project-row {
  counter-increment: proj;
  padding: clamp(18px, 2.4vw, 26px) 0 clamp(18px, 2.4vw, 26px) clamp(38px, 5vw, 56px);
  border-top: 1px solid var(--line);
  position: relative;
}
.projects--index .project-row:last-child { border-bottom: 1px solid var(--line); }
.project-row::before {
  content: counter(proj);
  position: absolute;
  left: 0;
  top: clamp(19px, 2.5vw, 28px);
  font-size: 13px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.project-row h3 { font-size: clamp(1.05rem, 2vw, 1.3rem); line-height: 1.25; }
.project-row__body { margin-top: 10px; max-width: 62ch; font-size: 15.5px; line-height: 1.65; color: var(--ink-2); }

/* ----------------------------------------------------------------- team --- */
/* The people. A portrait or nothing: a stock photograph of a smiling stranger
   is a picture of somebody who does not work here, captioned with the name of
   somebody who does. */

.team { list-style: none; padding: 0; margin: 0; }

.team--row { display: grid; gap: clamp(24px, 3vw, 38px); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 760px) { .team--row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1060px) { .team--row { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.person__portrait { margin: 0 0 14px; overflow: hidden; border-radius: var(--radius); background: var(--surface); }
.person__portrait img { width: 100%; display: block; aspect-ratio: 4 / 5; object-fit: cover; }

/* Somebody with no portrait yet. One letter on the surface, the same height a
   portrait would be, so the row does not go ragged while a client is still
   finding their photographs. */
.person__noportrait {
  display: grid;
  place-items: center;
  margin: 0 0 14px;
  aspect-ratio: 4 / 5;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-family: var(--font-heading);
  font-size: clamp(2.2rem, 5vw, 3.2rem);
  font-weight: var(--heading-weight);
  color: var(--ink-3);
}

.person__name { font-weight: 600; font-size: 16px; line-height: 1.3; }
.person__role { margin-top: 2px; font-size: 14.5px; color: var(--ink-2); }
.person__credential { margin-top: 4px; font-size: 13.5px; color: var(--ink-3); }
.person__body { margin-top: 9px; font-size: 14.5px; line-height: 1.6; color: var(--ink-2); }

/* --- lead: the first person large, for a business that is one person ------ */
.team--lead { display: grid; gap: clamp(24px, 3vw, 38px); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 900px) {
  .team--lead { grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: start; }
  .team--lead .person:first-child { grid-column: span 2; grid-row: span 2; }
  .team--lead .person:first-child .person__name { font-size: 20px; }
  .team--lead .person:first-child .person__role { font-size: 16px; }
}

/* --- list: names and no pictures ----------------------------------------- */
.team--list { display: grid; gap: 0; }

.person-row { padding: clamp(16px, 2.2vw, 22px) 0; border-top: 1px solid var(--line); }
.team--list .person-row:last-child { border-bottom: 1px solid var(--line); }
.person-row__name { font-weight: 600; font-size: 16.5px; }
.person-row__role { margin-top: 3px; font-size: 14.5px; color: var(--ink-2); }
.person-row__credential { color: var(--ink-3); }
.person-row__credential::before { content: "\00a0\00b7\00a0"; }
.person-row__credential.is-alone::before { content: none; }
.person-row__body { margin-top: 8px; max-width: 62ch; font-size: 15px; line-height: 1.65; color: var(--ink-2); }

@media (min-width: 760px) {
  .person-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr); gap: clamp(20px, 3vw, 40px); align-items: baseline; }
  .person-row__role { margin-top: 0; }
  .person-row__body { grid-column: 2; margin-top: 6px; }
}

/* A logo the business already had. Capped in height rather than in width, so a
   wide wordmark and a square mark sit on the same baseline as the type they
   replace. */
.brand--logo { display: inline-flex; align-items: center; }
.brand__logo { height: 34px; width: auto; max-width: 220px; object-fit: contain; }
@media (min-width: 860px) { .brand__logo { height: 40px; max-width: 280px; } }

/* ============================================================== classic ====
   The house style, and until now the absence of one.

   Fifteen sites are drawn with this layout, more than with any other, and it
   had no block in this file at all. The architecture is "the base rules are
   classic, every other layout restates what differs", which sounds tidy and
   means classic is definitionally whatever is left over when nobody has an
   opinion. Atelier committed a hundred rules of register. Classic had two
   paddings and a colour reset, and it shared all three with dark. That is the
   platform reason a third of the demos read as the builder's default: they
   were the default.

   WHAT IT IS NOW. A well-made local business site. Confident, plain, printed
   rather than assembled. Four decisions carry it and none of them is a
   flourish.

   1. THE OPENING IS A COMPOSITION, NOT A PHOTOGRAPH WITH WORDS ON IT. Classic
      shared dark's hero branch, so the two layouts were one skeleton in two
      colourways: 92svh of whatever picture the business happened to send, a
      scrim over the whole of it, and the name in the bottom left corner. On a
      375px phone that is 747 pixels of unvetted photograph before a single
      word, and measured over a near-white clinic interior the eyebrow came
      out at 3.05:1. Now the picture is a letterbox band across the top, the
      band ends, and the masthead is set on the page's own paper underneath
      it, where the ink is the ink and no gradient is protecting anything.
      Dark keeps the corner treatment and the two are finally two layouts.

   2. RULED, NOT BANDED. Every site in the file ran white hero, white
      services, grey reviews, dark gallery, white about, dark contact, grey
      closer, dark footer, in that order, because the ground is a constant of
      the section TYPE. That stripe pattern is the strongest "same template"
      cue on a page, readable from six feet away with the words out of focus.
      Here the grey band is gone: the alternate ground is the page, sections
      are separated by a full-bleed hairline, and the page is one sheet of
      paper from the masthead to the footer.

   3. ONE BAND OF COLOUR. With the banding gone, the dark section is a
      decision rather than a rhythm, so a page gets exactly one. Where a
      document files two (the front page files the gallery and the contact
      block; so does the contact page) the second and any after it come back
      onto the paper. The other colour on the page is the accent rule that
      closes it, three pixels above the footer.

   4. A HORIZONTAL GRID, AND AIR. Heads run on a wide/narrow pair with the
      standfirst hung off a two pixel rule in the second column, the same
      shape the sub-page masthead already uses, so the five pages of one site
      are one system rather than five stamps. Everything that was a card is a
      ruled entry hung under an ink rule, and the reading leading goes to 1.7.

   Specificity note: every selector here is at least [data-layout="classic"] X,
   which is (0,2,0) and beats the plain rules inside the 860px and 1080px media
   queries above at every width. Anything that has to change WITH the viewport
   is written into this block's own media queries at the end.
   ========================================================================= */

body[data-layout="classic"] {
  /* A missing cut must fail rather than be faked. The type catalogue is
     honest now and the coverage test keeps it that way, but a browser will
     still smear a 700 sideways if anything ever asks a 400-only face for a
     bold. With synthesis off the heading simply stays at the weight the face
     has, which is the honest answer. */
  font-synthesis: none;
}

/* -------------------------------------------------------- classic: rhythm --- */

/* The alternate ground is the page. What separates two sections is a rule
   across the whole width, not a change of colour: a printed page marks a new
   subject with a rule and keeps the paper. Stated for both grounds because
   with the tint gone every seam in the document is now a same-ground seam. */
[data-layout="classic"] .section--alt { background: var(--page); }
[data-layout="classic"] .section:not(.section--dark) + .section:not(.section--dark) {
  border-top: 1px solid var(--line);
}

/*
   AND THE SEAM KEEPS ITS AIR.

   There is a rule near the top of this file that halves the padding where a
   document files two sections on the same ground next to each other, because
   otherwise the two read as one very tall band with a hole in it. That was the
   right fix when the alternative was a colour change; here the boundary is
   drawn by an actual rule, and halving the padding on top of it squeezed the
   two subjects together instead. Full rhythm on both sides of the rule.
*/
[data-layout="classic"] .section--alt + .section--alt,
[data-layout="classic"] .section:not(.section--alt, .section--dark) + .section:not(.section--alt, .section--dark) {
  padding-top: clamp(64px, 9vw, 118px);
}
[data-layout="classic"] .section--alt:has(+ .section--alt),
[data-layout="classic"] .section:not(.section--alt, .section--dark):has(+ .section:not(.section--alt, .section--dark)) {
  padding-bottom: clamp(64px, 9vw, 118px);
}

/*
   ONE BAND OF COLOUR PER PAGE, AND A GUARD THAT KEEPS IT THAT WAY.

   Which sections sit on the dark ground is hardcoded per section type in the
   templates: the gallery and the contact block, and nothing else. On the
   eleven documents currently drawn with this layout that already works out at
   no more than one per page, and on the front page at none, which is exactly
   the rhythm the register wants: a photograph at the top, paper and rules all
   the way down, one band on the page that has one, and the footer.

   What this rule does is stop a document that files both on one page, which a
   single-page site would, from getting two. Measured: it fires on none of the
   fifty-one URLs today. It is here so that the claim above stays true when
   somebody writes a document that breaks it, not because anything on disk
   needs it now.

   The base block already declares the dark section's ink as tokens, with the
   note that "a layout that would rather have them light only redefines the
   tokens", so that is all this does.
*/
[data-layout="classic"] .section--dark ~ .section--dark {
  --on-deep: var(--ink);
  --on-deep-2: var(--ink-2);
  --on-deep-3: var(--ink-3);
  --panel: var(--surface);
  --panel-line: var(--line);
  --panel-today: var(--accent-soft);
  background: var(--page);
  color: var(--ink);
  border-top: 1px solid var(--line);
}
/* Three things inside a dark band are drawn in white directly rather than
   through a token, so they follow it back onto the paper by hand. */
[data-layout="classic"] .section--dark ~ .section--dark .stars__base { color: rgb(var(--primary-rgb) / .18); }
[data-layout="classic"] .section--dark ~ .section--dark .btn--ghost {
  --btn-ink: var(--ink);
  border-color: var(--ink-3);
  backdrop-filter: none;
}
[data-layout="classic"] .section--dark ~ .section--dark .btn--ghost:hover { background: var(--surface); border-color: var(--ink); }

/* ------------------------------------------- classic: how a section opens --- */
/*
   THE ONE THING EVERY PAGE IN THIS FILE DID FOUR TO SIX TIMES.

   A twelve pixel tracked eyebrow behind a 26x2 block of accent, a serif h2,
   and a line of grey lede, stacked in a 640px column at the left of a 1180px
   page. Fifteen section templates emit that eyebrow unconditionally, two
   layouts edited it, and classic took it verbatim. Drawn once it is a
   heading; drawn six times down one scroll it is the stamp, because the
   furniture above the words is the same object every time and the reader
   cannot tell the fee page from the gallery page without reading.

   A page is allowed one eyebrow. The hero's names the district and the
   sub-page masthead carries the business name, so every other one goes: each
   was repeating the navigation label immediately above a heading that said
   the same thing in larger type.

   What marks a section instead is the grid. The heading takes the wide column
   at a size that can carry a full-bleed page, and the standfirst hangs off a
   two pixel rule in the narrow one, level with the heading's own top. Nothing
   is drawn above the heading, which is the difference between this and the
   practice's paper further down the file: there the rule opens the head and
   the heading hangs under it; here the rule belongs to the note beside it.
*/
[data-layout="classic"] .section .eyebrow { display: none; }

[data-layout="classic"] .section-head { max-width: none; margin-bottom: clamp(34px, 4.6vw, 54px); }
[data-layout="classic"] .section-head h2,
[data-layout="classic"] .about__body h2,
[data-layout="classic"] .booking__intro h2 {
  font-size: clamp(2rem, 5.1vw, 3.25rem);
  line-height: 1.04;
  max-width: 20ch;
}
[data-layout="classic"] .section-head h2.h2--small { font-size: clamp(1.5rem, 3.2vw, 2rem); }
/* Measure and leading only. Restating the colour here would land after the
   rule that turns the standfirst white on a dark band. */
[data-layout="classic"] .section-head p { max-width: 46ch; line-height: 1.7; }

/* Inside the FAQ's own column the head keeps its stack: splitting a 300px
   column again leaves a heading and a paragraph of 140px each. */
[data-layout="classic"] .faq-grid .section-head { max-width: 34ch; }
[data-layout="classic"] .faq-grid .section-head h2 { font-size: clamp(1.7rem, 3.4vw, 2.3rem); }

/* -------------------------------------------------------- classic: type --- */

/* Generous leading is most of what separates a page somebody set from a page
   something generated. 1.7 on every running paragraph, 1.72 on the long ones. */
[data-layout="classic"] .service p,
[data-layout="classic"] .feature p,
[data-layout="classic"] .step p,
[data-layout="classic"] .svc-row__desc,
[data-layout="classic"] .svc-index__desc,
[data-layout="classic"] .menu-item__desc,
[data-layout="classic"] .faq__a,
[data-layout="classic"] .faq__body { line-height: 1.7; }
[data-layout="classic"] .about__body p,
[data-layout="classic"] .prose p { line-height: 1.72; }
[data-layout="classic"] .about__body,
[data-layout="classic"] .prose { max-width: 66ch; }

/* ----------------------------------------------------- classic: the lists --- */
/*
   NOTHING ON THIS PAGE IS A CARD.

   The three-up grid of bordered, rounded, drop-shadowed panels that lifts two
   pixels on hover is the single most recognisable object on a generated site,
   and it was drawing the services, the features and the process on every one
   of these pages. What replaces it is an entry hung under a two pixel rule of
   the page's own ink: same grid, same order, no box. In a row the three rules
   land on one line with the column gap between them, which is the horizontal
   grid this layout is built on, made visible.

   THE TINTED ICON SQUARE GOES WITH THEM. A rounded square of --accent-soft
   with a line icon inside it is the other half of that object, and at three
   or six a side it is the loudest colour on a page whose argument is that the
   colour appears once. The service name is what a reader came for.
*/
[data-layout="classic"] .services,
[data-layout="classic"] .features { gap: 0 clamp(26px, 3.2vw, 48px); }

[data-layout="classic"] .service,
[data-layout="classic"] .feature,
[data-layout="classic"] .steps .step {
  background: transparent;
  border: 0;
  border-top: 2px solid var(--ink);
  border-radius: 0;
  box-shadow: none;
  padding: 18px 0 clamp(26px, 3vw, 40px);
}
[data-layout="classic"] .service:hover {
  transform: none;
  box-shadow: none;
  border-top-color: var(--accent);
}
[data-layout="classic"] .service__icon,
[data-layout="classic"] .feature__icon,
[data-layout="classic"] .svc-row__icon { display: none; }

[data-layout="classic"] .service h3,
[data-layout="classic"] .feature h3 { font-size: 1.16rem; }
/* The price and the minutes were pinned to the foot of a card on a hairline.
   With no card to pin to they sit under the description on the same rule, and
   the figures take tabular widths so a row of them lines up digit under
   digit. */
[data-layout="classic"] .service__meta {
  margin-top: 14px;
  padding-top: 12px;
  min-height: 0;
  font-variant-numeric: tabular-nums lining-nums;
}

/* The zebra banded rows lose their tint for the same reason the grey section
   band went: an alternating fill is a table's decoration, and the rule under
   each row is already saying where one entry ends. */
[data-layout="classic"] .svc-row { border-top: 2px solid var(--ink); margin-inline: 0; padding-inline: 0; }
[data-layout="classic"] .svc-row:nth-child(even) { background: transparent; }
[data-layout="classic"] .svc-row:last-child { border-bottom: 2px solid var(--ink); }
[data-layout="classic"] .svc-row__price { font-variant-numeric: tabular-nums lining-nums; }

/* The printed index keeps its folio, in the page's quiet ink rather than in
   the accent: the numeral is the entry's address and the name beside it is
   the subject. The rules go to two pixels with the rest of the layout. */
[data-layout="classic"] .svc-index__item { border-top: 2px solid var(--ink); }
[data-layout="classic"] .svc-index__item:last-child { border-bottom: 2px solid var(--ink); }
[data-layout="classic"] .svc-index__num {
  color: var(--ink-3);
  font-family: var(--font);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .16em;
  line-height: 1.6;
}
[data-layout="classic"] .svc-index__price {
  color: var(--ink);
  font-variant-numeric: tabular-nums lining-nums;
}

/* The strip of facts is already hairlines and no chips, so all it takes is the
   band's own two edges in the layout's ink. The interior rules are left to the
   shared block, which knows whether the items are stacked, two abreast or in
   one row, and which side each rule belongs on. */
[data-layout="classic"] .feat-strip { border-block: 2px solid var(--ink); }

/*
   THE PLACES SERVED ARE A LIST, NOT A ROW OF PILLS.

   Rounded capsules with a coloured dot in front of each are a tag cloud, and a
   tag cloud is the shape of a filter control rather than of a statement about
   where a business will drive. Set as a directory on rules, in columns, the
   same list says the same thing and reads as part of the page.
*/
[data-layout="classic"] .areas {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 0 clamp(20px, 2.5vw, 44px);
}
[data-layout="classic"] .chip {
  display: block;
  padding: 12px 0;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  color: var(--ink);
}
[data-layout="classic"] .chip::before { display: none; }

/* ------------------------------------- classic: process, as information --- */
/*
   A numbered disc is a diagram of a process, not a process. The timeline
   variant, which threads those discs on a vertical line, is out of this
   layout's pool for that reason, and what is left is read as a schedule: the
   stage number as a small tracked label under the rule, the stage, and what
   happens in it. Nothing is drawn that a printed page could not print.
*/
[data-layout="classic"] .steps .step__num {
  display: block;
  width: auto;
  height: auto;
  background: none;
  border-radius: 0;
  color: var(--ink-3);
  font-family: var(--font);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .16em;
  line-height: 1.6;
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="classic"] .steps .step h3 { font-size: 1.16rem; }
[data-layout="classic"][data-v-steps="row"] .steps .step { gap: 8px; }

/* ------------------------------------------- classic: what people wrote --- */
/*
   A review set as a card, with a circular initial in a tinted disc beside the
   name, is the same object as the brand mark drawn round, and the whole
   section then reads as the widget the copy above it is trying not to be. A
   printed page attributes a quotation with a name and a date under a rule and
   trusts the reader to know what that means.
*/
[data-layout="classic"] .reviews .review {
  background: transparent;
  border: 0;
  border-top: 2px solid var(--ink);
  border-radius: 0;
  padding: 18px 0 0;
}
[data-layout="classic"] .reviews { gap: 0 clamp(26px, 3.2vw, 48px); }
[data-layout="classic"] .review__text { line-height: 1.72; max-width: 46ch; }
[data-layout="classic"] .review__avatar { display: none; }
[data-layout="classic"] .review__author {
  padding-top: 16px;
  border-top: 1px solid var(--line);
  flex-direction: column;
  gap: 2px;
}
[data-layout="classic"] .review__when { letter-spacing: .04em; text-transform: none; font-size: 13px; font-weight: 500; }
/* The scoreboard's numeral is the one large figure the section is allowed. It
   takes tabular widths so a 4,8 and a 5,0 are the same width on two sites. */
[data-layout="classic"] .rating-summary { border-bottom-width: 2px; border-bottom-color: var(--ink); }
[data-layout="classic"] .rating-summary__score { font-variant-numeric: tabular-nums lining-nums; }

/* The pull quote loses its decorative quotation mark. A 5.4rem glyph of
   punctuation floating beside a sentence is a stock-testimonial device, and
   the sentence is perfectly capable of being a quotation on its own. */
[data-layout="classic"] .review-quote__mark { display: none; }
/* The rule goes under the quotation rather than over it. The block itself is
   held to 900px so a display-size sentence breaks where a reader can follow
   it, and a two pixel rule that stops 240px short of every other rule on the
   page is a ruled page with one line in the wrong place. */
[data-layout="classic"][data-v-reviews="quote"] .review-lines { border-top: 2px solid var(--ink); }

/* -------------------------------------- classic: the questions and areas --- */

[data-layout="classic"] .faq__row { border-top: 1px solid var(--line); }
[data-layout="classic"] .faq--plain { border-bottom-color: var(--line); }
[data-layout="classic"] .faq__q { font-size: 1.08rem; }

/* --------------------------------------- classic: the price list, a table --- */
/*
   A FEE SCHEDULE, NOT A MENU CARD.

   Prices ship as a restaurant menu: the item on the left, a row of dots
   crossing the gap, the figure on the right, and on the card variant the
   whole thing boxed three abreast. That is the right design for a wine list
   and the wrong one for what a clinic or a workshop charges, which is a
   schedule somebody reads down a column of figures in and compares against
   another firm's.

   So it becomes a table. The group is named on a two pixel rule that runs the
   full measure, the entries are rows under it, and the price is a right hand
   column of its own in tabular lining figures with a minimum width, so
   hundreds sit under hundreds and the column has an edge. With the figures in
   a real column there is nothing left for the leader dots to lead the eye
   across, so they go.
*/
/* The two column arrangement the shared rules give a wide screen is kept.
   With the leader dots gone the figure is the right hand edge of its own
   column, and a column is roughly five hundred pixels wide: at the full
   1140px measure a three word dish and its price sit a thousand pixels apart
   with nothing between them, which is the problem the dots were invented to
   solve. Two columns solve it without them, and halve the page. */
[data-layout="classic"] .menu-groups { gap: clamp(34px, 4.5vw, 58px) clamp(40px, 6vw, 80px); }
[data-layout="classic"] .menu-group { border-top: 2px solid var(--ink); padding-top: 14px; }
[data-layout="classic"] .menu-group__name {
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  font-size: clamp(1.15rem, 2.6vw, 1.45rem);
}
[data-layout="classic"] .menu-group__name::after { display: none; }
[data-layout="classic"] .menu-group__desc { margin: 8px 0 0; max-width: 52ch; font-style: normal; }
[data-layout="classic"] .menu-list { margin-top: 14px; }
[data-layout="classic"] .menu-item { padding: 13px 0; border-bottom: 1px solid var(--line); }
[data-layout="classic"] .menu-item:first-child { border-top: 1px solid var(--line); }
[data-layout="classic"] .menu-item:last-child { border-bottom: 1px solid var(--line); }
[data-layout="classic"] .menu-item__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: clamp(24px, 4vw, 56px);
  align-items: baseline;
}
[data-layout="classic"] .menu-item__lead { display: none; }
[data-layout="classic"] .menu-item__price {
  min-width: 6ch;
  text-align: right;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: .01em;
}
[data-layout="classic"] .menu-item__desc { font-style: normal; text-align: left; max-width: 58ch; margin-top: 5px; }

/* --------------------------------------------- classic: how a page opens --- */
/*
   The hero, which is the whole reason this layout stopped being dark's twin.

   The picture is a band with a bottom edge, not a ground. It runs the full
   width and under the fixed bar, so the first thing on the page is still the
   business's own room or its own work; then the band ends and the name is set
   on paper. A phone gets a shallower band, because the words are what the
   reader came for and 92svh of photograph puts them a full swipe away.
*/
[data-layout="classic"] .hero--light {
  display: block;
  align-items: stretch;
  min-height: 0;
  max-height: none;
  padding: 0 0 clamp(38px, 5.5vw, 72px);
  background: var(--page);
  overflow: visible;
}
[data-layout="classic"] .hero__band {
  position: relative;
  display: block;
  margin: 0 0 clamp(34px, 5vw, 60px);
  height: clamp(230px, 40svh, 330px);
  background: var(--deep);
  overflow: hidden;
}
[data-layout="classic"] .hero__band img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 42%;
  border-radius: 0;
}
/* A path that resolved to no file leaves the figure empty, and an empty band
   is a coloured rectangle where a photograph was promised. */
[data-layout="classic"] .hero__band:empty { display: none; }

[data-layout="classic"] .hero--light .hero__inner { max-width: none; container-type: normal; }
[data-layout="classic"] .hero--light h1 {
  font-size: clamp(2.35rem, 6.4vw, 4.4rem);
  line-height: 1.02;
  max-width: 16ch;
}
[data-layout="classic"] .hero--light .hero__sub { margin-top: 18px; max-width: 42ch; line-height: 1.65; }
/* The locality line is on paper now, so it takes the token that was measured
   for a small label on paper instead of the hero's white. */
[data-layout="classic"] .hero--light .eyebrow { color: var(--accent-strong); }

/* The facts run full width under the masthead on a rule of their own, and
   they carry the hero's container so the ruled row the base block designed
   for them answers to the page rather than to the text column. */
[data-layout="classic"] .hero__foot {
  container-type: inline-size;
  container-name: heroinner;
  margin-top: clamp(30px, 4.5vw, 48px);
}
[data-layout="classic"] .hero__foot .trust { margin-top: 0; }

/*
   A PHOTO-LESS CLASSIC HERO KEEPS THE GROUND IT HAD.

   With no band there is nothing for the fixed bar to sit against, and the
   wordmark in the bar is white until the page scrolls. So a hero with no
   picture stays on --deep and the type does the work, which is what the
   shared .hero--noimage rules already arrange.
*/
[data-layout="classic"] .hero--noimage h1 { max-width: 14ch; }

/* -------------------------------------------- classic: how a page closes --- */
/*
   Every page used to end with the same slab: a tinted band, a heading, a line
   of lede and two buttons, in that order, five times across a five page site.
   The band is gone. What closes a page here is a rule and an ask set on the
   same paper as everything above it, and how heavy that rule is depends on
   which page it is closing, so the five endings are not one ending printed
   five times.
*/
[data-layout="classic"] .closer {
  background: var(--page);
  border-top: 2px solid var(--ink);
}
[data-layout="classic"] .section--alt + .closer { background: var(--page); }
[data-layout="classic"] .closer__inner { align-items: end; padding-block: clamp(40px, 5.5vw, 76px); }
[data-layout="classic"] .closer h2 { font-size: clamp(1.75rem, 4.2vw, 2.7rem); line-height: 1.06; max-width: 16ch; }
[data-layout="classic"] .closer p { line-height: 1.7; }

/* The two pages that end on a picture and on a person do not need to be
   shouted at afterwards. There the closer is one ruled line: a short ask, the
   controls beside it, and half the air. */
body[data-layout="classic"]:is([data-page="gallery"], [data-page="about"]) .closer { border-top: 1px solid var(--line); }
body[data-layout="classic"]:is([data-page="gallery"], [data-page="about"]) .closer__inner { padding-block: clamp(28px, 3.6vw, 44px); }
body[data-layout="classic"]:is([data-page="gallery"], [data-page="about"]) .closer h2 { font-size: clamp(1.25rem, 2.4vw, 1.6rem); max-width: 26ch; }
body[data-layout="classic"]:is([data-page="gallery"], [data-page="about"]) .closer__actions .btn {
  min-height: 46px;
  padding: 11px 20px;
  font-size: 15px;
}

/* ------------------------------------------------ classic: the sub-page --- */
/* The masthead the sub-pages already run is the shape this layout's section
   heads now take, so the two agree. All it needs is the heading at the
   layout's own size and the standfirst on the same two pixel rule. */
[data-layout="classic"] .pagehead { border-bottom-width: 2px; border-bottom-color: var(--ink); }
[data-layout="classic"] .pagehead h1 { line-height: 1.03; }
[data-layout="classic"] .pagehead__lede { line-height: 1.7; }

/* ------------------------------------------------- classic: the masthead --- */
/*
   THE INITIALS IN A BOX GO.

   Two capitals reversed out of a filled accent square is the most recognisable
   "generated site" mark on the web, it is printed on every page of every site
   with no variant and no opt-out, and it is the reason the bar reads as a
   builder's default before a reader has taken in a single word. The wordmark
   and the town under it were already in the markup and stand perfectly well on
   their own, so that is what the bar carries.

   The bar over the band takes a scrim tinted with the brand rather than with
   black, so the top of the page belongs to the business and not to a generic
   darkening layer. Once it sticks it is paper with a rule under it: no blur,
   no shadow, no floating panel.
*/
[data-layout="classic"] .brand__mark { display: none; }
[data-layout="classic"] .brand__meta { display: block; letter-spacing: .08em; font-size: 11.5px; text-transform: uppercase; }
[data-layout="classic"] .brand__name { font-size: 18.5px; letter-spacing: -0.015em; }
[data-layout="classic"] .site-header::before {
  background: linear-gradient(to bottom, rgb(var(--primary-rgb) / .72), rgb(var(--primary-rgb) / 0));
}
[data-layout="classic"] .site-header.is-stuck {
  background: var(--page);
  backdrop-filter: none;
  box-shadow: none;
  border-bottom-color: var(--line);
}
[data-layout="classic"] .nav a { border-radius: 0; font-weight: 500; }
/* The current page, marked by a rule under the word rather than by recolouring
   it. Over the band the label keeps the hero's own near-white, which is the
   token mixed for exactly that ground; on paper it takes the page's ink. Both
   carry the accent in the rule, where a pale one costs nobody anything. */
[data-layout="classic"] .nav a[aria-current="page"] {
  color: var(--accent-on-dark);
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--accent);
}
[data-layout="classic"] .is-stuck .nav a[aria-current="page"],
body[data-layout="classic"]:not(.has-hero) .nav a[aria-current="page"] { color: var(--ink); }

/* ------------------------------------------------- classic: the colophon --- */
/*
   The footer keeps the ink ground, because a page set entirely on paper has to
   stop somewhere and a hairline is not a stop. What it drops is the tracked
   capitals over every column, which are the same recipe as the eyebrow this
   layout just removed from the sections. Three pixels of the accent across the
   top is the one place the brand colour is a band rather than a detail.
*/
[data-layout="classic"] .site-footer {
  border-top: 3px solid var(--accent);
  padding-top: clamp(40px, 5vw, 58px);
}
[data-layout="classic"] .site-footer__heading {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
}
[data-layout="classic"] .site-footer__name { font-size: 23px; }
[data-layout="classic"] .site-footer__hours dd { font-variant-numeric: tabular-nums lining-nums; }

/* ============================================== classic: with the viewport === */

@media (min-width: 700px) {
  /* The band deepens with the screen, but it never takes the whole of one:
     the masthead has to start above the fold at every width. */
  [data-layout="classic"] .hero__band { height: clamp(300px, 46svh, 480px); }
}

@media (min-width: 860px) {
  /*
     THE HORIZONTAL GRID.

     Wide column, narrow column, one gutter, used by the hero, by every section
     head and by the sub-page masthead. It is the only structural idea in this
     layout and it is deliberately used everywhere, because a grid a reader can
     feel on five different pages is what makes five pages one site.
  */
  [data-layout="classic"] .hero--light .hero__inner {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
    column-gap: clamp(40px, 6vw, 96px);
    align-items: end;
  }
  [data-layout="classic"] .hero--light .hero__head { grid-column: 1; }
  [data-layout="classic"] .hero--light .hero__body { grid-column: 2; padding-bottom: .4em; }
  [data-layout="classic"] .hero--light .hero__sub { margin-top: 0; }

  [data-layout="classic"] .wrap > .section-head:not(.section-head--centre) {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(0, .7fr);
    column-gap: clamp(40px, 6vw, 96px);
    align-items: start;
  }
  [data-layout="classic"] .wrap > .section-head:not(.section-head--centre) h2 { grid-column: 1; }
  [data-layout="classic"] .wrap > .section-head:not(.section-head--centre) p {
    grid-column: 2;
    margin-top: 0;
    padding-top: 14px;
    /* The rule belongs to the note, so it is drawn in the ink of the ground
       the note is actually on. --on-deep is declared only inside a dark
       section, so everywhere else the fallback is the page's own ink. */
    border-top: 2px solid var(--on-deep, var(--ink));
  }

  /* The process runs across rather than down: four stages side by side under
     four rules on one line is the schedule, and a stack of four is a list of
     instructions. */
  [data-layout="classic"][data-v-steps="row"] .steps { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 0 clamp(26px, 3.2vw, 48px); }
}

@media (min-width: 1080px) {
  [data-layout="classic"] .hero__band { height: clamp(360px, 50svh, 540px); }
}

/* ------------------------------------------------ classic: no panels ------ */
/*
   The three objects left on the page with a drop shadow and a rounded corner
   round them. A booking form floating on a white card with a sixty pixel
   shadow under it is an application widget dropped onto a printed page, and
   the map beside it had the same frame. Squared and set flat, they read as
   part of the page they are on. The theme's radius is left alone everywhere
   else, so a document that asked for round buttons still gets them.
*/
[data-layout="classic"] .booking__card,
[data-layout="classic"] .panel,
[data-layout="classic"] .map {
  border-radius: 0;
  box-shadow: none;
}
[data-layout="classic"] .booking__card { border-color: var(--line); }

/* ----------------------------------- classic: the facts on a narrow screen --- */
/*
   The rules that give the meta row its rhythm are in a container query at
   620px of column width, which a 375px phone never reaches, so below it the
   row fell back to three phrases separated by nothing but a gap. That is the
   shape the comment above the container query calls a failure, left in place
   on the screen that matters most to a local business. It gets the same
   rhythm turned ninety degrees: one fact per line, each on a rule.
*/
@container heroinner (max-width: 619px) {
  [data-layout="classic"] .trust {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }
  [data-layout="classic"] .trust__item {
    padding: 10px 0;
    border-top: 1px solid var(--line);
  }
  [data-layout="classic"] .trust__item:first-child { border-top: 0; padding-top: 0; }
}

/* ------------------------------------ classic: the pull quote and the rest --- */
/*
   The quote variant holds both of its blocks to 900px, which on this layout
   left a quarter of the band empty down the right hand side while the reviews
   underneath it were a single column of very short rows. The quotation keeps
   its measure, because a sentence set at display size has to break somewhere
   a reader can follow; the ledger under it takes the full width in two
   columns, so the rules run across the page and the section has a foot.
*/
[data-layout="classic"][data-v-reviews="quote"] .review-lines { max-width: none; }

@media (min-width: 860px) {
  [data-layout="classic"][data-v-reviews="quote"] .review-lines {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(40px, 6vw, 96px);
  }

  /*
     THE INDEX ON THE SAME GRID AS EVERYTHING ELSE.

     The shared rules hold it to 62rem and give it a third column of its own
     width, so on this layout the description column landed a hundred pixels
     to the left of the standfirst column directly above it and the ruled
     entries stopped short of the rule under the heading. Here it runs the
     full measure on the layout's own wide/narrow pair, with the folio set as
     a label under the rule the way the process stages are.
  */
  [data-layout="classic"] .svc-index { max-width: none; }
  [data-layout="classic"] .svc-index__item {
    grid-template-columns: minmax(0, 1.3fr) minmax(0, .7fr);
    column-gap: clamp(40px, 6vw, 96px);
  }
  [data-layout="classic"] .svc-index__num { grid-column: 1; grid-row: 1; }
  [data-layout="classic"] .svc-index__head { grid-column: 1; grid-row: 2; }
  [data-layout="classic"] .svc-index__desc {
    grid-column: 2;
    grid-row: 1 / span 2;
    margin-top: 0;
    max-width: none;
  }
}

/* --------------------------------------- classic: the two things that float --- */
/*
   The verdict named floating chat bubbles by name, and the rail header adds a
   second one: a drop-shadowed tab with the phone number turned on its side,
   pinned to the middle of the right edge from 1080px up. Neither is this
   layout's to delete, because both are things the business can actually use,
   but a rounded chip with a forty pixel shadow under it is an overlay bolted
   onto a page rather than a part of one. Square, flat, and drawn with the
   same ink and the same hairline as everything else, they read as the page's
   own furniture.
*/
[data-layout="classic"] .chat__fab { border-radius: 0; box-shadow: none; }
[data-layout="classic"] .chat__panel { border-radius: 0; box-shadow: none; border-color: var(--ink-3); }
[data-layout="classic"] .phone-rail {
  border-radius: 0;
  box-shadow: none;
  background: var(--page);
  border-color: var(--ink);
  border-width: 2px;
  border-right: 0;
}

/* ============================================================ editorial ====
   A MAGAZINE FEATURE.

   Eight sites are set in this register: two bakeries, a restaurant, a barber,
   a physiotherapist, a photographer, a painter and a law firm. It has to be
   warm enough for a bread counter and cool enough for a solicitor, which
   rules out everything decorative and leaves the four things a printed
   feature is actually made of.

   1. AN ASYMMETRIC GRID WITH A MARGIN THAT IS REALLY EMPTY. A section opens
      with a rule across the measure, a folio hung in a narrow column, and
      the heading indented into the wide one. The margin carries the folio and
      nothing else, which is the whole point: the text column is narrower than
      the page and the difference is visible. Every other layout in this file
      runs its heading to the same left edge as its body copy.

   2. A STANDFIRST, NOT A GREY LINE OF LEDE. The subtitle under a heading was
      a 1.05rem paragraph in --ink-2, which is body copy in a slightly paler
      ink: three sizes of the same thing stacked on top of each other. Here it
      is set in the display face at reading size in full ink, held to
      forty-six characters. A standfirst is a different object from body copy
      and now looks like one.

   3. THE PICTURE GOES PAST THE EDGE. The hero photograph runs off the right
      of the window, the feature gallery runs off both, and nothing anywhere
      on the layout has a corner radius. --radius is zero for the whole page,
      so a photograph in a rounded box cannot happen by inheritance.

   4. RECTO AND VERSO. Sections alternate which margin the folio hangs in and
      where the standfirst sits: odd sections put the folio left and the
      standfirst under the heading, even sections put the folio right and the
      standfirst beside it. That is what a spread does with a page number, and
      it is the cheapest honest answer to five pages of one site opening the
      same way fifteen times.

   WHAT WAS HERE BEFORE. Fifty-seven selector mentions, of which a fifth
   styled a numbered service list this layout can never be dealt: Variants
   narrows services to rows, index and list, and .service is emitted only by
   the cards branch. Those are deleted. Most of the rest set a background or a
   colour, so the layout owned no header, no page head, no price treatment, no
   closer and no footer of its own, and an editorial page was a classic page
   with the eyebrow tracked two hundredths of an em wider.

   Specificity note: every selector here is [data-layout="editorial"] X, which
   is (0,2,0) and beats the plain rules inside the shared media queries above
   at every width. Anything that has to change WITH the viewport is written
   into this block's own media queries at the end, never up here.
   ========================================================================= */

body[data-layout="editorial"] {
  /*
     SQUARE, WHATEVER THE DOCUMENT ASKED FOR. A photograph that runs to the
     edge of the page cannot have rounded corners, and once the pictures are
     square every fill and every field on the page has to be square with them
     or the radius reads as an accident rather than as a decision.
  */
  --radius: 0px;

  /*
     A MISSING CUT MUST FAIL, NOT BE FAKED. --font-heading can resolve to a
     display face that ships one weight and no italic, and asking such a face
     for 600 or for an oblique gets a browser-synthesised fake. This block
     used to set two menu rules in italic and one section heading at a literal
     600; with synthesis off, a face that has not got the cut simply stays at
     the one it has.
  */
  font-synthesis: none;

  /* The distance from the edge of the text column to the edge of the window,
     which is what a full-bleed picture has to travel. Same expression the
     marquee and the filmstrip use. */
  --bleed: max(20px, calc((100vw - 1180px) / 2 + 20px));
}

/* ------------------------------------------ editorial: the dark bands --- */
/*
   There are none. The gallery and contact sections ship on --deep, and a
   black band across the middle of a feature is a website's idea, not a
   page's. The tokens are redefined rather than the rules rewritten, so
   anything drawn on those bands follows without knowing this happened.
*/
[data-layout="editorial"] .section--dark {
  --on-deep: var(--ink);
  --on-deep-2: var(--ink-2);
  --on-deep-3: var(--ink-3);
  --panel: transparent;
  --panel-line: var(--line);
  --panel-today: transparent;
  background: var(--surface);
  border-block: 1px solid var(--line);
}
[data-layout="editorial"] .section--dark .contact-status { color: var(--ok); }
[data-layout="editorial"] .section--dark .contact-status--closed { color: var(--bad); }
[data-layout="editorial"] .section--dark .stars__base { color: rgb(var(--primary-rgb) / .18); }

/* -------------------------------------- editorial: how a section opens --- */
/*
   THE STAMP, AND WHAT REPLACES IT.

   Every section on every page opened with the same three-part block: a 12px
   tracked capital label behind a 26x2 bar of accent, a display heading, and a
   grey line of lede. Drawn once that is a heading. Drawn up to fifteen times
   across a five page site it is the loudest template tell on the page,
   because the furniture above the words is the same object every time and the
   reader cannot tell the fee page from the gallery page except by reading.

   What a feature does instead is rule the measure, number the section in the
   margin, and indent the heading into the column. The label goes. The page
   keeps exactly one eyebrow: the locality over the front page headline, and
   the breadcrumb over every sub-page title, which is not an eyebrow at all.

   The folio is a counter rather than anything in the markup, so no template
   has to know it exists and a document that files its sections in a different
   order is numbered correctly without being touched. It increments on the
   head rather than on the section, so a section with no head does not leave a
   hole in the sequence.
*/
[data-layout="editorial"] main { counter-reset: sect; }
[data-layout="editorial"] .section .eyebrow { display: none; }

[data-layout="editorial"] .section-head {
  max-width: none;
  margin-bottom: clamp(30px, 4vw, 50px);
}
/* A centred heading is a poster's, and this layout has a left margin for a
   reason. The menu section asks for centring by class when it is dealt the
   ledger; it is not dealt the ledger any more, and the rule stays because
   two other sections can still ask. */
[data-layout="editorial"] .section-head--centre { text-align: left; margin-inline: 0; }

[data-layout="editorial"] .wrap > .section-head {
  counter-increment: sect;
  border-top: 2px solid var(--ink);
  padding-top: clamp(14px, 2vw, 22px);
}
[data-layout="editorial"] .wrap > .section-head::before {
  content: counter(sect, decimal-leading-zero);
  display: block;
  margin-bottom: 12px;
  font-family: var(--font);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .2em;
  /* A folio is read, so it owes a reader 4.5:1 and --ink-3 does not hold it
     on most of the palettes. --ink-2 is the next step up and its worst in the
     set is 5.39. */
  color: var(--ink-2);
  font-variant-numeric: tabular-nums lining-nums;
}

/*
   THE WEIGHT COMES FROM THE PAIRING, NOT FROM HERE.

   This rule used to carry a literal font-weight: 600, which overrode
   --heading-weight for section headings only. On a site whose pairing asks
   for 400 the section heads came out heavier than the page title above them
   and heavier than the closing ask below; on a pairing asking for 700 the
   relationship inverted and every section heading was lighter than both. Two
   of the three headings on a page moved and one did not.

   The floor also comes down. At 2rem the section h2 was 32px on a phone
   against a 35.2px page title, three pixels apart at the same weight, which
   is the one layout where the sub-page hierarchy collapsed below 640px. The
   pair is now 28px against 41.6px and they are separated by position as well:
   the title hangs in the margin column and the heading does not.
*/
[data-layout="editorial"] .section-head h2,
[data-layout="editorial"] .about__body h2,
[data-layout="editorial"] .booking__intro h2 {
  font-size: clamp(1.75rem, 5.2vw, 3.3rem);
  line-height: 1.04;
  max-width: 20ch;
}
[data-layout="editorial"] .section-head h2.h2--small { font-size: clamp(1.35rem, 3vw, 1.9rem); }

/*
   The booking section names itself in a .booking__intro rather than in a
   .section-head, so it was the one block on the page opening with no rule
   over it and no folio beside it: four sections numbered and one not. It
   takes the same opening, and because a counter increments in document order
   the sequence stays consecutive without anything else being told.
*/
[data-layout="editorial"] .booking__intro {
  counter-increment: sect;
  border-top: 2px solid var(--ink);
  padding-top: clamp(14px, 2vw, 22px);
}
[data-layout="editorial"] .booking__intro::before {
  content: counter(sect, decimal-leading-zero);
  display: block;
  margin-bottom: 12px;
  font-family: var(--font);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .2em;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="editorial"] .booking__lede {
  font-family: var(--font-heading);
  font-size: clamp(1.06rem, 2vw, 1.2rem);
  line-height: 1.45;
  letter-spacing: var(--heading-track);
  color: var(--ink);
  max-width: 42ch;
}

/* The standfirst. Measure only for the colour, because .section--dark
   .section-head p is (0,2,0) as well and would otherwise be overruled on the
   bands this layout has already turned light. */
[data-layout="editorial"] .section-head p {
  margin-top: clamp(12px, 1.6vw, 18px);
  max-width: 46ch;
  font-family: var(--font-heading);
  font-size: clamp(1.08rem, 2.1vw, 1.28rem);
  line-height: 1.45;
  letter-spacing: var(--heading-track);
  color: var(--ink);
}

/* The two eyebrows a page keeps. A 26x2 block of accent is a card's mark; a
   long hairline under a tracked label is a printed page's. */
[data-layout="editorial"] .eyebrow {
  font-size: 11.5px;
  letter-spacing: .22em;
  color: var(--ink-2);
}
[data-layout="editorial"] .eyebrow::before {
  width: 46px;
  height: 1px;
  background: var(--ink-3);
}

/* ------------------------------------------------ editorial: the rhythm --- */
/*
   A LONG PAGE NEEDS A CADENCE, NOT AN INTERVAL.

   With the dark bands turned light there are two grounds on an editorial page
   and every boundary is a hairline, which is a legitimate move and was not
   paid for anywhere: measure, scale and rhythm were all inherited, so the
   page read as flat rather than as quiet. Alternate sections now breathe
   differently, which is what buys the quiet back.
*/
[data-layout="editorial"] .section { padding: clamp(56px, 7.6vw, 100px) 0; }
[data-layout="editorial"] .section:nth-of-type(even) { padding-block: clamp(72px, 10.4vw, 142px); }
[data-layout="editorial"] .section--tight { padding: clamp(40px, 5.4vw, 68px) 0; }

/* Two sections on the same ground read as one very tall band with a hole in
   it. The shared fix for that is (0,2,0) and so is the padding above, so it
   is restated here after the rules that would otherwise cancel it. */
[data-layout="editorial"] .section--alt + .section--alt,
[data-layout="editorial"] .section:not(.section--alt, .section--dark) + .section:not(.section--alt, .section--dark) {
  padding-top: clamp(38px, 5vw, 64px);
}
[data-layout="editorial"] .section--alt:has(+ .section--alt),
[data-layout="editorial"] .section:not(.section--alt, .section--dark):has(+ .section:not(.section--alt, .section--dark)) {
  padding-bottom: clamp(38px, 5vw, 64px);
}

/* ------------------------------------------------- editorial: the measure --- */

[data-layout="editorial"] .about__body,
[data-layout="editorial"] .prose { max-width: 62ch; }
[data-layout="editorial"] .about__body p,
[data-layout="editorial"] .prose p { line-height: 1.7; }
[data-layout="editorial"] .about__rule { width: 64px; height: 1px; background: var(--line); margin: 24px 0; }

/* ------------------------------------------------ editorial: the masthead --- */
/*
   A RUNNING HEAD, NOT AN APPLICATION BAR.

   The bar arrives with the name at 17px next to the navigation in pill shaped
   links, a blurred translucent ground once it sticks and a shadow under it.
   Here the name is the largest thing in the row, set in the display face at
   reading size with the locality under it as a tracked label; the links are a
   running head in small capitals with nothing drawn behind them; and the page
   the reader is on is marked with a rule under the word rather than with a
   colour, which is what a printed running head does and which does not
   depend on the accent being dark enough to read at 12px.
*/
[data-layout="editorial"] .header-inner { min-height: 82px; gap: clamp(18px, 3vw, 40px); }
/* Two lines rather than an ellipsis. The shared wordmark is 17px and holds
   itself to one line with overflow: hidden, which at reading size turned
   "Advokatbyra Wallin" into "Advokatbyra Wal..." on a 1440px screen: a
   business name cut off by its own masthead. A name is allowed to break. */
[data-layout="editorial"] .brand__name {
  font-weight: var(--heading-weight-strong);
  font-size: clamp(18px, 1.5vw, 22px);
  letter-spacing: -0.022em;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  line-height: 1.12;
  text-wrap: balance;
}
[data-layout="editorial"] .brand__meta {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
}
[data-layout="editorial"] .nav { gap: clamp(13px, 1.9vw, 28px); }
[data-layout="editorial"] .nav a {
  border-radius: 0;
  padding: 7px 0;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .15em;
  text-transform: uppercase;
}
[data-layout="editorial"] .nav a:hover { background: none; }
/* body-prefixed so it outranks body:not(.has-hero) .nav a[aria-current], which
   is (0,3,2) and points the current page at the accent. */
body[data-layout="editorial"] .nav a[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
  box-shadow: inset 0 -1px 0 0 var(--ink);
}
[data-layout="editorial"] .header-tel {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .04em;
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="editorial"] .site-header.is-stuck {
  background: var(--page);
  backdrop-filter: none;
  box-shadow: none;
  border-bottom-color: var(--ink-3);
}
/* The drawer is the same paper as the page behind it. */
[data-layout="editorial"] .mobile-nav a { letter-spacing: -0.02em; }
/* The tab with the number turned on its side, pinned to the middle of the
   right edge. It is not this layout's to delete, but a rounded chip with a
   shadow under it is an overlay bolted onto a page rather than a part of one. */
[data-layout="editorial"] .phone-rail {
  box-shadow: none;
  background: var(--page);
  border-color: var(--ink);
  border-right: 0;
}
[data-layout="editorial"] .chat__fab { box-shadow: none; }
[data-layout="editorial"] .chat__panel { box-shadow: none; border-color: var(--ink-3); }

/* ------------------------------------------------ editorial: how a page opens --- */
/*
   THE TITLE HANGS IN THE MARGIN'S COLUMN, NOT ON IT.

   The sub-page head is a masthead on every layout: breadcrumb across the top,
   title left, one line of lede dropped onto its last baseline on the right.
   Two thirds of the way down that page the first section head did the same
   thing at a slightly smaller size, which is what made the two read as one
   repeated object.

   Here they separate by position. The breadcrumb moves into the narrow left
   column, where the section folios below it also sit, so the margin is one
   column all the way down the page; the title starts where the headings start
   and is half again their size; and the lede becomes a standfirst under it
   rather than a caption beside it. The rule is the heavy one, drawn over the
   head, because this is the top of the page and the sections below it are
   subdivisions of it.
*/
/*
   THE RULES ALL STOP IN THE SAME PLACE.

   A border on .wrap is drawn around its padding box and a border inside .wrap
   is drawn around its content box, so the rule over the page title ran twenty
   pixels wider at each end than the rule over every section under it: four
   lines down one page that start and end on four different verticals. Drawn
   as an inset pseudo rule instead, every rule on an editorial page is the
   same measure, which is the whole point of ruling a page rather than banding
   it. Out of flow, so the grid below is not given two extra items.
*/
[data-layout="editorial"] .pagehead { border-bottom: 0; padding-bottom: 0; }
[data-layout="editorial"] .pagehead > .wrap {
  position: relative;
  padding-top: clamp(14px, 2vw, 22px);
  padding-bottom: clamp(34px, 5.4vw, 68px);
}
[data-layout="editorial"] .pagehead > .wrap::before,
[data-layout="editorial"] .pagehead > .wrap::after {
  content: '';
  position: absolute;
  left: 20px;
  right: 20px;
}
[data-layout="editorial"] .pagehead > .wrap::before { top: 0; height: 2px; background: var(--ink); }
[data-layout="editorial"] .pagehead > .wrap::after { bottom: 0; height: 1px; background: var(--line); }
[data-layout="editorial"] .pagehead__eyebrow {
  margin: 0 0 14px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ink-2);
}
[data-layout="editorial"] .pagehead h1 {
  font-size: clamp(2.6rem, 7.4vw, 4.4rem);
  line-height: 1.02;
  max-width: 16ch;
}
[data-layout="editorial"] .pagehead__lede {
  margin-top: clamp(16px, 2vw, 24px);
  max-width: 46ch;
  font-family: var(--font-heading);
  font-size: clamp(1.08rem, 2.1vw, 1.28rem);
  line-height: 1.45;
  letter-spacing: var(--heading-track);
  color: var(--ink);
}

/*
   AND ONE PAGE IN FIVE DOES NOT OPEN LIKE THE OTHER FOUR.

   Variants are dealt per site, so without this every sub-page of one business
   carries the same head. On the gallery page the subject is a wall of
   photographs and the shared lede says what the title already said, so the
   title runs at nearly half again the size on its own and the rule under it
   closes the head. It needs data-page on the body element, which
   show.blade.php prints for every layout.
*/
[data-layout="editorial"][data-page="gallery"] .pagehead h1 {
  font-size: clamp(3rem, 10.5vw, 6rem);
  max-width: 12ch;
}
[data-layout="editorial"][data-page="gallery"] .pagehead__lede { display: none; }
[data-layout="editorial"][data-page="gallery"] .pagehead > .wrap { padding-bottom: clamp(40px, 7vw, 92px); }
[data-layout="editorial"][data-page="gallery"] .pagehead > .wrap::after { height: 2px; background: var(--ink); }

/* -------------------------------------------------- editorial: the prices --- */
/*
   A SCHEDULE, NOT A PRICE TAG.

   The entire editorial contribution to the price list used to be one weight
   on one class, so a fee schedule on this layout was byte-identical to the
   same schedule on bold, split and dark: the figure pushed right by an auto
   margin, set in the accent at 700, with the duration crammed onto the same
   line beside it.

   A printed schedule does three things differently. The figure is a column of
   its own rather than something pushed to the right, so hundreds line up
   under hundreds; it is set in the page's own ink at the same size as the
   name it belongs to, because a column of accent coloured numerals is read as
   a column of links before any of the names are; and the duration is a note
   under the name, which is what it is, rather than a second figure next to
   the first.
*/
[data-layout="editorial"] .svc-list { border-top: 1px solid var(--ink); }
[data-layout="editorial"] .svc-list__item {
  padding: clamp(15px, 2.2vw, 22px) 0;
  border-bottom: 1px solid var(--line);
}
[data-layout="editorial"] .svc-list__item:first-child { border-top: 0; }
[data-layout="editorial"] .svc-list__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: clamp(20px, 3vw, 44px);
  align-items: baseline;
}
[data-layout="editorial"] .svc-list__name {
  grid-column: 1; grid-row: 1;
  font-weight: var(--heading-weight-strong);
}
[data-layout="editorial"] .svc-list__time {
  grid-column: 1; grid-row: 2;
  margin-top: 4px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-2);
}
[data-layout="editorial"] .svc-list__price {
  grid-column: 2; grid-row: 1;
  margin-left: 0;
  font-size: 1.14rem;
  font-weight: var(--heading-weight-strong);
  color: var(--ink);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="editorial"] .svc-list__desc { max-width: 54ch; }

/* The printed index. The numeral is a folio like the section's: small,
   tracked, in the quiet ink, hanging in a column of its own. Set in the
   display face in the accent at the shared size it was the loudest object in
   a section whose subject is the names beside it, and it rhymed with nothing
   else on the page. */
/* The full measure, so the rule over the first entry lines up with the rule
   over the heading above it. The shared 62rem cap stopped it 150px short and
   left two rules on a page starting together and ending apart. */
[data-layout="editorial"] .svc-index { border-top: 1px solid var(--ink); max-width: none; }
[data-layout="editorial"] .svc-index__item {
  border-top: 1px solid var(--line);
  column-gap: clamp(18px, 3.4vw, 48px);
}
[data-layout="editorial"] .svc-index__item:first-child { border-top: 0; }
[data-layout="editorial"] .svc-index__num {
  font-family: var(--font);
  font-weight: 600;
  font-size: 11.5px;
  letter-spacing: .2em;
  line-height: 2.9;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="editorial"] .svc-index__name { font-weight: var(--heading-weight-strong); }
[data-layout="editorial"] .svc-index__price {
  color: var(--ink);
  font-weight: var(--heading-weight-strong);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="editorial"] .svc-index__time {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-2);
}
[data-layout="editorial"] .svc-index__desc { max-width: 52ch; }

/* The full width rows. Zebra banding is a table's answer to a long list and
   this list is four items, so the band goes and the rule stays. The icon,
   where a trade has turned it on, stops being a filled accent square: a
   54 to 74px block of colour next to a service name is the loudest thing in
   the section and it is drawn round a pictogram nobody chose. */
[data-layout="editorial"] .svc-rows { border-top: 1px solid var(--ink); }
[data-layout="editorial"] .svc-row {
  border-top: 1px solid var(--line);
  background: transparent;
  margin-inline: 0;
  padding-inline: 0;
  align-items: baseline;
}
[data-layout="editorial"] .svc-row:first-child { border-top: 0; }
[data-layout="editorial"] .svc-row:nth-child(even) { background: transparent; }
[data-layout="editorial"] .svc-row__icon {
  width: auto;
  aspect-ratio: auto;
  background: transparent;
  color: var(--accent-strong);
  align-self: start;
  margin-top: 6px;
}
[data-layout="editorial"] .svc-row__icon svg { width: 20px; height: 20px; stroke-width: 1.4; }
[data-layout="editorial"] .svc-row__name { font-weight: var(--heading-weight-strong); }
[data-layout="editorial"] .svc-row__desc { max-width: 56ch; }
[data-layout="editorial"] .svc-row__price { font-variant-numeric: tabular-nums lining-nums; }
[data-layout="editorial"] .svc-row__time {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* ------------------------------------------------- editorial: the bill of fare --- */
/*
   A MENU CARD IS A TABLE WITH THE COLUMN TAKEN OUT OF IT.

   The price section ships as a restaurant card: the item on the left, a row
   of dots crossing the gap, the figure on the right, the description in
   italic under it, and the group name underlined with a 2px bar of accent.
   Four of the eight sites on this layout sell food, so the register is not
   wrong. The drawing is: the dots exist to carry the eye across a gap that
   only exists because the figure is not in a column, the italic had no file
   behind it until the type pass, and the 2px accent bar is a card's mark.

   What replaces it is one list, the group named in the margin beside its
   entries, and the figures in a column of their own in tabular lining
   numerals. That is the same table a fee schedule wants and the same table a
   bread counter wants, which is the point of a register that has to work warm
   and cool.
*/
[data-layout="editorial"] .menu-groups {
  /* One column at any width. The shared rule puts the groups two abreast
     above 860px, which with a margin column inside each half leaves the
     entries about 230px wide and stops the figures being a column anybody can
     read down. */
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(34px, 5vw, 60px);
}
[data-layout="editorial"] .menu-group {
  border-top: 2px solid var(--ink);
  padding-top: clamp(13px, 1.8vw, 18px);
}
[data-layout="editorial"] .menu-group__name {
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  font-family: var(--font);
  font-size: 11.5px;
  font-weight: 600;
  font-style: normal;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-2);
}
[data-layout="editorial"] .menu-group__desc {
  margin: 10px 0 0;
  max-width: 40ch;
  font-style: normal;
}
[data-layout="editorial"] .menu-list { margin-top: 12px; }
[data-layout="editorial"] .menu-item {
  padding: 13px 0;
  border-bottom: 1px solid var(--line);
}
[data-layout="editorial"] .menu-item:last-child { border-bottom: 1px solid var(--line); }
[data-layout="editorial"] .menu-item__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: clamp(20px, 3vw, 40px);
  align-items: baseline;
}
/* With the figures in a real column there is nothing left for the eye to be
   led across. */
[data-layout="editorial"] .menu-item__lead { display: none; }
[data-layout="editorial"] .menu-item__name {
  font-family: var(--font-heading);
  font-size: 1.08rem;
  font-weight: var(--heading-weight-strong);
  letter-spacing: var(--heading-track);
}
[data-layout="editorial"] .menu-item__price {
  font-family: var(--font-heading);
  font-size: 1.08rem;
  font-weight: var(--heading-weight-strong);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="editorial"] .menu-item__desc {
  font-style: normal;
  max-width: 54ch;
  margin-top: 5px;
}
[data-layout="editorial"] .menu-note { border-top-color: var(--line); max-width: 62ch; }

/* --------------------------------- editorial: process as a schedule --- */
/*
   A NUMBERED DISC ON A LINE IS A DIAGRAM OF A PROCESS, NOT A PROCESS.

   The timeline variant is out of this layout's pool for that reason and the
   two that are left lose their discs here. A 40px circle of accent with a
   figure reversed out of it is the one shape that appears on every template
   ever generated; a stage set under a rule with its number as a folio is what
   a printed schedule looks like, and it rhymes with the sections above it
   because they are numbered the same way.
*/
[data-layout="editorial"] .steps .step {
  background: transparent;
  border: 0;
  border-top: 1px solid var(--ink);
  border-radius: 0;
  padding: clamp(14px, 2vw, 20px) 0 0;
}
[data-layout="editorial"] .steps .step__num {
  width: auto; height: auto;
  display: block;
  background: transparent;
  border: 0;
  border-radius: 0;
  margin-top: 0;
  font-family: var(--font);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .2em;
  line-height: 1.5;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="editorial"] .steps .step h3 { font-size: 1.1rem; }
[data-layout="editorial"] .steps .step p { max-width: 46ch; }
/* The row variant stacks the folio over the stage with sixteen pixels between
   them, which was tuned for a forty pixel disc. A line of small capitals sits
   close under the rule it hangs from. */
[data-layout="editorial"][data-v-steps="row"] .steps .step,
[data-layout="editorial"][data-v-steps="numbered"] .steps .step { gap: 6px; }

/* ----------------------------------------- editorial: what people wrote --- */
/*
   The layout's own review treatment used to reach one variant in four: it
   styled .review, and the pull quote emits .review-quote and .review-line, so
   half the sites on this layout showed the shared Google-review shape the
   verdict names. Variants now deals this layout the pull quote or the ruled
   column and nothing else, and both are written here.
*/

/* The pull quote is the one place display type is doing the job it was cut
   for, so it keeps the face and takes the heavy rule. What it loses is the
   floating quotation mark: an outsized ornament deliberately set below the
   contrast floor is a decoration on a layout that has none. */
[data-layout="editorial"] .review-quote__mark { display: none; }
[data-layout="editorial"] .review-quote {
  border-top: 2px solid var(--ink);
  padding-top: clamp(22px, 3.2vw, 36px);
  max-width: 22ch;
}
[data-layout="editorial"] .review-quote__text {
  margin-top: 0;
  max-width: 20ch;
  font-size: clamp(1.5rem, 5vw, 2.7rem);
  font-weight: var(--heading-weight);
  line-height: 1.16;
}
[data-layout="editorial"] .review-quote__author { margin-top: clamp(22px, 3vw, 32px); }
/* The name is a caption under a quotation, so it is set as one. */
[data-layout="editorial"] .review-line__name,
[data-layout="editorial"] .review__name {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-2);
}
[data-layout="editorial"] .review-lines { border-top-color: var(--ink); }
[data-layout="editorial"] .review-line { border-bottom-color: var(--line); }
[data-layout="editorial"] .review-line__text { max-width: 62ch; }

/* The ruled column. The measure and the leading carry the quiet, not the
   size: forty-six characters against sixty-two for prose elsewhere. */
[data-layout="editorial"] .reviews .review {
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  border-bottom: 0;
  border-radius: 0;
  box-shadow: none;
  padding: clamp(20px, 3.2vw, 28px) 0;
}
[data-layout="editorial"] .reviews .review__text {
  font-size: 1.06rem;
  line-height: 1.72;
  max-width: 46ch;
  color: var(--ink);
}
[data-layout="editorial"] .reviews .review__author {
  margin-top: 16px;
  padding-top: 0;
  border-top: 0;
  align-items: center;
  gap: 12px;
}
[data-layout="editorial"] .reviews .review__stars { margin: 0; }
/* A fact about the section, so it sits with the head rather than floating
   between the head and the first quotation. */
[data-layout="editorial"] .rating-line {
  font-size: 12.5px;
  letter-spacing: .04em;
  color: var(--ink-2);
  margin-bottom: clamp(18px, 2.6vw, 28px);
}

/* ------------------------------------------------- editorial: questions --- */
/* Both shapes this layout can be dealt are plain rows, so there is no
   <details> marker to restyle and nothing to open. */
[data-layout="editorial"] .faq--plain { border-bottom: 1px solid var(--line); }
[data-layout="editorial"] .faq__row { border-top: 1px solid var(--line); }
[data-layout="editorial"] .faq__q { font-size: 1.06rem; }
[data-layout="editorial"] .faq__a { max-width: 58ch; }
[data-layout="editorial"] .faq-grid .section-head { max-width: 30ch; }
[data-layout="editorial"] .faq-grid .section-head h2 { font-size: clamp(1.5rem, 3.2vw, 2.1rem); }
[data-layout="editorial"] .faq-grid .section-head p { font-size: 1.02rem; }

/* ------------------------------------------------ editorial: the columns --- */
/*
   A PANEL IS A CARD WITH THE WORD CARD TAKEN OUT OF ITS NAME.

   The booking form and the two blocks on the contact page kept a fill, a
   border and, on the form, a sixty pixel drop shadow. They become columns of
   a printed sheet: a rule over each, the label under it in the same small
   tracked capitals the schedule and the colophon use, and nothing else drawn.
*/
[data-layout="editorial"] .panel,
[data-layout="editorial"] .booking__card {
  background: transparent;
  border: 0;
  border-top: 1px solid var(--ink);
  border-radius: 0;
  padding: clamp(16px, 2.4vw, 24px) 0 0;
  box-shadow: none;
}
[data-layout="editorial"] .panel h3 {
  color: var(--ink-2);
  font-weight: 600;
  letter-spacing: .2em;
  font-size: 11.5px;
}
/* Today's row was a filled bar with a pill on it, two pieces of furniture
   marking one line on a page with no other fill and no other pill. */
[data-layout="editorial"] .hours__row { padding-inline: 0; }
[data-layout="editorial"] .hours__row.is-today { background: transparent; color: var(--ink); }
[data-layout="editorial"] .hours__today {
  padding: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
  font-weight: 600;
  letter-spacing: .16em;
  opacity: .66;
}
[data-layout="editorial"] .map { border: 1px solid var(--line); }
[data-layout="editorial"] .chip {
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  padding: 8px 2px;
  color: var(--ink-2);
}
[data-layout="editorial"] .chip::before { background: var(--accent-strong); }

/* ------------------------------------------------- editorial: the pictures --- */
/* Nothing is in a rounded box, and the one picture a page can afford to run
   past the column does so. The feature gallery is one plate with a strip
   under it, which is the arrangement that can take a full bleed without the
   strip below it looking cropped. */
[data-layout="editorial"] .gallery figure:hover img { transform: none; }
/*
   THE PHOTOGRAPH RUNS OFF THE PAGE, NOT UP TO A MARGIN.

   The split about is a picture in the left column and prose in the right, and
   on every other layout the picture starts on the same vertical as the text
   above it, which makes it an illustration inside the column. A feature
   crops its plate against the edge of the paper. The picture is first in the
   source on both viewports, so this changes what is seen and not what is
   announced.
*/
[data-layout="editorial"] .about__media { margin-inline: calc(-1 * var(--bleed)) 0; }
[data-layout="editorial"] .about__media img { aspect-ratio: 4 / 3.6; }

/* The panel laid over a full bleed photograph is the one place this layout
   stacks two things. It is paper on a picture, so it loses the shadow that
   made it a card floating above one. */
[data-layout="editorial"] .about-overlay__panel {
  box-shadow: none;
  border: 0;
  padding: clamp(24px, 4.6vw, 44px);
}

/* ------------------------------------------------- editorial: the controls --- */
/* Square, flat, and drawn with the page's own ink. A button is the only
   interface element a printed page has no answer for, so it is the one thing
   here allowed to be a filled rectangle, and it is a rectangle. */
[data-layout="editorial"] .btn {
  border-radius: 0;
  box-shadow: none;
  font-weight: 600;
  letter-spacing: -0.005em;
  padding: 15px 26px;
}
[data-layout="editorial"] .btn:hover { transform: none; box-shadow: none; }
[data-layout="editorial"] .btn--outline,
[data-layout="editorial"] .btn--ghost { border-color: var(--ink-3); }
[data-layout="editorial"] .btn--outline:hover,
[data-layout="editorial"] .btn--ghost:hover { border-color: var(--ink); background: transparent; }
[data-layout="editorial"] .bfield input,
[data-layout="editorial"] .bfield select,
[data-layout="editorial"] .bfield textarea { border-radius: 0; background: var(--page); }

/* ------------------------------------------------ editorial: how a page closes --- */
/*
   TWO CLOSING BANDS THAT ARE NOT THE SAME BAND TWICE.

   A page ends with either the document's own cta section or the generic
   closer, and both were a heading on the left and a filled button on the
   right, so a reader met the same slab on all five pages and could not tell
   which of the two they were looking at.

   The cta band keeps its ground and stays the loud one: it is the ask. The
   closer becomes the colophon at the foot of the sheet: the page's own paper,
   a heavy rule across it, the line of type at the left of the measure and the
   two actions hung at the right of it. No fill, no lifted ground, and nothing
   between it and the imprint below but the rule each of them carries.
*/
[data-layout="editorial"] .closer,
[data-layout="editorial"] .section--alt + .closer { background: var(--page); }
[data-layout="editorial"] .closer { border-top: 0; }
[data-layout="editorial"] .closer__inner {
  position: relative;
  border-top: 0;
  padding-block: clamp(24px, 3.4vw, 40px) clamp(40px, 6vw, 76px);
  align-items: start;
}
/* Same inset rule as the page head, for the same reason. */
[data-layout="editorial"] .closer__inner::before {
  content: '';
  position: absolute;
  top: 0;
  left: 20px;
  right: 20px;
  height: 2px;
  background: var(--ink);
}
[data-layout="editorial"] .closer h2 { font-size: clamp(1.45rem, 3.2vw, 2.1rem); max-width: 26ch; }
[data-layout="editorial"] .closer p { max-width: 48ch; }
/* The opening state above the ask is a signal, not a badge. */
[data-layout="editorial"] .closer .status-pill {
  margin-bottom: 12px;
  padding: 0;
  background: transparent;
  border: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-2);
}
[data-layout="editorial"] .closer .status-pill__dot { display: none; }
/* Level with the heading rather than oversized. The band is a footnote to the
   page above it; the cta band is the ask. */
[data-layout="editorial"] .closer__actions .btn--accent {
  min-height: 0;
  padding: 15px 26px;
  font-size: 15px;
}
[data-layout="editorial"] .cta-band h2 { font-size: clamp(1.6rem, 3.6vw, 2.4rem); }

/* ------------------------------------------------ editorial: the colophon --- */
/*
   THE SITE ENDS ON PAPER.

   The shared footer is a band of --deep with four columns of white at half
   opacity on it, and this layout already turned it onto a light ground. What
   it did not do was change anything else about it, so the last screen of an
   editorial site was the same four column block every other layout ends with,
   recoloured. An imprint opens with a rule, sets the name at reading size
   rather than as a second logo, and labels its columns in the same small
   tracked capitals the schedule, the folios and the contact sheet use, so the
   last thing on the page rhymes with something earlier on it.
*/
[data-layout="editorial"] .site-footer {
  background: var(--page);
  color: var(--ink-2);
  border-top: 2px solid var(--ink);
  padding: clamp(32px, 4.6vw, 50px) 0 40px;
}
[data-layout="editorial"] .site-footer__name {
  color: var(--ink);
  font-weight: var(--heading-weight-strong);
  font-size: clamp(19px, 2vw, 24px);
}
[data-layout="editorial"] .site-footer__heading {
  color: var(--ink-2);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .22em;
}
[data-layout="editorial"] .site-footer__top,
[data-layout="editorial"] .site-footer__legal { border-color: var(--line); }
[data-layout="editorial"] .site-footer__legal { color: var(--ink-2); }
[data-layout="editorial"] .site-footer__links a:hover,
[data-layout="editorial"] .site-footer__contact a:hover,
[data-layout="editorial"] .site-footer__by a:hover { color: var(--ink); }
[data-layout="editorial"] .site-footer__social a { color: var(--ink-2); }
[data-layout="editorial"] .site-footer__social a:hover { color: var(--ink); background: var(--line); }

/* ------------------------------------------------ editorial: the two widths --- */

@media (min-width: 860px) {
  /*
     THE GRID. A narrow margin and a wide text column, and the margin really
     is empty apart from the folio hung in it. This is the one structural
     thing the layout owns and the reason a section here does not look like a
     section on classic: the heading starts a third of the way into the page
     and the rule above it does not.
  */
  [data-layout="editorial"] .wrap > .section-head {
    display: grid;
    grid-template-columns: minmax(0, .26fr) minmax(0, 1fr);
    column-gap: clamp(30px, 5vw, 84px);
    align-items: start;
  }
  [data-layout="editorial"] .wrap > .section-head::before {
    grid-column: 1; grid-row: 1;
    margin: 0;
    line-height: 1.7;
  }
  [data-layout="editorial"] .wrap > .section-head > h2 { grid-column: 2; grid-row: 1; }
  [data-layout="editorial"] .wrap > .section-head > p { grid-column: 2; grid-row: 2; }

  /*
     VERSO. On the alternate section the folio crosses to the other margin and
     the standfirst comes up beside the heading instead of under it, which is
     what a spread does with a page number and what stops five sections down
     one page reading as one object drawn five times.
  */
  [data-layout="editorial"] .section:nth-of-type(even) > .wrap > .section-head {
    grid-template-columns: minmax(0, 1fr) minmax(0, .56fr);
  }
  [data-layout="editorial"] .section:nth-of-type(even) > .wrap > .section-head::before {
    grid-column: 2; grid-row: 1;
    text-align: right;
  }
  [data-layout="editorial"] .section:nth-of-type(even) > .wrap > .section-head > h2 {
    grid-column: 1; grid-row: 1 / span 2;
    max-width: 16ch;
  }
  [data-layout="editorial"] .section:nth-of-type(even) > .wrap > .section-head > p {
    grid-column: 2; grid-row: 2;
    margin-top: 0;
    max-width: none;
  }

  /* The sub-page head on the same margin as the sections under it. */
  [data-layout="editorial"] .pagehead > .wrap {
    grid-template-columns: minmax(0, .26fr) minmax(0, 1fr);
    column-gap: clamp(30px, 5vw, 84px);
    align-items: start;
  }
  [data-layout="editorial"] .pagehead__eyebrow {
    grid-column: 1; grid-row: 1;
    margin: 0;
    line-height: 1.7;
  }
  [data-layout="editorial"] .pagehead h1 { grid-column: 2; grid-row: 1; max-width: 15ch; }
  [data-layout="editorial"] .pagehead__lede { grid-column: 2; grid-row: 2; }

  /* The bill of fare's group named in the margin, the entries in a column
     beside it. A wide left margin with the text column not filling the page
     is the whole shape of this layout, and a price list is the one place it
     can be literal about it. */
  [data-layout="editorial"] .menu-group {
    display: grid;
    grid-template-columns: minmax(0, .26fr) minmax(0, 1fr);
    /* Stated, or the entry column's spare height is shared between the two
       rows and the group's note floats away from the name it belongs to. */
    grid-template-rows: auto 1fr;
    column-gap: clamp(30px, 5vw, 84px);
    align-items: start;
  }
  [data-layout="editorial"] .menu-group__name { grid-column: 1; grid-row: 1; line-height: 1.7; }
  [data-layout="editorial"] .menu-group__desc { grid-column: 1; grid-row: 2; }
  [data-layout="editorial"] .menu-list { grid-column: 2; grid-row: 1 / span 2; margin-top: 0; }

  /* The closer's ask at the left of the measure, the actions at the right of
     it, both hanging from the same rule. */
  [data-layout="editorial"] .closer__inner {
    flex-wrap: nowrap;
    justify-content: space-between;
  }
  [data-layout="editorial"] .closer__actions { flex: none; }

  /* The pull quote runs to a headline measure, which is what makes it read as
     display type rather than as a large paragraph. */
  [data-layout="editorial"] .review-quote { max-width: 26ch; }
  [data-layout="editorial"] .review-quote__text { max-width: 24ch; }
}

@media (max-width: 859px) {
  /* No margin column on a phone, so the folio becomes a line over the rule's
     heading instead of a thing hung beside it, and the standfirst stays under
     the heading on both the recto and the verso arrangement. */
  [data-layout="editorial"] .review-quote,
  [data-layout="editorial"] .review-quote__text { max-width: none; }

  /* One column, so the plate runs off both edges rather than one, and the
     crop opens out: a spread is a composition and a phone has no spread. */
  [data-layout="editorial"] .about__media { margin-inline: -20px; }
  [data-layout="editorial"] .about__media img { aspect-ratio: 4 / 3.2; }
}

/* ================================================================= bold ====
   A POSTER.

   WHAT THIS LAYOUT WAS. Fifty-eight selectors, and a property census of every
   one of them returned font-size, background, color, border, border-radius
   and opacity, and not one grid-template, display, flex-direction or
   grid-column. Every section on a bold page had the identical box model to
   the same section on a classic page, so the two differed by a radius and by
   two grounds. That is a recolour, and a recolour is the reason a stranger
   opening three of these reads one site done three times.

   And the one ground it did choose for itself it chose wrong. The comment
   over the block promised a colour block, and the colour it reached for was
   --primary, which is the darkest token in the palette by construction: every
   document on this layout sets a near black primary, so the poster's colour
   block was a black hero with an accent rule under it, which is the classic
   hero. The one saturated colour each of these businesses owns was spent on a
   10px stripe, a 4px mount round the photograph and a button.

   WHAT IT IS NOW. Three grounds and no fourth: the business's own colour, the
   deep ink, and the paper. A photograph is a ground in its own right, so it
   is never framed, never rounded and never inset; the accent mount this
   layout used to draw round the hero picture is the single most "made in a
   template builder" detail we had. Nothing is tinted, because a tint is a
   soft edge and the whole argument here is hard ones: the alternating band
   used to be an 86 percent wash toward white, the palest area on a page whose
   loudest area was the same colour at full strength two screens below it.

   NOTHING ON A COLOURED GROUND IS DIMMED. --accent-ink is the one ink
   measured against --accent, and every step away from it is a step back
   toward the ground. 82 percent of white over the red in this catalogue
   measures 3.81:1, under the floor, so there is no safe grey on the colour.
   Secondary type on the colour is therefore the same ink as primary type and
   the difference is carried by size, tracking and case, which is how a poster
   separates two lines anyway.

   ONE EYEBROW PER PAGE. The hero carries the locality, or the page head
   carries the breadcrumb. Every other tracked label on the page is switched
   off below, because the eyebrow, hairline, heading and grey lede stack was
   repeating up to fifteen times across a five page site and it was the reason
   the fee page and the gallery page opened with the same object.
   ========================================================================== */

/* --------------------------------------------------- bold: the two bands --- */
/*
   THE PALE BAND AND THE BLACK BAND TRADE PLACES.

   --alt was --accent-soft and --dark was the ground the gallery and the
   contact section shipped with, which gave a page one wash, one black band
   and a lot of paper in no order a reader could feel. Here the alternating
   band IS the black one, and the two sections that shipped dark come back
   onto paper, so the page alternates paper and ink from the hero down and the
   photographs in the gallery are the only thing on their own ground.

   Every token is redeclared rather than every rule restated. A service, a
   review, a price, a rule and a control are all written in tokens, so turning
   the tokens over turns the band over without this block having to know which
   sections can land on it.
*/
[data-layout="bold"] .section--alt {
  --focus: #fff;
  --page: var(--deep);
  --ink: #fff;
  --ink-2: rgb(255 255 255 / .82);
  --ink-3: rgb(255 255 255 / .74);
  --line: rgb(255 255 255 / .3);
  --surface: rgb(255 255 255 / .07);
  --card: rgb(255 255 255 / .06);
  /* --accent-strong is the accent taken toward the page's own ink, which on a
     near black ground is the accent taken toward black: measured on the blue
     in this catalogue it lands at 1.4:1 there. --accent-on-dark is the same
     colour lifted the other way and is measured against exactly this ground. */
  --accent-strong: var(--accent-on-dark);
  --on-deep: #fff;
  --on-deep-2: rgb(255 255 255 / .8);
  --on-deep-3: rgb(255 255 255 / .68);
  --panel: rgb(255 255 255 / .06);
  --panel-line: rgb(255 255 255 / .18);
  background: var(--deep);
  color: #fff;
}
[data-layout="bold"] .section--alt .stars__base { color: rgb(255 255 255 / .24); }
[data-layout="bold"] .section--alt .btn--outline { border-color: rgb(255 255 255 / .5); }
[data-layout="bold"] .section--alt .btn--outline:hover { background: rgb(255 255 255 / .1); border-color: #fff; }

[data-layout="bold"] .section--dark {
  --on-deep: var(--ink);
  --on-deep-2: var(--ink-2);
  --on-deep-3: var(--ink-3);
  --panel: var(--card);
  --panel-line: var(--line);
  --panel-today: var(--accent-soft);
  background: var(--page);
  color: var(--ink);
}
[data-layout="bold"] .section--dark .contact-status { color: var(--ok); }
[data-layout="bold"] .section--dark .contact-status--closed { color: var(--bad); }
[data-layout="bold"] .section--dark .stars__base { color: rgb(var(--primary-rgb) / .18); }

/* Two paper sections in a row are separated by the shared hairline rule, and
   the two that used to be dark are excluded from it because they used to have
   a ground of their own. They no longer do, so they need the seam. */
[data-layout="bold"] .section--dark + .section--dark {
  padding-top: clamp(38px, 5vw, 62px);
  border-top: 3px solid var(--ink);
}

/* Radius nought, whatever the document's theme says, because the point of the
   layout is edges. */
[data-layout="bold"] :is(
  .btn, .service, .feature, .step, .review, .booking__card, .panel,
  .rating-summary, .gallery figure, .about__media img, .service__icon,
  .feature__icon, .step__num, .chip, .bfield input, .bfield select,
  .bfield textarea, .map, .chat__panel, .hero__figure img, .product,
  .product__media, .cartline__media, .svc-row__icon, .hours__row,
  .hours__today, .contact-status, .status-pill, .nav-toggle, .chat__fab
) { border-radius: 0; }

/* ---------------------------------------------------- bold: the masthead --- */
/*
   A BLOCK OF THE BUSINESS'S COLOUR, ON EVERY PAGE AND IN EVERY STATE.

   The shared bar arrives with two capital letters in a filled square, pill
   shaped links, a black gradient painted down over the top of the page, and a
   blurred translucent ground the moment it sticks. Four of those are the
   chrome of an application and the fifth is a placeholder from a design tool.

   Here the bar is the same hard block of colour the hero and the page head
   are, so it never fades, never blurs and never changes colour on scroll: on
   this layout the top of the window is the business's colour from the first
   pixel to the last page. That is also what makes the initials box redundant.
   The name is the logo.
*/
body[data-layout="bold"] .site-header { background: var(--accent); border-bottom-color: transparent; }
[data-layout="bold"] .site-header::before { display: none; }
[data-layout="bold"] .site-header.is-stuck {
  background: var(--accent);
  backdrop-filter: none;
  box-shadow: none;
  border-bottom: 0;
}
[data-layout="bold"] .brand__mark { display: none; }
body[data-layout="bold"] .brand__name,
body[data-layout="bold"] .is-stuck .brand__name {
  font-size: clamp(1.05rem, 2.4vw, 1.42rem);
  letter-spacing: -0.035em;
  color: var(--accent-ink);
}
body[data-layout="bold"] .brand__meta,
body[data-layout="bold"] .is-stuck .brand__meta {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent-ink);
}
body[data-layout="bold"] .nav a,
body[data-layout="bold"] .is-stuck .nav a {
  padding: 9px 0;
  /* The mark under the current page is an inset shadow, and a shadow follows
     the radius: on a theme that rounds its controls the rule under the link
     came out as a smile. */
  border-radius: 0;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent-ink);
  background: none;
}
[data-layout="bold"] .nav { gap: clamp(8px, 1.6vw, 26px); }
body[data-layout="bold"] .nav a:hover,
body[data-layout="bold"] .is-stuck .nav a:hover {
  background: none;
  color: var(--accent-ink);
  box-shadow: inset 0 -3px 0 var(--accent-ink);
}
body[data-layout="bold"] .nav a[aria-current="page"] {
  color: var(--accent-ink);
  box-shadow: inset 0 -3px 0 var(--accent-ink);
}
body[data-layout="bold"] .header-tel,
body[data-layout="bold"] .is-stuck .header-tel {
  color: var(--accent-ink);
  font-weight: 700;
  font-variant-numeric: tabular-nums lining-nums;
}
body[data-layout="bold"] .status-pill,
body[data-layout="bold"] .is-stuck .status-pill { color: var(--accent-ink); }
body[data-layout="bold"] .nav-toggle,
body[data-layout="bold"] .is-stuck .nav-toggle { color: var(--accent-ink); border-radius: 0; }
body[data-layout="bold"] .nav-toggle:hover,
body[data-layout="bold"] .is-stuck .nav-toggle:hover {
  background: color-mix(in srgb, var(--accent-ink) 16%, var(--accent));
}
/* A filled accent pill on an accent bar is not a control. It becomes the one
   block of ink in the row instead, which is the same move the closing band
   makes with its own button. */
[data-layout="bold"] .header-actions .btn--accent {
  --btn-bg: var(--accent-ink);
  --btn-ink: var(--accent);
  box-shadow: none;
  font-weight: 700;
  letter-spacing: .02em;
}
[data-layout="bold"] .header-actions .btn--accent:hover {
  background: var(--accent-ink);
  transform: none;
  filter: none;
}
/* The stack variant's utility strip is the ink block above the colour one, so
   it is opaque rather than 94 percent of the primary over whatever is behind
   it, which on this layout is now the accent. */
[data-layout="bold"] .header-utility { background: var(--deep); }
/* The centred variant divides its two rows with a white hairline written for
   a bar sitting on a photograph. */
[data-layout="bold"] .nav { border-top-color: color-mix(in srgb, var(--accent-ink) 28%, var(--accent)); }

/* The drawer is the same block of colour, full screen, with the page names at
   the size the poster sets everything else. */
[data-layout="bold"] .mobile-nav { background: var(--accent); color: var(--accent-ink); }
[data-layout="bold"] .mobile-nav a {
  color: var(--accent-ink);
  border-bottom-color: color-mix(in srgb, var(--accent-ink) 24%, var(--accent));
  font-family: var(--font-heading);
  font-weight: var(--heading-weight);
  font-size: clamp(1.5rem, 7vw, 2.1rem);
  letter-spacing: -0.03em;
  text-transform: var(--heading-case);
}
[data-layout="bold"] .mobile-nav__meta { color: var(--accent-ink); }
[data-layout="bold"] .mobile-nav .btn--accent {
  --btn-bg: var(--accent-ink);
  --btn-ink: var(--accent);
  box-shadow: none;
}
[data-layout="bold"] .mobile-nav__social a { color: var(--accent-ink); }

/* -------------------------------------------------------- bold: the hero --- */
/*
   TWO GROUNDS AND ONE HARD EDGE BETWEEN THEM.

   The markup branch is new; see hero.blade.php. What it gives this block is a
   .hero__poster carrying the type on the colour and a .hero__band carrying
   the photograph full width underneath it, so the arrangement is the same
   composition at 375px as it is at 1440 rather than a two column grid that
   collapses into the editorial hero the moment the window narrows.

   The clearance is the other half of it. --hero-clear has said 46px since the
   header variants landed and this hero has never once got it: the rule that
   turns a clearance into a padding fires only for the two tall header
   variants, and six of these seven sites draw neither, so the hero carried a
   hardcoded 120px instead. Measured at 375px that left eleven pixels between
   a fixed bar and the largest type on the site, and at 1280px it left one.
*/
.hero--bold {
  display: block;
  align-items: initial;
  background: var(--page);
  padding: 0;
  min-height: 0;
  max-height: none;
}
/* Without a photograph the bold hero was also .hero--noimage, and that rule
   (0,2,0) outranked the reset above (0,1,0): 150px of top padding and 68svh of
   height landed on the section around the poster, which clears the bar on its
   own, and the reader got a band of empty page between the header and the
   colour. Three classes, so this wins wherever it sits in the file. */
.hero.hero--noimage.hero--bold { padding: 0; min-height: 0; }
body[data-layout="bold"] .hero--bold {
  --focus: var(--accent-ink);
}
[data-layout="bold"] .hero__poster {
  background: var(--accent);
  color: var(--accent-ink);
  padding-top: calc(var(--header-top) + var(--header-h) + var(--hero-clear));
  padding-bottom: clamp(36px, 5.5vw, 72px);
}
[data-layout="bold"] .hero__head,
[data-layout="bold"] .hero__body,
[data-layout="bold"] .hero__foot { max-width: none; }
/* The trust row's hairline arrangement answers to the width of the column it
   is in rather than to the window, and the column it is in is no longer
   .hero__inner. */
[data-layout="bold"] .hero__foot { container-type: inline-size; container-name: heroinner; }
[data-layout="bold"] .hero__foot:empty { display: none; }

.hero--bold h1 {
  font-size: clamp(2.9rem, 9.2vw, 6.4rem);
  line-height: .94;
  max-width: 15ch;
}
body[data-layout="bold"] .hero--bold .eyebrow {
  color: var(--accent-ink);
  font-size: 12px;
  letter-spacing: .2em;
  margin-bottom: clamp(16px, 2.6vw, 26px);
}
body[data-layout="bold"] .hero--bold .eyebrow::before {
  width: 44px;
  height: 5px;
  background: var(--accent-ink);
}
.hero--bold .hero__sub {
  color: var(--accent-ink);
  max-width: 44ch;
  font-size: clamp(1.06rem, 2.1vw, 1.3rem);
  font-weight: 500;
  margin-top: clamp(20px, 3vw, 30px);
}
.hero--bold .hero__actions { margin-top: clamp(26px, 3.6vw, 38px); }
.hero--bold .btn--accent {
  --btn-bg: var(--accent-ink);
  --btn-ink: var(--accent);
  box-shadow: none;
}
.hero--bold .btn--accent:hover { background: var(--accent-ink); transform: none; }
.hero--bold .btn--ghost {
  --btn-ink: var(--accent-ink);
  border: 3px solid var(--accent-ink);
  backdrop-filter: none;
}
.hero--bold .btn--ghost:hover {
  background: none;
  border-color: var(--accent-ink);
  transform: none;
}
.hero--bold .trust {
  color: var(--accent-ink);
  border-top: 4px solid var(--accent-ink);
  padding-top: clamp(16px, 2.4vw, 22px);
  font-weight: 600;
}
.hero--bold .trust__score { color: var(--accent-ink); }
.hero--bold .trust__item { border-left-color: color-mix(in srgb, var(--accent-ink) 36%, var(--accent)); }
.hero--bold .stars__fill { color: var(--accent-ink); }
.hero--bold .stars__base { color: color-mix(in srgb, var(--accent-ink) 30%, var(--accent)); }

/* The photograph as a ground, not as an object on one. No mount, no radius,
   no inset, and it runs the full window at every width. */
[data-layout="bold"] .hero__band {
  display: block;
  margin: 0;
  height: clamp(230px, 44vw, 470px);
  overflow: hidden;
  background: var(--deep);
}
[data-layout="bold"] .hero__band img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 0;
}
[data-layout="bold"] .hero__band:empty { display: none; }

/* ---------------------------------------------------- bold: the page head --- */
/*
   FOUR PAGES IN FIVE USED TO OPEN ON SOMEBODY ELSE'S LAYOUT.

   The whole visual argument was spent on the front page. /tjanster, /galleri,
   /om-oss and /kontakt opened on white paper closed by a hairline, with a
   heading two thirds the size of the one on the home page, which is exactly
   what a minimal or a classic sub-page opens with. A reader arriving from
   search on any of those four never saw the layout at all.

   They open on a block now, at the same scale the hero uses. And not all on
   the same block: two of the five take the ink instead of the colour, so a
   reader moving through one site meets two fronts rather than the same
   rectangle five times. Which two is fixed per page rather than dealt,
   because the variants are dealt per site and cannot vary inside one.
*/
[data-layout="bold"] .pagehead {
  background: var(--accent);
  color: var(--accent-ink);
  border-bottom: 0;
  --focus: var(--accent-ink);
  padding-top: calc(var(--header-top) + var(--header-h) + clamp(38px, 7vw, 90px));
  padding-bottom: clamp(34px, 5.5vw, 74px);
}
[data-layout="bold"] .pagehead h1 {
  font-size: clamp(2.6rem, 9.5vw, 6rem);
  line-height: .94;
  max-width: 13ch;
}
[data-layout="bold"] .pagehead__eyebrow {
  margin-bottom: clamp(14px, 2.4vw, 22px);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent-ink);
}
[data-layout="bold"] .pagehead__eyebrow a { color: var(--accent-ink); }
[data-layout="bold"] .pagehead__eyebrow a:hover { color: var(--accent-ink); text-decoration: underline; }
[data-layout="bold"] .pagehead__lede {
  color: var(--accent-ink);
  max-width: 38ch;
  font-size: clamp(1.02rem, 1.9vw, 1.18rem);
  font-weight: 500;
}
[data-layout="bold"]:is([data-page="gallery"], [data-page="contact"]) .pagehead {
  background: var(--deep);
  color: #fff;
  --focus: #fff;
}
[data-layout="bold"]:is([data-page="gallery"], [data-page="contact"]) .pagehead__eyebrow,
[data-layout="bold"]:is([data-page="gallery"], [data-page="contact"]) .pagehead__eyebrow a,
[data-layout="bold"]:is([data-page="gallery"], [data-page="contact"]) .pagehead__lede { color: #fff; }
/* Where the ink page head meets the ink band, the two grounds are the same
   ground and the seam is nothing but two paddings added together. The edge
   gets drawn instead, in the one colour that is not either of them. */
[data-layout="bold"] .pagehead + .section--alt { border-top: 8px solid var(--accent); }

/* ------------------------------------------- bold: how a section opens --- */
/*
   THE ONE THING EVERY LAYOUT IN THIS FILE DID IDENTICALLY.

   A tracked eyebrow behind a short accent bar, a heading, and a grey line of
   lede, stacked inside a 640px column. Drawn once it is a heading. Drawn
   fifteen times across five pages it is the stamp, and the reader cannot tell
   the fee page from the gallery page except by reading the words.

   A poster opens with scale and nothing else. The label goes, because the
   heading below it was saying the same word in larger type; the column goes,
   because the heading is the widest thing on the page; and the lede moves
   beside the heading rather than under it, so the two are one object on one
   baseline rather than three stacked ones.

   Scoped to a head that is a direct child of .wrap: the FAQ nests its head
   inside one column of a two column grid, and splitting that again leaves a
   300px heading next to a 300px paragraph.
*/
[data-layout="bold"] .section .eyebrow { display: none; }
[data-layout="bold"] .section-head {
  max-width: none;
  margin-bottom: clamp(30px, 4.2vw, 54px);
}
[data-layout="bold"] .section-head h2,
[data-layout="bold"] .about__body h2,
[data-layout="bold"] .booking__intro h2 {
  font-size: clamp(2.3rem, 7.4vw, 4.8rem);
  line-height: .96;
  max-width: 15ch;
}
[data-layout="bold"] .section-head h2.h2--small { font-size: clamp(1.7rem, 4vw, 2.4rem); }
[data-layout="bold"] .section-head p:not(.eyebrow) {
  font-size: clamp(1.02rem, 1.8vw, 1.16rem);
  max-width: 40ch;
}
[data-layout="bold"] .faq-grid .section-head h2 { font-size: clamp(1.8rem, 4.4vw, 2.6rem); }
/* A 54px tab of accent under a heading is a card's mark. A poster's is a rule
   across the whole measure, in whatever ink the block it sits in is written
   in, which is what makes it work on the overlay and on paper alike. */
[data-layout="bold"] .about__rule {
  width: 100%;
  height: 4px;
  background: currentColor;
  margin: clamp(18px, 2.4vw, 26px) 0;
}

/* ------------------------------- bold: the work, and what it costs --- */
/*
   THE FEE SCHEDULE IS A TABLE.

   Every price on this layout is set in the same three ways wherever it
   appears: at the size of the thing it prices, in the page's own ink rather
   than in the accent, and with tabular lining figures so a column of them can
   be read down. What it is not is a restaurant card with dotted leaders, and
   what it is not is a right hand column of accent coloured numerals, which a
   reader scans as a column of links before they have read a single name.

   The boxes go with it. A row of bordered cards is the shape of a template,
   and at this scale a card outline reads as a box drawn round the whole
   section. What separates one item from the next is a rule as heavy as the
   type above it.
*/
[data-layout="bold"] .services { grid-template-columns: minmax(0, 1fr); gap: 0; }
[data-layout="bold"] .service {
  flex-wrap: wrap;
  border: 0;
  border-top: 3px solid var(--ink);
  background: transparent;
  padding: clamp(18px, 2.8vw, 30px) 0;
  gap: 4px clamp(24px, 4vw, 56px);
  align-items: baseline;
  transition: none;
}
[data-layout="bold"] .services > .service:last-child { border-bottom: 3px solid var(--ink); }
[data-layout="bold"] .service:hover {
  background: transparent;
  color: inherit;
  transform: none;
  box-shadow: none;
  border-color: var(--ink);
}
[data-layout="bold"] .service__icon { display: none; }
[data-layout="bold"] .service__body { flex: 1 1 240px; }
[data-layout="bold"] .service h3 {
  font-size: clamp(1.45rem, 4.4vw, 2.5rem);
  line-height: 1.03;
  letter-spacing: -0.025em;
}
[data-layout="bold"] .service p { margin-top: 8px; max-width: 52ch; font-size: 15.5px; }
[data-layout="bold"] .service__meta {
  width: auto;
  flex: none;
  margin: 0 0 0 auto;
  padding-top: 0;
  border-top: 0;
  min-height: 0;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}
[data-layout="bold"] .service__price {
  margin: 0;
  font-weight: var(--heading-weight-strong);
  font-size: clamp(1.3rem, 3.6vw, 2.1rem);
  line-height: 1.1;
  color: var(--ink);
  font-variant-numeric: tabular-nums lining-nums;
}

/* The same treatment on the rows variant, which already ran full width and
   banded every second row in --surface. A zebra is a table's device and this
   is not a table of two hundred rows, it is five things a business does. */
[data-layout="bold"] .svc-row {
  margin-inline: 0;
  padding: clamp(20px, 3.2vw, 34px) 0;
  border-top: 3px solid var(--ink);
  align-items: baseline;
}
[data-layout="bold"] .svc-row:last-child { border-bottom: 3px solid var(--ink); }
[data-layout="bold"] .svc-row:nth-child(even) { background: transparent; }
[data-layout="bold"] .svc-row__icon { display: none; }
[data-layout="bold"] .svc-row__name {
  font-size: clamp(1.5rem, 5vw, 3rem);
  line-height: 1;
  letter-spacing: -0.03em;
}
[data-layout="bold"] .svc-row__price {
  font-weight: var(--heading-weight-strong);
  font-size: clamp(1.3rem, 3.6vw, 2.1rem);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="bold"] .svc-rows:has(> :nth-child(6)) .svc-row__name { font-size: clamp(1.3rem, 3.4vw, 2rem); }

/* The bill of fare, as a schedule rather than as a printed card. The leader
   dots go, the name and the figure become two columns of a grid so every
   figure lands on one right edge, and the group name is a heading rather than
   a label with a 2px accent bar under it. */
[data-layout="bold"] .menu-groups { grid-template-columns: minmax(0, 1fr); gap: clamp(36px, 5vw, 64px); }
[data-layout="bold"] .menu-group { border-top: 6px solid var(--ink); padding-top: clamp(14px, 2vw, 20px); }
[data-layout="bold"] .menu-group__name {
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  font-size: clamp(1.5rem, 4.4vw, 2.5rem);
  line-height: 1.02;
  letter-spacing: -0.025em;
}
[data-layout="bold"] .menu-group__desc { margin: 8px 0 0; max-width: 46ch; }
[data-layout="bold"] .menu-list { margin-top: 14px; }
[data-layout="bold"] .menu-item { padding: 14px 0; border-bottom: 2px solid var(--line); }
[data-layout="bold"] .menu-item:last-child { border-bottom: 2px solid var(--line); }
[data-layout="bold"] .menu-item__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: clamp(20px, 3vw, 48px);
  align-items: baseline;
}
[data-layout="bold"] .menu-item__lead { display: none; }
[data-layout="bold"] .menu-item__name { font-size: 1.08rem; }
[data-layout="bold"] .menu-item__price {
  font-family: var(--font);
  font-size: 1.08rem;
  font-weight: 650;
  color: var(--ink);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="bold"] .menu-item__desc { max-width: 54ch; }
[data-layout="bold"] .menu-note { border-top-width: 3px; border-top-color: var(--ink); }

/* ------------------------------------ bold: the facts and the process --- */
/*
   A PROCESS IS INFORMATION, NOT FOUR DISCS ON A LINE.

   Both shapes this layout can be dealt draw a numeral. On the numbered
   variant it is already a figure over a rule, and it comes up to poster size
   here. On the row variant it is a 40px filled circle with a number inside
   it, which is an icon standing in for a step rather than the step, so the
   circle goes and the numeral is set as a numeral in the margin beside what
   it names.
*/
[data-layout="bold"] .feat-num { grid-template-columns: minmax(0, 1fr); gap: 0; }
[data-layout="bold"] .feat-num__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  column-gap: clamp(18px, 3.4vw, 44px);
  align-items: start;
  border-top: 3px solid var(--ink);
  padding: clamp(14px, 2.2vw, 24px) 0;
}
[data-layout="bold"] .feat-num__n {
  grid-column: 1;
  grid-row: 1 / span 2;
  margin: 0;
  font-size: clamp(2.2rem, 7vw, 4.2rem);
  color: var(--ink);
}
[data-layout="bold"] .feat-num__title { grid-column: 2; grid-row: 1; font-size: clamp(1.1rem, 2.6vw, 1.4rem); }
[data-layout="bold"] .feat-num__body { grid-column: 2; grid-row: 2; max-width: 52ch; font-size: 15.5px; }

[data-layout="bold"] .feature {
  border: 0;
  border-top: 3px solid var(--ink);
  background: transparent;
  padding: clamp(14px, 2.2vw, 22px) 0;
}
[data-layout="bold"] .feature__icon { display: none; }
[data-layout="bold"] .feature h3 { font-size: clamp(1.05rem, 2.4vw, 1.35rem); }

/* The band of facts. Every rule in it is a hairline, which on this layout is
   a rule nobody can see, and each fact carries a 19px pictogram standing in
   for a word that is already written beside it. */
[data-layout="bold"] .feat-strip { border-block: 3px solid var(--ink); }
[data-layout="bold"] .feat-strip__icon { display: none; }
[data-layout="bold"] .feat-strip__item { grid-template-columns: minmax(0, 1fr); }
[data-layout="bold"] .feat-strip__title { font-size: clamp(1.05rem, 2.4vw, 1.32rem); }
[data-layout="bold"] .feat-strip__item + .feat-strip__item,
[data-layout="bold"] .feat-strip__item:nth-child(n + 3) { border-top-color: var(--ink); border-top-width: 2px; }
[data-layout="bold"] .feat-strip__item:nth-child(even) { border-left-color: var(--ink); border-left-width: 2px; }

[data-layout="bold"] .steps { gap: 0; }
[data-layout="bold"] .steps .step {
  border: 0;
  border-top: 3px solid var(--ink);
  background: transparent;
  padding: clamp(16px, 2.4vw, 26px) 0;
  gap: clamp(18px, 3.4vw, 44px);
  align-items: baseline;
}
[data-layout="bold"] .steps .step__num {
  width: auto;
  height: auto;
  display: block;
  background: none;
  color: var(--ink);
  border-radius: 0;
  font-size: clamp(2rem, 6vw, 3.4rem);
  line-height: 1;
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="bold"] .steps .step h3 { font-size: clamp(1.1rem, 2.6vw, 1.4rem); }
[data-layout="bold"] .steps .step p { max-width: 52ch; }

/*
   THE BOOKING BAND IS A BAND, NOT A WASH.

   The panel variant lays the accent over the section at 12 percent so it
   reads as a band on every layout. Here the section it lands on is already
   the ink band, and the variant's rule is (0,3,0) against this scope's
   (0,2,0), so the wash won and the white type this block had just turned over
   was being drawn on a 12 percent tint: measured on the green in this
   catalogue, white on rgb(62 147 99 / .12) over paper is 1.1:1. It takes the
   band's own ground, and the raised card under it loses the shadow, which is
   the one object on a poster that is not flat.
*/
[data-layout="bold"][data-v-booking="panel"] .section--alt:has(> .wrap > .booking) { background: var(--deep); }
[data-layout="bold"] .booking__card {
  border: 3px solid var(--ink);
  background: transparent;
  box-shadow: none;
}
[data-layout="bold"] .bfield input,
[data-layout="bold"] .bfield select,
[data-layout="bold"] .bfield textarea { border-width: 2px; }

/* ----------------------------------------------------- bold: the reviews --- */
/*
   NO WIDGET, EITHER SHAPE.

   The pool this layout draws from used to hold the marquee, which is a wall
   of bordered boxes that scrolls itself, and that is the review widget the
   verdict names, by name. What is left is one review at poster size, or all
   of them as full width blocks divided by a rule. Neither is a box and
   neither has an avatar in it.
*/
[data-layout="bold"] .rating-summary { border-bottom-width: 4px; border-bottom-color: var(--ink); }
[data-layout="bold"] .rating-summary__score { font-size: clamp(3.6rem, 12vw, 6.5rem); }
[data-layout="bold"] .rating-summary__badge { display: none; }
[data-layout="bold"] .review__avatar { display: none; }
[data-layout="bold"] .review-quote__mark { display: none; }
[data-layout="bold"] .review-quote__text {
  margin-top: 0;
  font-size: clamp(1.7rem, 6vw, 3.6rem);
  line-height: 1.05;
  max-width: 18ch;
  color: var(--ink);
}
[data-layout="bold"] .review-quote { max-width: none; }
[data-layout="bold"] .review-lines { max-width: none; border-top-width: 3px; border-top-color: var(--ink); }
[data-layout="bold"] .review-line { border-bottom-width: 2px; padding: 18px 0; }
[data-layout="bold"] .reviews-hint { display: none; }

[data-layout="bold"][data-v-reviews="cards"] .reviews {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  margin-inline: 0;
  padding: 0;
  overflow: visible;
}
[data-layout="bold"][data-v-reviews="cards"] .review {
  border: 0;
  border-top: 3px solid var(--ink);
  background: transparent;
  padding: clamp(20px, 3vw, 32px) 0;
}
[data-layout="bold"][data-v-reviews="cards"] .reviews > .review:last-child { border-bottom: 3px solid var(--ink); }
[data-layout="bold"][data-v-reviews="cards"] .review__text {
  font-size: clamp(1.1rem, 2.6vw, 1.45rem);
  line-height: 1.42;
  max-width: 34ch;
}
[data-layout="bold"][data-v-reviews="cards"] .review__author {
  margin-top: 16px;
  padding-top: 0;
  border-top: 0;
}

/* -------------------------------------------- bold: where and when open --- */
/*
   The contact panel arrives as a bordered card with a rounded label in the
   accent, a pill with a green wash behind it and a week of hours indented
   inside the box. That is four different shapes in one small block and three
   of them are borrowed from an application. What it needs to be is a column:
   a rule, a label, and the week under it.
*/
[data-layout="bold"] .panel {
  border: 0;
  border-top: 3px solid var(--ink);
  background: transparent;
  padding: clamp(14px, 2.2vw, 22px) 0 0;
}
[data-layout="bold"] .panel h3 {
  color: var(--ink);
  font-size: 11px;
  letter-spacing: .2em;
  margin-bottom: 14px;
}
[data-layout="bold"] .hours__row { padding-inline: 0; }
/* Today is marked by weight and by ink, which the base already sets. The wash
   behind it is a highlighter pen on a poster. */
[data-layout="bold"] .hours__row.is-today { background: transparent; }
[data-layout="bold"] .contact-status {
  padding: 0;
  border-radius: 0;
  background: transparent;
  margin-bottom: 18px;
}
[data-layout="bold"] .map { border: 0; }

/* ------------------------------------------------- bold: the photographs --- */
/* Nothing is drawn round a photograph, and the gaps between them close to the
   width of a rule so a wall of pictures reads as one block rather than as a
   grid of tiles. */
[data-layout="bold"] .gallery { gap: 5px; }
[data-layout="bold"] .gallery figure { background: var(--deep); }
[data-layout="bold"] .gallery figure:hover img { transform: none; }
[data-layout="bold"] .about__media img { aspect-ratio: 4 / 4.4; }

/* ------------------------------------------------------ bold: the closer --- */
/*
   THE SAME SLAB AT FIVE URLS.

   Every page ended on one shared band: a status pill, a heading, a line, and
   two buttons, on the lifted surface. Five pages of one site drew it five
   times, and so did forty-four other sites, which is why it reads as a
   platform's footer rather than as this business asking.

   Here it is a block, like everything else on the page, and which block
   depends on what it follows: after the ink band it takes the colour, and
   after paper it takes the ink. So the page that ends on reviews and the page
   that ends on a gallery do not end the same way, and neither ends the way
   the front page does, which closes on its own written ask.
*/
[data-layout="bold"] .closer {
  border-top: 0;
  background: var(--deep);
  color: #fff;
  --focus: #fff;
}
[data-layout="bold"] .closer h2 { font-size: clamp(1.9rem, 5.4vw, 3.4rem); line-height: 1; max-width: 16ch; }
[data-layout="bold"] .closer p { color: rgb(255 255 255 / .84); }
[data-layout="bold"] .closer .status-pill { color: rgb(255 255 255 / .84); }
[data-layout="bold"] .closer__actions .btn--accent { box-shadow: none; }
[data-layout="bold"] .closer__actions .btn--outline {
  --btn-ink: #fff;
  border: 3px solid rgb(255 255 255 / .55);
  min-height: 58px;
  padding: 16px 30px;
  font-size: 16.5px;
}
[data-layout="bold"] .closer__actions .btn--outline:hover { background: rgb(255 255 255 / .1); border-color: #fff; }

[data-layout="bold"] .section--alt + .closer {
  background: var(--accent);
  color: var(--accent-ink);
  --focus: var(--accent-ink);
}
[data-layout="bold"] .section--alt + .closer p,
[data-layout="bold"] .section--alt + .closer .status-pill { color: var(--accent-ink); }
[data-layout="bold"] .section--alt + .closer .btn--accent {
  --btn-bg: var(--accent-ink);
  --btn-ink: var(--accent);
}
[data-layout="bold"] .section--alt + .closer .btn--accent:hover { background: var(--accent-ink); }
[data-layout="bold"] .section--alt + .closer .btn--outline {
  --btn-ink: var(--accent-ink);
  border-color: var(--accent-ink);
}
[data-layout="bold"] .section--alt + .closer .btn--outline:hover { background: none; border-color: var(--accent-ink); }

/* The written ask, on the front page only. It is the colour block the page
   opened on, closing it. */
[data-layout="bold"] .cta-band { padding: clamp(56px, 8vw, 104px) 0; }
[data-layout="bold"] .cta-band h2 { font-size: clamp(2.2rem, 7vw, 5rem); line-height: .96; max-width: 16ch; }
[data-layout="bold"] .cta-band p { opacity: 1; font-weight: 500; max-width: 40ch; }
[data-layout="bold"] .cta-band .btn--accent:hover { filter: none; }

/* ------------------------------------------------------ bold: the imprint --- */
/* The last thing on the page is the name, at the size the first thing on it
   was, over the one rule on the site heavy enough to be a block. Everything
   under the name is small print and is set as small print. */
[data-layout="bold"] .site-footer { border-top: 12px solid var(--accent); }
[data-layout="bold"] .site-footer__name {
  font-size: clamp(1.5rem, 5vw, 2.6rem);
  line-height: 1;
  letter-spacing: -0.035em;
  color: var(--accent-on-dark);
}
[data-layout="bold"] .site-footer__heading {
  font-size: 10.5px;
  letter-spacing: .2em;
}

/* ========================================================= bold: 700px ==== */

@media (min-width: 700px) {
  [data-layout="bold"] .feat-num { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(30px, 4vw, 60px); }
}

/* ========================================================= bold: 860px ==== */

@media (min-width: 860px) {
  /*
     The heading and the line under it used to sit in one 640px column,
     stacked, which is the shape of the page head forty pixels above it and
     the reason two heads in a row read as one repeated thing. Here they are
     two columns sharing a baseline: the heading takes the measure it needs,
     the line that explains it sits beside its foot.
  */
  [data-layout="bold"] .wrap > .section-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, .52fr);
    column-gap: clamp(32px, 5vw, 80px);
    align-items: end;
  }
  [data-layout="bold"] .wrap > .section-head > h2 { grid-column: 1; margin: 0; max-width: none; }
  [data-layout="bold"] .wrap > .section-head > p:not(.eyebrow) { grid-column: 2; margin: 0 0 .45em; }

  /* The poster's front: the type on the colour holds a measure rather than
     running the full window, because a 7rem headline across 1180px is a
     banner and not a poster. */
  [data-layout="bold"] .hero__poster { padding-bottom: clamp(48px, 6vw, 84px); }

  /* The page head's running line drops onto the headline's last baseline, and
     a headline set this large has three of them. Start it instead, level with
     the first, or it hangs in the middle of nothing. */
  [data-layout="bold"] .pagehead > .wrap { align-items: start; }
  [data-layout="bold"] .pagehead__lede { margin: .55em 0 0; }

  [data-layout="bold"] .service { flex-wrap: nowrap; }
  [data-layout="bold"] .services:has(> :nth-child(4)):not(:has(> :nth-child(5))) {
    grid-template-columns: minmax(0, 1fr);
  }
  [data-layout="bold"] .services:has(> :nth-child(4)):not(:has(> :nth-child(5))) > .service {
    flex-direction: row;
  }
}

/* ========================================================= bold: 560px ==== */

@media (max-width: 559px) {
  /* At this width the poster is the only thing carrying the layout, so the
     edges it is built out of scale with it rather than staying at the
     hairline sizes that made the phone version of this page hard to tell from
     the phone version of a classic one. */
  [data-layout="bold"] .service,
  [data-layout="bold"] .svc-row,
  [data-layout="bold"] .feat-num__item,
  [data-layout="bold"] .feature,
  [data-layout="bold"] .steps .step,
  [data-layout="bold"][data-v-reviews="cards"] .review { border-top-width: 2px; }
  [data-layout="bold"] .services > .service:last-child,
  [data-layout="bold"] .svc-row:last-child,
  [data-layout="bold"][data-v-reviews="cards"] .reviews > .review:last-child { border-bottom-width: 2px; }
}


/* ============================================================== minimal ====
   ==========================================================================

   WHAT THIS LAYOUT IS, NOW THAT IT IS SOMETHING.

   One column of type, at one size, set on a measure and held in the middle of
   a lot of white, with photographs as the only wide objects on the page. The
   design is the interval and the measure. Nothing else is drawn: no fills, no
   cards, no shadows and no second ground. The only rules left on the site are
   inside the three blocks that are genuinely tables, the price list, the
   service schedule and the rating ledger, where a line does work a space
   cannot.

   WHAT IT WAS. A hundred lines that took the classic page and removed things
   from it. Every ground was flattened to white, every card border was set to
   zero, and the result was the base stylesheet with its grounds switched off:
   3900 pixels of undifferentiated white on a phone, separated by hairlines,
   with a centred eyebrow, a centred serif h2 and a centred grey lede stamped
   on top of it up to fifteen times across a five page site. Nine of those
   rules styled a services variant this layout is forbidden to be dealt and
   drew nothing at all. It looked empty, which is the one way quiet fails.

   THE FOUR DECISIONS EVERYTHING BELOW COMES OUT OF.

   1. ONE MEASURE, AND A RAIL BESIDE IT. Every block of words on every page is
      the same 640px column, set flush left. From 1040px a 300px rail stands
      to the left of it holding the section's name, and the frame is exactly
      the two of them plus the gutter, so the page fills its frame and its
      margins are equal. Photographs are the exception and run the whole
      frame. A measure alone, hung from the left of the frame, was read by
      every stranger who saw it as half a screen of nothing; see "the measure"
      below.

      Flush left inside a centred column, not centred text. Centred multi-line
      body copy is the template tell the verdict names, and it was worse than
      that here: on the column reviews the section head was centred in the
      page, the review column was pinned to the left of the wrap, the review
      text was centred inside it and the author row was flush left. Four
      alignments in one section. There is one alignment now, on every page.

   2. A HEADING IS A STEP, NOT A SHOUT. A section heading is 1.95rem against
      a 1.06rem body: under twice the size, where the base stylesheet makes it
      two and a half times. It used to be a fifth larger, on the theory that
      the white above it would announce the section, and nobody reading the
      page could tell where a section started. Size and the rail announce it
      now. The front page headline and the sub-page title stay the single
      large thing on their page.

   3. NO EYEBROWS, NO GROUNDS, NO SEAMS. The eyebrow is gone from every
      section: the hero's locality and the sub-page breadcrumb are the one per
      page that survive. The alternate and dark bands are painted the page,
      which they already were, but now the rhythm follows the ground rather
      than the class names, so two sections are the same distance apart
      wherever they land. It used to vary two to one inside one page because
      the shared seam rule keys on a class whose meaning this layout erased.

   4. ONE FILLED CONTROL. The hero's primary action and the submit button of a
      form are filled. Every other button on the site is an underlined word,
      because a page with eleven buttons on it has no primary action, and
      because the second call to action at the foot of every page was the only
      block of colour in the whole layout and it was spending it on
      boilerplate.

   SPECIFICITY. Nearly every selector here is [data-layout="minimal"] X, which
   is (0,2,0) and beats the plain rules inside the 560, 860 and 1080px media
   queries higher up the file at every width. Anything that has to change WITH
   the viewport is written into this block's own media queries at the end.
   ========================================================================= */

body[data-layout="minimal"] {
  /*
     THE MEASURE. About sixty-four characters at this body size, which is the
     width a paragraph is set to when somebody expects it to be read rather
     than scanned. Everything that is words takes it; photographs do not.
  */
  --col: 640px;

  /*
     THE SIDE COLUMN, AND THE SPACE BETWEEN THE TWO.

     The measure alone is not a composition. Hung from the left edge of a
     1020px frame it left a fifth of the window empty down the right of every
     section, which three readers in a row called an unfinished page rather
     than a quiet one. So the page is two columns from 1040px up: the section's
     name and standfirst in this rail, the work in the measure beside it, and
     the white between them instead of beside everything.

     The rail is wide enough for two or three words of a heading per line and
     narrow enough that it can never be mistaken for a second measure.
  */
  --rail: 300px;
  --gutter: clamp(36px, 4.6vw, 72px);

  /* The interval between two things inside one section. One number, used by
     the space under a section head and by the gap inside every list, so the
     page has a rhythm rather than eleven unrelated paddings. */
  --beat: clamp(26px, 3.4vw, 44px);

  /*
     A MISSING CUT MUST FAIL, NOT BE FAKED.

     --font-heading can resolve to a display face with one weight and no
     italic. Asking such a face for a bold gets a browser-synthesised smear.
     With synthesis off it stays at the weight the face actually has, which is
     the honest answer and the register this layout wants anyway.
  */
  font-synthesis: none;
}

/* ------------------------------------------------------ minimal: rhythm --- */

/*
   ONE INTERVAL, WHATEVER THE CLASSES SAY.

   Every band on this layout is the page's own ground, so the shared rule that
   halves the seam between two sections sharing a class was firing on some
   pairs and not on others with nothing visible to explain the difference:
   measured on a contact page, an alt band next to a dark band, both white,
   kept 227px of empty white between two subjects while two alt bands on the
   front page got 124. Same site, same layout, seams differing by a factor of
   two. The interval is the design here, so it is stated once and it is the
   same everywhere.
*/
[data-layout="minimal"] .section { padding: clamp(40px, 5vw, 76px) 0; }
[data-layout="minimal"] .section--tight { padding: clamp(34px, 4vw, 58px) 0; }
[data-layout="minimal"] .section + .section {
  padding-top: clamp(40px, 5vw, 76px);
  border-top: 0;
}
[data-layout="minimal"] .section:has(+ .section) { padding-bottom: clamp(40px, 5vw, 76px); }

/* There is no second ground on this layout and there is no third. The dark
   bands keep their token names so nothing inside them has to know. */
[data-layout="minimal"] .section--alt { background: var(--page); }
[data-layout="minimal"] .section--dark {
  --on-deep: var(--ink);
  --on-deep-2: var(--ink-2);
  --on-deep-3: var(--ink-3);
  --panel: transparent;
  --panel-line: var(--line);
  --panel-today: transparent;
  background: var(--page);
  color: var(--ink);
}
[data-layout="minimal"] .section--dark .stars__base { color: rgb(var(--primary-rgb) / .18); }
/* The open and closed inks are the light-ground ones, because the ground here
   is light. Restating them as literals is what the old block did, and one of
   the two literals measured 3.08:1. */
[data-layout="minimal"] .section--dark .contact-status { color: var(--ok); }
[data-layout="minimal"] .section--dark .contact-status--closed { color: var(--bad); }
[data-layout="minimal"] .section--dark .btn--ghost { --btn-ink: var(--ink); }

/* ------------------------------------------------- minimal: the measure --- */

/*
   THE TWO RULES THAT MAKE THE LAYOUT: A MEASURE, AND A RAIL BESIDE IT.

   Every block of words is still the same 640px column, still flush left, and
   photographs are still the only wide objects on the page. What has changed is
   what sits to the left of that column.

   WHY IT CHANGED. One column hung from the left edge of a 1020px frame is a
   defensible idea on paper and it did not survive being looked at. Read cold,
   from screenshots, by people who had not been told what the layout was for,
   it came back the same way every time: a page whose right half is empty, no
   grid, one narrow rail down the left. That is three strangers describing one
   picture. A register that has to be explained before it reads as restraint is
   not restraint yet, it is an unfinished page.

   WHAT IT IS NOW. From 1040px the section's wrap is two columns: the heading
   and its standfirst in a 300px rail, everything else in the measure beside
   it. The frame is exactly rail plus gutter plus measure, so the composition
   fills it corner to corner and the white lands where white belongs, between
   the name of a thing and the thing, not beside the whole page. The margins
   left and right of the frame are then equal, which is the other half of what
   the readers were complaining about.

   The left edge survives, which was the point of the old rule. Every section
   head, every photograph and the first column of the imprint still start on
   one vertical; the body copy starts on a second one, and two verticals a
   reader can name are a grid where one was a rail.

   BELOW 1040 there is no room for a rail, so the head goes back over the
   measure and the page is the single column it always was on a phone.
*/
[data-layout="minimal"] .wrap {
  max-width: calc(var(--rail) + var(--gutter) + var(--col) + 40px);
}
[data-layout="minimal"] .section > .wrap > *,
[data-layout="minimal"] .closer > .wrap > *,
[data-layout="minimal"] .cta-band > .wrap > * {
  max-width: var(--col);
  margin-inline: 0;
}
[data-layout="minimal"] .section > .wrap > .gallery,
[data-layout="minimal"] .section > .wrap > .about,
[data-layout="minimal"] .section > .wrap > .shop,
[data-layout="minimal"] .section > .wrap > .projects,
[data-layout="minimal"] .section > .wrap > .map { max-width: none; }

/* Inside the measure there is one column and it is flush left. The grids the
   shared stylesheet builds at 860 and 1080 have no room here and would halve
   the measure if they fired. */
[data-layout="minimal"] .faq-grid,
[data-layout="minimal"] .booking,
[data-layout="minimal"] .contact,
[data-layout="minimal"] .menu-groups,
[data-layout="minimal"] .features,
[data-layout="minimal"] .steps,
[data-layout="minimal"] .svc-list { grid-template-columns: minmax(0, 1fr); }

/* ---------------------------------------- minimal: how a section opens --- */

/*
   THE EYEBROW GOES, AND THE HEADING COMES DOWN TO READING SIZE.

   Every section template prints a tracked caps label above its heading, and
   the label is a constant per section type while the heading comes from the
   document, so when a document names a section the obvious way the two are
   the same word: one of these sites read PRISLISTA over Prislista in 46px
   display type, and its contact page did it again with Vanliga fragor.
   Centring both, which this layout used to do, made the repetition the most
   prominent thing on the page.

   What is left is one label per page: the district over the front page
   headline and the business name over every sub-page title. The heading and
   the white above it carry the section, which is what the layout's own
   comment always claimed it did.
*/
[data-layout="minimal"] .section .eyebrow { display: none; }

[data-layout="minimal"] .section-head {
  max-width: var(--col);
  margin-bottom: var(--beat);
  text-align: left;
}
/* The centring classes the menu and contact templates reach for are the
   stylesheet's own, and this layout has one axis. */
[data-layout="minimal"] .section-head--centre { text-align: left; }

/*
   A HEADING HAS TO BE LEGIBLE AS A STEP.

   It used to be 1.38rem against a 1.06rem body, which is a fifth larger, and
   every reader who looked at the result said the same thing: nothing announces
   a new section. A third larger is a rounding error at reading distance, and
   the white above it cannot carry a section on its own when the page has
   already spent its white on the margins.

   1.95rem against 1.06rem is a real step, and it is still nowhere near the two
   and a half times the base stylesheet takes. Set in the rail, where nothing
   else on the page is set, it is announcing the section twice: once by size
   and once by where it is. That is enough, and it is the last thing on this
   layout that is allowed to get louder.
*/
[data-layout="minimal"] .section-head h2,
[data-layout="minimal"] .about__body h2,
[data-layout="minimal"] .booking__intro h2 {
  font-size: clamp(1.5rem, 2.4vw, 1.95rem);
  line-height: 1.16;
  letter-spacing: var(--heading-track);
}
[data-layout="minimal"] .section-head h2.h2--small { font-size: clamp(1.26rem, 1.8vw, 1.48rem); }
/* The lede is body copy, at body size, in the quiet ink. It used to be a step
   larger than the paragraphs under it, which on a layout with one size of
   type is one size too many. */
[data-layout="minimal"] .section-head p:not(.eyebrow),
[data-layout="minimal"] .booking__lede {
  margin-top: 10px;
  font-size: 1rem;
  max-width: 58ch;
}

/* --------------------------------------------------------- minimal: type --- */

[data-layout="minimal"] h3 { font-size: 1.06rem; letter-spacing: var(--heading-track); }
[data-layout="minimal"] .prose,
[data-layout="minimal"] .about__body { max-width: 62ch; }
[data-layout="minimal"] .prose p,
[data-layout="minimal"] .about__body p { line-height: 1.75; }
/* A 72px bar under a heading is a card's mark. There are no rules on this
   layout outside the price table. */
[data-layout="minimal"] .about__rule { display: none; }

/* ----------------------------------------------------- minimal: controls --- */

/*
   ONE FILLED CONTROL PER PAGE, AND IT IS THE ONE THE PAGE IS FOR.

   The shared stylesheet fills the primary button of the hero, of the closing
   band, of the contact panel and of the booking form, and outlines a second
   one beside each. That is up to eight bordered rectangles on a page whose
   whole argument is that nothing is drawn, and with eight of them none of
   them is primary.

   So the filled control is the hero's action and the form's submit, and every
   other button becomes what it should have been on a page of words: the word,
   underlined. It keeps the button's minimum height, so nothing loses a tap
   target on a phone.
*/
[data-layout="minimal"] .btn { box-shadow: none; }
[data-layout="minimal"] .btn:hover { transform: none; }
[data-layout="minimal"] .btn--outline,
[data-layout="minimal"] .btn--ghost,
[data-layout="minimal"] .header-actions .btn--accent,
[data-layout="minimal"] .contact-actions .btn--accent {
  --btn-bg: transparent;
  --btn-ink: var(--ink);
  border: 0;
  padding: 14px 2px;
  backdrop-filter: none;
  box-shadow: none;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
}
[data-layout="minimal"] .btn--outline:hover,
[data-layout="minimal"] .btn--ghost:hover,
[data-layout="minimal"] .header-actions .btn--accent:hover,
[data-layout="minimal"] .contact-actions .btn--accent:hover {
  background: transparent;
  border-color: transparent;
  color: var(--accent-strong);
}
/* A grid of full width buttons is three bars across the measure. These are
   words on the page, so the track is the width of the word and the words
   start where every other line on the page starts. */
[data-layout="minimal"] .contact-actions {
  justify-items: start;
  gap: 0;
  margin-top: 22px;
  padding-top: 0;
}
[data-layout="minimal"] .contact-actions .btn { justify-content: flex-start; }

/* A vertical tab of the phone number, fixed to the right edge of the window
   on a card ground with a shadow under it, is the shape of a support widget.
   The number is in the masthead, in the imprint and in the closing ask; it
   does not also need to follow the reader down the page. */
[data-layout="minimal"] .phone-rail { display: none; }
/* The two that stay filled. */
[data-layout="minimal"] .hero__actions .btn--accent,
[data-layout="minimal"] .bform button {
  --btn-bg: var(--accent);
  --btn-ink: var(--accent-ink);
  border: 0;
  text-decoration: none;
  padding: 14px 26px;
}
/* The submit is a button and not a bar. Full width it was the single largest
   block of colour on the site, sitting under a form that has no ground of its
   own for it to close. */
[data-layout="minimal"] .bform button {
  width: auto;
  justify-self: start;
  min-width: 0;
}

/* A form field is a user interface component and its edge owes the reader 3:1
   against the paper behind it. --line is about 1.2:1, which the shared rules
   get away with because a fill sits behind the field; there is no fill here. */
[data-layout="minimal"] .bfield input,
[data-layout="minimal"] .bfield select,
[data-layout="minimal"] .bfield textarea {
  background: var(--page);
  border-color: var(--ink-3);
}
[data-layout="minimal"] .bfield input:focus,
[data-layout="minimal"] .bfield select:focus,
[data-layout="minimal"] .bfield textarea:focus {
  border-color: var(--ink);
  box-shadow: none;
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* --------------------------------------------------------- minimal: hero --- */

/*
   THE ONE LARGE THING ON THE SITE.

   The comment over the old rule said the headline "has to be the largest thing
   on the site rather than the smallest of the six" and then set it to
   clamp(2.4rem, 6.6vw, 4.6rem), whose ceiling is BELOW the base hero's 4.7rem.
   Measured on a laptop the layout's one typographic commitment came out four
   per cent smaller than every other layout's. It is its own range now, and the
   measure comes down to thirteen characters so it breaks into two or three
   short lines instead of running out as one long one.

   The clearance is read from the tokens rather than from a literal. The shared
   rule that consumes --hero-clear is keyed on the two tall header variants,
   which this layout can no longer be dealt, so the 56px it declared was never
   applied and the hero sat 21px under the bar on a phone.
*/
.hero--minimal {
  align-items: flex-start;
  padding-top: calc(var(--header-top) + var(--header-h) + var(--hero-clear));
  padding-bottom: clamp(28px, 4vw, 56px);
  min-height: 0;
  max-height: none;
}
.hero--minimal .hero__inner--measure {
  max-width: 720px;
  margin-inline: 0;
  text-align: left;
}
.hero--minimal h1 {
  font-size: clamp(2.55rem, 7.4vw, 5.4rem);
  line-height: 1;
  max-width: 13ch;
}
.hero--minimal .hero__sub {
  margin-top: clamp(18px, 2.4vw, 26px);
  font-size: 1.06rem;
  line-height: 1.7;
  max-width: 46ch;
}
.hero--minimal .hero__actions { margin-top: clamp(24px, 3.4vw, 34px); align-items: center; }
/* One button and one word. Two equal rectangles side by side is the shape of
   a form, and on this layout the second action is already a link everywhere
   else. */
@media (min-width: 560px) {
  .hero--minimal .hero__actions .btn { flex: 0 0 auto; }
}
/* No rule over the meta row: it is the last line of the column, not a band. */
.hero--minimal .trust { border-top: 0; padding-top: 0; margin-top: clamp(24px, 3.2vw, 34px); }
.hero--minimal .eyebrow { justify-content: flex-start; }
.hero--minimal .eyebrow::before { display: none; }

/*
   THE PHOTOGRAPH IS THE WIDE OBJECT.

   The column above it is 760px and the plate below it is the full 1180px
   wrap, and that step is the only composition this layout has. A ratio is not
   a size: 16/6 is a band at 1140px across and a 120px letterbox strip at 320,
   so the band starts where the column is wide enough to carry it.
*/
.hero--minimal .hero__figure { margin-top: clamp(34px, 4.5vw, 58px); }
.hero--minimal .hero__figure img {
  aspect-ratio: 3 / 2;
  max-height: 52svh;
  border-radius: var(--radius);
}
@media (min-width: 560px) {
  .hero--minimal .hero__figure img { aspect-ratio: 16 / 6.6; }
}

/* ------------------------------------------- minimal: how a page opens --- */

/*
   FIVE PAGES THAT DO NOT OPEN THE SAME WAY.

   Variants are dealt per site, so every sub-page of one site gets the same
   head: breadcrumb, title, one line of lede, on a two column masthead grid at
   1080 and above. The front page below it was one centred measure, so the
   layout's one structural idea stopped at the home page and every sub-page
   opened on a different axis from it.

   The head takes the measure, the grid goes, and the title becomes the page's
   single large object the way the headline is the front page's. On the two
   pages whose lede is filler, a wall of photographs and a room full of people,
   the lede is dropped and the title goes up again: the picture is what the
   page is, so the page says its name and gets out of the way. It needs
   data-page on the body element, which show.blade.php prints for every layout.
*/
[data-layout="minimal"] .pagehead {
  border-bottom: 0;
  padding-bottom: 0;
}
[data-layout="minimal"] .pagehead > .wrap { display: block; }
[data-layout="minimal"] .pagehead > .wrap > * {
  max-width: var(--col);
  margin-inline: 0;
}
[data-layout="minimal"] .pagehead h1 {
  font-size: clamp(2.2rem, 5.4vw, 3.6rem);
  line-height: 1.04;
  max-width: 15ch;
}
[data-layout="minimal"] .pagehead__eyebrow { margin-bottom: 14px; }
[data-layout="minimal"] .pagehead__lede {
  margin-top: 16px;
  font-size: 1rem;
  max-width: 52ch;
}
[data-layout="minimal"]:is([data-page="gallery"], [data-page="about"]) .pagehead h1 {
  font-size: clamp(2.6rem, 6.8vw, 4.4rem);
  max-width: 14ch;
}
[data-layout="minimal"]:is([data-page="gallery"], [data-page="about"]) .pagehead__lede { display: none; }

/* ---------------------------------------------------- minimal: the lists --- */

/*
   THE SERVICES BLOCK IS THE LARGEST THING ON SIX OF THE SEVEN SITES AND IT
   HAD NO DESIGN AT ALL.

   Nine rules in the old block styled .service, .services and .svc-row, which
   are emitted only by the cards and rows branches of the template. This
   layout's pool is list and index, so not one of the nine could ever match:
   the price list rendered byte-identical to classic, bold, split and dark.
   They are deleted, and what is below is written against the two shapes this
   layout can actually be dealt.
*/

/* The schedule. A rule under each entry and nothing else: this and the price
   table are the only ruled objects on the site, because a column of figures is
   the one thing a space cannot separate as well as a line can. */
[data-layout="minimal"] .svc-list__item {
  padding: 18px 0 20px;
  border-bottom: 1px solid var(--line);
}
[data-layout="minimal"] .svc-list__item:first-child { border-top: 0; }
[data-layout="minimal"] .svc-list__name { font-size: 1.06rem; }
/* Figures in the text colour and in tabular widths, so hundreds line up under
   hundreds. Set in the accent they read as a column of links and get scanned
   before any of the names. */
[data-layout="minimal"] .svc-list__price,
[data-layout="minimal"] .svc-index__price {
  font-family: var(--font);
  font-size: 1.06rem;
  color: var(--ink);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="minimal"] .svc-list__desc,
[data-layout="minimal"] .svc-index__desc { max-width: 54ch; }

/* The index numeral is a folio: small, quiet, hanging in a fixed column so
   every name starts on the same vertical. At the shared size and in the accent
   it was the loudest thing in a section whose subject is the names. */
[data-layout="minimal"] .svc-index__item {
  padding-block: 20px;
  border-top: 0;
  border-bottom: 1px solid var(--line);
  column-gap: 26px;
}
[data-layout="minimal"] .svc-index__item:first-child { border-top: 1px solid var(--line); }
[data-layout="minimal"] .svc-index__num {
  font-family: var(--font);
  font-weight: 500;
  font-size: 0.82rem;
  line-height: 2.1;
  letter-spacing: .08em;
  color: var(--ink-3);
}
[data-layout="minimal"] .svc-index__name { font-size: 1.06rem; }

/* -------------------------------------------- minimal: the fee schedule --- */

/*
   A TABLE, NOT A MENU CARD.

   The price section ships as a restaurant menu: the item on the left, a row of
   dotted leaders crossing the gap, the figure on the right and the description
   in italic underneath. That is the correct design for a wine list and the
   wrong one for what an electrician or an accountant charges, which a reader
   compares by running down a column of figures. Four of these seven sites were
   being dealt it and two more were being dealt three boxes side by side, so
   the price list, the page most of them exist for, was a different object on
   every site.

   'columns' is now the only value this layout can be dealt, and here it is a
   table: the group named above it on a rule, the entries in rows, the price a
   right hand column of its own in tabular figures, the leaders gone. With the
   figures in a real column there is nothing left for the eye to be led across.
*/
[data-layout="minimal"] .menu-groups { gap: clamp(34px, 4.5vw, 54px); }
[data-layout="minimal"] .menu-group__name {
  display: block;
  font-size: 1.06rem;
  padding: 0 0 10px;
  margin: 0;
  border-bottom: 1px solid var(--ink);
}
[data-layout="minimal"] .menu-group__name::after { display: none; }
[data-layout="minimal"] .menu-group__desc { font-style: normal; margin: 12px 0 0; max-width: 52ch; }
[data-layout="minimal"] .menu-list { margin-top: 4px; }
[data-layout="minimal"] .menu-item {
  padding: 13px 0;
  border-bottom: 1px solid var(--line);
}
[data-layout="minimal"] .menu-item:last-child { border-bottom: 1px solid var(--line); }
[data-layout="minimal"] .menu-item__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: clamp(20px, 3vw, 40px);
  align-items: baseline;
}
[data-layout="minimal"] .menu-item__lead { display: none; }
[data-layout="minimal"] .menu-item__name { font-weight: 500; font-size: 1rem; }
[data-layout="minimal"] .menu-item__price {
  font-weight: 500;
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="minimal"] .menu-item__desc {
  font-style: normal;
  margin-top: 5px;
  max-width: 52ch;
}
[data-layout="minimal"] .menu-note { border-top: 0; margin-top: 18px; padding-top: 0; }

/* ------------------------------------------ minimal: facts and stages --- */

/* Four facts, one per line, with nothing round them. The card, the tinted icon
   chip and the hairline all go: what is left is a name at heading size and a
   sentence under it, which is what the four facts are. */
[data-layout="minimal"] .features { gap: var(--beat); }
[data-layout="minimal"] .feature {
  display: block;
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
}
[data-layout="minimal"] .feature__icon { display: none; }
[data-layout="minimal"] .feature p,
[data-layout="minimal"] .step p { font-size: 1rem; line-height: 1.65; max-width: 54ch; }

/*
   PROCESS AS INFORMATION, NOT AS A DIAGRAM.

   The timeline variant, numbered discs threaded on a vertical line, is out of
   this layout's pool because it is a drawing of a process rather than the
   process. The two that remain are drawn here as a schedule: the stage number
   as a folio in the quiet ink, the stage, and what happens in it.
*/
[data-layout="minimal"] .steps { gap: var(--beat); }
[data-layout="minimal"] .steps .step {
  display: block;
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
  box-shadow: none;
}
[data-layout="minimal"] .steps .step::before,
[data-layout="minimal"] .steps .step::after { display: none; }
[data-layout="minimal"] .steps .step__num {
  width: auto; height: auto;
  display: block;
  background: transparent;
  border: 0;
  border-radius: 0;
  color: var(--ink-3);
  font-family: var(--font);
  font-weight: 500;
  font-size: 0.82rem;
  letter-spacing: .08em;
  line-height: 1.6;
  margin: 0 0 4px;
}
/* .feat-num is not styled here. The numbered features variant is out of this
   layout's pool, so a rule for it would be a rule that can never match, which
   is exactly what the nine services rules above it were. */
[data-layout="minimal"] .feat-strip { border: 0; }
[data-layout="minimal"] .feat-strip__item { border: 0; padding-inline: 0; }

/* ----------------------------------------- minimal: what people wrote --- */

/*
   The rating is a sentence, so it is set as one, and it sits with the section
   head rather than floating between the head and the first quote, where it was
   colliding with the pull quote's oversized quotation mark.
*/
[data-layout="minimal"] .rating-line {
  font-size: 0.95rem;
  color: var(--ink-2);
  margin: calc(var(--beat) * -1 + 10px) 0 var(--beat);
}
/* And when the document's own subtitle already says it, it does not say it
   again. Measured on one of these sites: "Omdomen fran Google. 4,7 av 5 fran
   103 recensioner." followed immediately by "4,7 av 5 i snitt, av 103
   omdomen pa Google." Two sentences, same three facts, one under the other. */
[data-layout="minimal"] .section-head:has(> p:not(.eyebrow)) + .rating-line { display: none; }
/* An outsized ornament deliberately set below the contrast floor is a
   decoration on a layout that has no decorations. */
[data-layout="minimal"] .review-quote__mark { display: none; }
[data-layout="minimal"] .review-quote { padding-top: 0; border-top: 0; }
/* A pull quote, but not a headline. On a layout whose section headings are a
   third larger than body copy, a review at 1.7rem would be the largest object
   on the page and the section would be shouting a stranger's sentence at the
   reader. The measure and the leading make it a quotation instead. */
[data-layout="minimal"] .review-quote__text {
  margin-top: 0;
  font-size: clamp(1.18rem, 1.9vw, 1.42rem);
  line-height: 1.45;
  max-width: 42ch;
}
[data-layout="minimal"] .review-lines { border-top: 0; }
[data-layout="minimal"] .review-line { border-bottom-color: var(--line); }

/* The column variant falls through to the shared card markup, and the old
   block centred the text inside a column the variant had already pinned to the
   left of the wrap. One alignment. */
[data-layout="minimal"] .reviews { gap: var(--beat); border-top: 0; }
[data-layout="minimal"] .reviews .review {
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
  text-align: left;
  align-items: flex-start;
  box-shadow: none;
}
[data-layout="minimal"] .reviews .review__text {
  font-size: 1rem;
  line-height: 1.72;
  color: var(--ink);
  max-width: 54ch;
}
[data-layout="minimal"] .reviews .review__author {
  border-top: 0;
  justify-content: flex-start;
  padding-top: 8px;
}

/* ------------------------------------------------- minimal: questions --- */

/* Both shapes this layout can be dealt are plain rows, so there is no
   <details> marker to restyle. The question takes reading size and the answer
   the prose measure, and the space between them does the separating. */
[data-layout="minimal"] .faq--plain { border-bottom: 0; }
[data-layout="minimal"] .faq__row {
  border-top: 0;
  padding: 0 0 var(--beat);
}
[data-layout="minimal"] .faq__row:last-child { padding-bottom: 0; }
[data-layout="minimal"] .faq__q { font-size: 1.06rem; }
[data-layout="minimal"] .faq__a { max-width: 56ch; }
[data-layout="minimal"] .faq-grid .section-head { margin-bottom: var(--beat); }

/* ----------------------------------------------- minimal: the panels --- */

/*
   A PANEL IS A CARD WITH THE WORD CARD TAKEN OUT OF ITS NAME.

   Flattening the dark band left the hours block and the find-us block as white
   rectangles on a white section behind a border measuring about 1.25:1. The
   two things a reader came to the contact page for had no container they could
   see. They become what everything else on this layout is: a block of words
   with space around it and a label over it.
*/
[data-layout="minimal"] .panel,
[data-layout="minimal"] .booking__card {
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
  box-shadow: none;
}
[data-layout="minimal"] .contact { gap: clamp(38px, 5vw, 56px); }
[data-layout="minimal"] .panel h3 {
  font-family: var(--font);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
  margin-bottom: 16px;
}
/* Today's row was a filled bar with a pill on it, which on a page with no
   other fill and no other pill was two pieces of furniture marking one line.
   Weight and full ink mark it instead. */
[data-layout="minimal"] .hours__row { padding-inline: 0; }
[data-layout="minimal"] .hours__row.is-today { background: transparent; }
[data-layout="minimal"] .hours__today {
  padding: 0;
  border-radius: 0;
  background: transparent;
  color: var(--ink-2);
  font-weight: 600;
  letter-spacing: .1em;
}
/* The status is a fact, not a badge. */
[data-layout="minimal"] .contact-status {
  padding: 0;
  border-radius: 0;
  background: transparent;
  margin-bottom: 18px;
}
[data-layout="minimal"] .contact-line svg { display: none; }
[data-layout="minimal"] .contact-line dt {
  font-size: 0.88rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
}
[data-layout="minimal"] .contact-line dd { font-size: 1rem; }
[data-layout="minimal"] .map { border: 0; }

/* ---------------------------------------------- minimal: photographs --- */

/* Square pictures, a hair of a gap between them, and nothing drawn around
   them. The pictures are the only wide objects on the page, so they are also
   the only place a reader's eye is meant to stop. */
[data-layout="minimal"] .gallery { gap: 8px; }
[data-layout="minimal"] .gallery figure:hover img { transform: none; }

/*
   THE SHOP IS A PAGE OF PHOTOGRAPHS, NOT A ROW OF CARDS.

   Two of these sites sell something, and the shop arrives as bordered cards on
   a card ground with a filled button inside each: four blocks of solid colour
   in one row, on a site whose only other filled control is the hero's. The
   card comes off, the picture is the object, the name and the price are set
   under it as a caption and the basket link is the underlined word the rest of
   the site uses. The button is still a button and still 44px high; it is not
   also a rectangle of paint.
*/
[data-layout="minimal"] .shop { gap: clamp(20px, 2.6vw, 34px) clamp(16px, 2vw, 26px); }
[data-layout="minimal"] .product {
  background: transparent;
  border: 0;
  border-radius: 0;
  overflow: visible;
}
[data-layout="minimal"] .product__media { border-radius: var(--radius); overflow: hidden; }
[data-layout="minimal"] .product__body { padding: 14px 0 0; gap: 4px; }
[data-layout="minimal"] .product__price { font-weight: 500; margin-bottom: 6px; }
[data-layout="minimal"] .product__body .btn {
  --btn-bg: transparent;
  --btn-ink: var(--ink);
  border: 0;
  box-shadow: none;
  width: auto;
  min-height: 44px;
  padding: 8px 2px;
  justify-content: flex-start;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
}
[data-layout="minimal"] .product__body .btn:hover {
  background: transparent;
  color: var(--accent-strong);
}

/*
   THE ABOUT BLOCK IS THE HERO AGAIN, NOT A THIRD VERTICAL.

   The split variant puts the photograph in one half of the page and the prose
   in the other, which on this layout means the words start at 710px and every
   other line on the page starts at 230. So the block takes the composition the
   front page already uses and the sub-page heads already use: the picture runs
   the full frame, the words are the measure underneath it, and the page has
   one left edge from the masthead to the imprint.
*/
[data-layout="minimal"] .about { display: block; }
[data-layout="minimal"] .about__media { margin-bottom: clamp(28px, 3.6vw, 44px); }
[data-layout="minimal"] .about__media img { aspect-ratio: 16 / 8; }
[data-layout="minimal"] .about--stat { max-width: none; }
[data-layout="minimal"] .about__body,
[data-layout="minimal"] .about-stats { max-width: var(--col); }
[data-layout="minimal"] .about__body p { font-size: 1rem; }

/* ------------------------------------------ minimal: how a page closes --- */

/*
   THE CLOSING BAND IS NOT A SLAB.

   Every page of every site ended with the same grey rectangle, the same seven
   words and the same two buttons: thirty-four of them across these seven
   demos. It was also the ONLY ground change on the whole layout, so the one
   moment of visual emphasis in an entire site was being spent on boilerplate,
   five times per site.

   It is the page's own paper now, it keeps the section rhythm above it, and
   the ask is a line of type with the two actions spelled out under it as
   words. Nothing about it is a band.
*/
[data-layout="minimal"] .closer,
[data-layout="minimal"] .section--alt + .closer {
  background: var(--page);
  border-top: 0;
}
/* No top padding: the last section above it already carries the interval, and
   two of them stacked put a quarter of a screen of nothing before the ask. */
[data-layout="minimal"] .closer__inner {
  display: block;
  padding-block: clamp(18px, 2.4vw, 36px) clamp(64px, 8vw, 112px);
}
[data-layout="minimal"] .closer h2 {
  font-size: clamp(1.5rem, 2.4vw, 1.95rem);
  line-height: 1.16;
  max-width: 22ch;
}
[data-layout="minimal"] .closer p { margin-top: 10px; max-width: 52ch; font-size: 1rem; }
[data-layout="minimal"] .closer .status-pill { display: none; }
[data-layout="minimal"] .closer__actions {
  margin-top: 20px;
  gap: 4px 28px;
}
[data-layout="minimal"] .closer__actions .btn--accent,
[data-layout="minimal"] .closer__actions .btn--outline {
  --btn-bg: transparent;
  --btn-ink: var(--ink);
  border: 0;
  box-shadow: none;
  min-height: 44px;
  padding: 10px 2px;
  font-size: 1rem;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
}

/* The document's own cta section is the one place the business wrote the ask
   itself, so it keeps a filled button. It does not keep a ground: there are no
   grounds. */
[data-layout="minimal"] .cta-band {
  background: var(--page);
  color: var(--ink);
  border-block: 0;
  text-align: left;
}
[data-layout="minimal"] .cta-band__inner {
  display: block;
  padding-block: clamp(18px, 2.4vw, 36px) clamp(64px, 8vw, 112px);
}
[data-layout="minimal"] .cta-band h2 { font-size: clamp(1.5rem, 2.6vw, 2rem); max-width: 20ch; }
[data-layout="minimal"] .cta-band p { margin-top: 10px; max-width: 52ch; }
[data-layout="minimal"] .cta-band .btn--accent {
  --btn-bg: var(--accent);
  --btn-ink: var(--accent-ink);
  margin-top: 26px;
  justify-self: start;
  text-decoration: none;
}

/* ---------------------------------------------- minimal: the masthead --- */

/*
   THE NAME, SET AS TYPE, AND NOTHING ELSE.

   The bar arrives with a filled accent pill holding the phone number, pill
   shaped navigation links, a blurred translucent ground once it sticks and a
   shadow under it. On the trades that get the phone pill the first thing on
   the page was therefore a block of solid colour, on a layout whose argument
   is that nothing is a block of solid colour.

   The number stays, because on a phone it is the point of the header. It is a
   word now.
*/
[data-layout="minimal"] .header-inner { min-height: 76px; }
[data-layout="minimal"] .brand__name { font-size: 17px; letter-spacing: var(--heading-track); }
[data-layout="minimal"] .brand__meta { font-size: 12px; letter-spacing: 0; text-transform: none; }
[data-layout="minimal"] .nav a {
  border-radius: 0;
  padding: 8px 0;
  font-size: 14.5px;
}
[data-layout="minimal"] .nav a { color: var(--ink-2); }
[data-layout="minimal"] .nav a:hover { background: none; color: var(--ink); }
/* The current page is marked by the ink, not by the accent. A pale accent word
   among darker ones reads as disabled rather than as current, and on a layout
   with one colour in it the colour is spent on the hero's button. */
/* body-prefixed so it outranks body:not(.has-hero) .nav a[aria-current], which
   turns the current link accent on every page that has no hero. */
body[data-layout="minimal"] .nav a[aria-current="page"] { color: var(--ink); }
[data-layout="minimal"] .header-tel { font-weight: 500; }
[data-layout="minimal"] .site-header.is-stuck {
  background: var(--page);
  backdrop-filter: none;
  box-shadow: none;
  border-bottom-color: var(--line);
}
[data-layout="minimal"] .mobile-nav { background: var(--page); color: var(--ink); }
[data-layout="minimal"] .mobile-nav a { border-bottom-color: var(--line); }
[data-layout="minimal"] .mobile-nav__meta { color: var(--ink-3); }

/* ----------------------------------------------- minimal: the imprint --- */

/* The site ends on the same paper it started on. Four columns of white on a
   black slab is a footer from a different design. */
[data-layout="minimal"] .site-footer {
  background: var(--page);
  color: var(--ink-2);
  border-top: 1px solid var(--line);
}
[data-layout="minimal"] .site-footer__name { color: var(--ink); }
[data-layout="minimal"] .site-footer__heading {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
}
[data-layout="minimal"] .site-footer__top,
[data-layout="minimal"] .site-footer__legal { border-color: var(--line); }
/* The shared imprint declares four tracks whatever it has to put in them, so a
   site with three columns of it left the last quarter of the frame empty under
   a page that has just spent five sections filling the frame. As many equal
   columns as there is content, and they reach the right edge. */
[data-layout="minimal"] .site-footer__top { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
[data-layout="minimal"] .site-footer__links a:hover,
[data-layout="minimal"] .site-footer__contact a:hover,
[data-layout="minimal"] .site-footer__by a:hover { color: var(--ink); }
[data-layout="minimal"] .site-footer__social a { color: var(--ink-2); }
[data-layout="minimal"] .site-footer__social a:hover { color: var(--ink); background: transparent; }
[data-layout="minimal"] .site-footer__legal { color: var(--ink-2); }

/* The two controls that float over the page rather than sitting in it. Filled
   with the accent they were a button with no edge on a pale palette; they take
   the same ink the page is set in. */
[data-layout="minimal"] .chat__fab,
[data-layout="minimal"] .chat__send { background: var(--ink); color: var(--page); }
[data-layout="minimal"] .chat__fab { box-shadow: 0 2px 14px rgb(0 0 0 / .18); }

/* ========================================= minimal: with the viewport ==== */

/*
   A MOBILE DESIGN RATHER THAN A MOBILE FALLBACK.

   At 375 the desktop idea has nothing left: the 640px measure, the 760px hero
   column and the 1180px wrap are all inert, and what remains is a single
   column of text with a photograph in it. So the phone gets the one thing it
   can have that the desktop cannot, which is the picture running edge to edge
   of the screen instead of sitting inside a 20px gutter, and it keeps the
   interval, which is the design.
*/
@media (max-width: 559px) {
  .hero--minimal .hero__figure {
    margin-inline: -20px;
    width: calc(100% + 40px);
  }
  .hero--minimal .hero__figure img { border-radius: 0; }
  [data-layout="minimal"] .section > .wrap > .gallery {
    margin-inline: -20px;
    width: calc(100% + 40px);
  }
  [data-layout="minimal"] .gallery { gap: 4px; }
  [data-layout="minimal"] .gallery figure { border-radius: 0; }
  /* Stacked, the two closing links were two different widths of full width
     button. They are words on two lines now, each one as wide as the word: a
     block level flex box rather than a block, or the phone icon takes a line
     of its own above the number. */
  [data-layout="minimal"] .closer__actions { display: block; }
  [data-layout="minimal"] .closer__actions .btn {
    display: flex;
    justify-content: flex-start;
    width: fit-content;
    flex: 0 0 auto;
  }
}

@media (min-width: 860px) {
  /* The measure is the measure. Every grid the shared stylesheet opens out at
     this width would put two columns inside it. */
  [data-layout="minimal"] .features { grid-template-columns: minmax(0, 1fr); }
  [data-layout="minimal"] .steps { grid-template-columns: minmax(0, 1fr); }
  [data-layout="minimal"] .feature,
  [data-layout="minimal"] .steps .step { flex-direction: column; }

  /* The shared rule splits the price list into two columns from four entries
     and draws a rule over the second one to line the two up. One column here,
     so that rule puts a second hairline on top of the first entry's. */
  [data-layout="minimal"] .svc-list:has(> :nth-child(4)) > .svc-list__item:nth-child(2) { border-top: 0; }

  /* And the index keeps two columns rather than opening into three. The third
     column is a 25rem measure for the description, which inside a 640px page
     column leaves the name eleven characters wide and breaking over two
     lines. The description goes back under the name where it belongs. */
  [data-layout="minimal"] .svc-index { max-width: none; }
  [data-layout="minimal"] .svc-index__item { grid-template-columns: 44px minmax(0, 1fr); }
  [data-layout="minimal"] .svc-index__num { grid-row: 1 / span 2; }
  [data-layout="minimal"] .svc-index__desc {
    grid-column: 2;
    grid-row: 2;
    margin-top: 8px;
    max-width: 54ch;
  }
}

/* ====================================== minimal: the two column page ==== */

/*
   1040 IS WHERE THE RAIL FITS AND NOT A PIXEL SOONER.

   Rail plus gutter plus measure plus the wrap's own 20px gutters is 1052 at
   the gutter's ceiling, and at 1040 the gutter is 48px, so the two columns
   want 1028 of the 1025 a window with a scrollbar has. Every track is a
   minmax(0, x) for exactly that: the measure gives up three pixels rather
   than pushing the page sideways.

   Below this width the wrap is narrower than the two columns need and the head
   goes back on top of the measure, which is the same page a phone gets. There
   is no third arrangement between them.
*/
@media (min-width: 1040px) {
  [data-layout="minimal"] .section > .wrap,
  [data-layout="minimal"] .pagehead > .wrap,
  [data-layout="minimal"] .faq-grid,
  [data-layout="minimal"] .booking,
  [data-layout="minimal"] .about,
  [data-layout="minimal"] .about__body,
  [data-layout="minimal"] .prose,
  [data-layout="minimal"] .closer__inner,
  [data-layout="minimal"] .cta-band__inner {
    display: grid;
    grid-template-columns: minmax(0, var(--rail)) minmax(0, var(--col));
    column-gap: var(--gutter);
    align-items: start;
  }

  [data-layout="minimal"] .section > .wrap > * { grid-column: 2; }

  /* What hangs in the rail: the name of the section, and the one line under it
     that says what the section is. Nothing else on the page is set here, so
     the position alone says a section has started. */
  [data-layout="minimal"] .section > .wrap > .section-head,
  [data-layout="minimal"] .section > .wrap > .rating-line { grid-column: 1; }
  [data-layout="minimal"] .section-head { margin-bottom: 0; }
  [data-layout="minimal"] .section-head p:not(.eyebrow) { max-width: none; }
  /* The rating sentence sits under the head in the rail rather than being
     pulled up over it, which is what the negative margin was for when the two
     were stacked in one column. */
  [data-layout="minimal"] .rating-line { margin: 12px 0 0; }

  /* The wide objects, which were the only things running the full frame
     before and still are. What changed is that there is now page on both
     sides of them instead of page on one side. */
  [data-layout="minimal"] .section > .wrap > .gallery,
  [data-layout="minimal"] .section > .wrap > .about,
  [data-layout="minimal"] .section > .wrap > .shop,
  [data-layout="minimal"] .section > .wrap > .projects,
  [data-layout="minimal"] .section > .wrap > .faq-grid,
  [data-layout="minimal"] .section > .wrap > .booking,
  [data-layout="minimal"] .section > .wrap > .prose,
  [data-layout="minimal"] .section > .wrap > .map {
    grid-column: 1 / -1;
    max-width: none;
  }
  /* A wide object has a row of its own under the head, and nothing beside the
     head to hold the two apart, so the interval is stated. */
  [data-layout="minimal"] .section > .wrap > .section-head ~ :is(.gallery, .shop, .projects, .map) {
    margin-top: var(--beat);
  }
  /* When the rating sentence is printed it takes a second row in the rail, and
     the first thing in the measure starts level with the heading, not with it. */
  [data-layout="minimal"] .section > .wrap > .section-head:not(:has(> h2:empty)) + .rating-line + * { grid-row: 1 / span 2; }

  /* The four blocks that carry their own heading instead of a section head
     restate the same two tracks at the same widths, so a heading inside one of
     them lands on the same vertical as every heading outside it. */
  [data-layout="minimal"] .faq-grid > .section-head,
  [data-layout="minimal"] .booking__intro,
  [data-layout="minimal"] .prose > h2,
  [data-layout="minimal"] .about__body > h2 { grid-column: 1; }
  [data-layout="minimal"] .faq-grid > .faq,
  [data-layout="minimal"] .booking__card,
  [data-layout="minimal"] .prose > p,
  [data-layout="minimal"] .about__body > p,
  [data-layout="minimal"] .about__body > .about__lead { grid-column: 2; }
  [data-layout="minimal"] .faq-grid .section-head { margin-bottom: 0; }
  /* A paragraph is still a paragraph when its column is wider than a measure. */
  [data-layout="minimal"] .prose > p,
  [data-layout="minimal"] .about__body > p { max-width: 62ch; }
  [data-layout="minimal"] .about__media { grid-column: 1 / -1; }
  /* align-self because the shared split variant centres its body against its
     photograph, and here the photograph is on a row of its own. */
  [data-layout="minimal"] .about__body {
    grid-column: 1 / -1;
    align-self: start;
    max-width: none;
  }
  /*
     The stat variant keeps its heading in the rail and puts both of the things
     it is a heading for, the figures and the prose, in the measure beside it.
     Its heading lives in a wrapper of its own rather than with the prose, so
     that wrapper takes the rail as one block: spanning both tracks, as the
     split variant's body does, it would have pushed the figures onto a row of
     their own and left a screen of nothing under the heading.
  */
  [data-layout="minimal"] .about--stat > .about__body:not(.about__body--prose) {
    display: block;
    grid-column: 1;
  }
  [data-layout="minimal"] .about--stat > .about-stats {
    grid-column: 2;
    max-width: none;
    margin-top: 0;
  }
  /* A heading whose wrapper has nothing else left in it is not a box. Kept, it
     takes the rail's first row and pushes the figures down a row beside it. */
  [data-layout="minimal"] .about--stat > .about__body:not(.about__body--prose):has(> h2:empty) { display: none; }
  [data-layout="minimal"] .about__body--prose {
    display: block;
    grid-column: 2;
    max-width: none;
  }

  /*
     THE PAGE HEAD STATES THE GRID BEFORE THE FIRST SECTION DOES.

     The business name hangs in the rail, the page's own name runs the frame
     because it is the one large thing on a sub-page, and the line saying what
     is on the page is indented to the measure. A reader has seen both verticals
     before they have scrolled.
  */
  [data-layout="minimal"] .pagehead__eyebrow { grid-column: 1; }
  [data-layout="minimal"] .pagehead h1 { grid-column: 1 / -1; max-width: 18ch; }
  [data-layout="minimal"] .pagehead__lede { grid-column: 2; max-width: none; }

  /*
     THE CLOSING ASK TAKES THE SAME TWO COLUMNS.

     display:contents on the wrapper the template prints, so the ask's heading
     hangs in the rail with every other heading on the site and the sentence and
     the two actions sit in the measure. Without it the whole ask is one grid
     item and the page ends on the shape it just spent five sections not being.
  */
  [data-layout="minimal"] .closer__say,
  [data-layout="minimal"] .cta-band__inner > div { display: contents; }
  /* Spanning both rows, so a heading that breaks onto two lines makes its own
     room instead of pushing the actions a line below a one line sentence. */
  [data-layout="minimal"] .closer__say > h2,
  [data-layout="minimal"] .cta-band__inner > div > h2 {
    grid-column: 1;
    grid-row: 1 / span 2;
  }
  [data-layout="minimal"] .closer__say > p,
  [data-layout="minimal"] .closer__actions,
  [data-layout="minimal"] .cta-band__inner > div > p,
  [data-layout="minimal"] .cta-band__inner > .btn { grid-column: 2; }
  [data-layout="minimal"] .closer__say > p,
  [data-layout="minimal"] .cta-band__inner > div > p { max-width: none; }
  [data-layout="minimal"] .cta-band__inner > .btn { justify-self: start; }
  /* The shared band sets a 44px gap for its own two column arrangement, which
     here lands between a sentence and the two actions that answer it. */
  [data-layout="minimal"] .closer__inner,
  [data-layout="minimal"] .cta-band__inner { row-gap: 0; }
  /* The document's own band nests its grid one level inside the wrap, where
     the measure cap from the single column page would squeeze both tracks
     into 640px. */
  [data-layout="minimal"] .cta-band > .wrap > .cta-band__inner { max-width: none; }
  [data-layout="minimal"] .closer__actions { margin-top: 14px; }

  /*
     A SECTION WHOSE HEADING WAS TAKEN AWAY DOES NOT GET A RAIL.

     show.blade.php drops the first section's heading on a sub-page when it
     repeats the page's own name, and every template still prints the empty
     element around it. Left in the grid that is a 300px column of nothing
     running the height of a whole section, which is the exact fault this
     rework exists to remove, arriving from the other side of the page. Two of
     the seven sites have a sub-page where it happens twice.

     So the empty head comes out and the work takes the frame. The page head
     above it is the heading, which is why the heading below it was dropped.
  */
  [data-layout="minimal"] .section > .wrap:has(> .section-head > h2:empty) > .section-head,
  [data-layout="minimal"] .faq-grid:has(> .section-head > h2:empty) > .section-head,
  [data-layout="minimal"] .about__body > h2:empty,
  [data-layout="minimal"] .booking__intro > h2:empty { display: none; }

  /* Two shapes of the same thing: the head printed empty, and the head not
     printed at all, which is what features and gallery do with no title. */
  [data-layout="minimal"] .section > .wrap:has(> .section-head > h2:empty) > *,
  [data-layout="minimal"] .section > .wrap:not(:has(> .section-head)) > *,
  [data-layout="minimal"] .faq-grid:has(> .section-head > h2:empty) > * {
    grid-column: 1 / -1;
    max-width: none;
  }
  /* Except a paragraph, which owes the reader a measure whatever column it is
     standing in. */
  [data-layout="minimal"] .section > .wrap:has(> .section-head > h2:empty) > .prose > p,
  [data-layout="minimal"] .section > .wrap:not(:has(> .section-head)) > .prose > p { max-width: 62ch; }

  /* Four facts one under another down a 1012px frame is a list with a lot of
     air in the middle of it. Across the frame they pair off. */
  [data-layout="minimal"] .section > .wrap:has(> .section-head > h2:empty) > .features,
  [data-layout="minimal"] .section > .wrap:not(:has(> .section-head)) > .features {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--gutter);
  }

  /*
     AND WHEN IT IS THE ABOUT BLOCK, THE OPENING LINE TAKES THE RAIL.

     This one has prose rather than a list, and prose set to the frame is not a
     measure any more. So the paragraph that would have been under the heading
     becomes the standfirst and hangs where the heading would have hung. The
     rail holds a sentence instead of a label, which is the one place on the
     site where it does, and the page keeps both of its verticals.

     The rule div is the anchor rather than :first-of-type, because the first
     p in this block is the eyebrow the layout has already switched off and a
     hidden element is still of its type.
  */
  [data-layout="minimal"] .about:has(> .about__body > h2:empty) .about__body > .about__rule + p,
  [data-layout="minimal"] .about--stat:has(> .about__body > h2:empty) > .about__body--prose > p:first-child {
    grid-column: 1;
    grid-row: 1;
    margin-top: 0;
    color: var(--ink-2);
  }
  /* The stat variant's prose is a wrapper round the paragraphs rather than the
     paragraphs, so it stops generating a box of its own and hands them to the
     grid, which is the only way one of them can stand in a different column
     from the rest. */
  [data-layout="minimal"] .about--stat:has(> .about__body > h2:empty) > .about__body--prose { display: contents; }
  [data-layout="minimal"] .about--stat:has(> .about__body > h2:empty) > .about__body--prose > p {
    grid-column: 2;
    max-width: 62ch;
  }
}

/* ================================================================= split ====
   A PAGE DIVIDED DOWN ITS LENGTH.

   What this layout was: seven hero rules, four token flips, a drop shadow, a
   filled circular icon and six footer recolours. Nineteen rules, and only the
   hero ones changed a shape. Everything that makes a page look like somebody
   designed it for one business, the measure, the rhythm, where things align,
   what a card is, how a section opens, how the page closes, came from the
   base, so a split page was the classic page with the photograph moved. Below
   860px even the photograph stopped moving: every rule that made a split a
   split lived inside a min-width query, so the phone, which is most of the
   traffic, got the default page with a letterbox sliver on top of it.

   What it is now, in one sentence: the picture is half the page, held to the
   edge of the window, and everything else is quiet enough to let it be.

   The four decisions the rest of this block follows from.

   1. THE SEAM IS THE DESIGN, AND IT SURVIVES THE HERO. On the front page the
      window divides in two: type on the left, one photograph on the right. On
      every other page the same division is a rule down the length of the
      content: the section's name and standfirst hang in a narrow left column,
      the work sits in the wide one, and a hairline runs between them for the
      full height of the section. Five pages of one business are then the same
      page structure at five different weights, rather than five stacks of the
      same head over the same band.

   2. THE HEADLINE IS NOT THE LOUD THING. A section head set at 2.85rem beside
      a photograph that is half the screen is two things competing. In the
      margin column it comes down to 1.95rem and reads as a label on the work,
      which is the job it actually has here. The one thing set large on a
      sub-page is the page's own name.

   3. ONE GROUND CHANGE THAT IS REAL. The old block repainted .section--dark
      as --surface, which put four of the five bands on a page 1.04:1 apart:
      1541px of unbroken near-white on the gallery page with a hairline in the
      middle of it. The dark bands are dark again. A paper page with one ink
      band in it has a beat; a paper page with a tint in it has a smudge. It
      also hands back the contrast the flip had quietly broken: the contact
      panel's labels are drawn in the raw accent, which measured 2.30:1 on the
      recoloured ground on five of the six sites.

   4. THE PHONE STATES THE SAME SPLIT. It cannot do it sideways at 375px, so
      it does it the other way up: the words first on paper under the bar, the
      photograph below them running the full width and a long way down. The
      division is still one straight edge across the whole screen; only its
      axis changed.

   Specificity note, the same one the atelier block makes: nearly every
   selector here is [data-layout="split"] X, which is (0,2,0) and beats the
   plain rules inside the 560, 860 and 1080 media queries earlier in the file
   at every width. Anything that has to change WITH the viewport is written
   into this block's own queries at the end, never up here.
   ========================================================================= */

body[data-layout="split"] {
  /*
     SQUARE. The argument of the layout is a photograph cut off by the edge of
     the window, and a rounded corner somewhere else on the page is the page
     apologising for it. Radius 0 also takes the pill off the status line, the
     hours badge and the area list, which were the last three shapes on the
     page that came from a builder's component kit rather than from this
     design.
  */
  --radius: 0px;

  /* A missing cut must fail rather than be faked. Same reasoning as atelier:
     with synthesis off, a face that ships one weight stays at the weight it
     has instead of being smeared into a bold it has not got. */
  font-synthesis: none;

  /*
     THE RULE THE PAGE IS BUILT OUT OF.

     --line is the hairline the base uses to separate blocks and it measures
     about 1.2:1 against paper. Across a whole section, as the seam that
     carries the layout's one idea, it disappears. --rule is ink at 24 per
     cent, which is 1.9:1 on paper: still a hairline, and still visible at the
     length this file draws it. It is decoration around content that carries
     its own meaning, so the floor that applies is legibility and not the
     4.5:1 a piece of text owes or the 3:1 a control edge owes.
  */
  --rule: color-mix(in srgb, var(--ink) 24%, var(--page));
}

/* The seam, per ground. Stated on the section rather than on the body so the
   dark bands get a rule that can be seen on ink without anything naming a
   colour twice. */
[data-layout="split"] .section { --seam: var(--rule); }
/* --panel-line is 12 per cent white, which is a panel edge and vanishes as a
   rule drawn the height of a band. This is the same hairline weight the paper
   sections get, measured from the other end of the scale. */
[data-layout="split"] .section--dark { --seam: rgb(255 255 255 / .32); }

/* --------------------------------------------------------- split: rhythm --- */

/* Asymmetric, the way a printed page is: more air over a section than under
   it, so the heading is clearly the top of something rather than floating
   between two equal gaps. */
[data-layout="split"] .section { padding: clamp(68px, 9.5vw, 136px) 0 clamp(52px, 7vw, 100px); }
[data-layout="split"] .section--tight { padding: clamp(48px, 6vw, 80px) 0 clamp(40px, 5vw, 66px); }

/* --------------------------------------------- split: how a section opens --- */
/*
   THE THING EVERY LAYOUT IN THIS FILE USED TO DO IDENTICALLY.

   A tracked eyebrow behind a coloured bar, a serif h2 and a grey line of
   lede, stacked in a 640px column with the other half of the page empty
   beside it. Drawn once it is a heading. Drawn up to fifteen times across
   five pages it is the stamp, and on one site it printed the eyebrow and the
   heading with the same four words in them, one directly above the other.

   THE EYEBROW GOES. A page is allowed one. The hero already carries it, and
   on a sub-page the page head's breadcrumb is doing the same job. Everything
   else was the navigation label repeated immediately above a heading that
   said the same thing in larger type.
*/
[data-layout="split"] .section .eyebrow { display: none; }

/* The rule over the name, which is the phone's and the tablet's expression of
   the seam and stays on the two sections at desktop width that hand their
   whole column to photographs. At 1080 and over, everywhere else, it is
   replaced by the vertical one at the end of this block. */
[data-layout="split"] .section > .wrap > .section-head {
  border-top: 1px solid var(--seam);
  padding-top: 14px;
}

[data-layout="split"] .section-head { max-width: none; margin-bottom: clamp(30px, 4vw, 46px); }
[data-layout="split"] .section-head h2 { font-size: clamp(1.45rem, 2.6vw, 1.95rem); line-height: 1.14; }
[data-layout="split"] .section-head h2.h2--small { font-size: clamp(1.3rem, 2.2vw, 1.6rem); }
/* Measure and size only. Restating the colour here would be (0,3,0) and would
   land after .section--dark .section-head p, which is the rule that turns the
   standfirst white on the two ink bands. */
[data-layout="split"] .section-head p:not(.eyebrow) { margin-top: 12px; font-size: .98rem; line-height: 1.6; }

/* ----------------------------------------------------------- split: type --- */

[data-layout="split"] .about__body,
[data-layout="split"] .prose { max-width: 62ch; }
[data-layout="split"] .about__body p,
[data-layout="split"] .prose p { line-height: 1.7; }
/* The about block has no section head, so its heading carries its own rule.
   72 pixels of 3px accent under a heading is an underline; a hairline across
   the measure is the same device every other heading on this layout sits on. */
[data-layout="split"] .about__rule {
  width: 100%;
  height: 1px;
  background: var(--rule);
  margin: 20px 0 26px;
}

/* ------------------------------------------------------- split: controls --- */
/*
   A button on this page is a rectangle with a label in it. The lift on hover
   and the coloured glow under the primary were the two things on the page
   that moved and floated, and a register whose whole claim is stillness
   cannot afford either.
*/
[data-layout="split"] .btn { font-weight: 600; letter-spacing: .01em; }
[data-layout="split"] .btn:hover { transform: none; }
[data-layout="split"] .btn--accent { box-shadow: none; }
[data-layout="split"] .btn--accent:hover { background: var(--accent-deep); }
[data-layout="split"] .btn--outline { border-color: var(--ink-3); }
[data-layout="split"] .btn--outline:hover { background: transparent; border-color: var(--ink); }

/* The three lozenges left in the catalogue. Radius 0 squares them; these take
   the wash off as well, because a filled shape behind two words is the
   component kit and the words are perfectly able to carry themselves. */
[data-layout="split"] .contact-status { background: none; padding: 0; margin-bottom: 20px; }
[data-layout="split"] .hours__today {
  padding: 0;
  margin-left: 10px;
  background: none;
}

/*
   THE ACCENT ON THE INK BAND.

   .panel h3 and the marks beside the contact lines are drawn in the raw
   --accent, which Theme derives to sit on paper. On the two dark bands that
   is the same omission the old block had on its recoloured pale ones, only
   the other way round: measured on the contact page it lands at 3.01:1 on one
   of these palettes and 2.72:1 on the panel inside it, against the 4.5 a
   13px label owes and the 3 a mark owes. --accent-on-dark is the accent
   lifted towards white until it is readable, which is exactly the question
   being asked, and the hero already uses it for the same reason.

   Scoped to this layout rather than fixed in the base, because two of the
   seven repaint .section--dark as a pale band and there the lifted accent
   would be the unreadable one. The base needs the fix stated the other way
   round and that is a change to four layouts at once, not to this one.
*/
[data-layout="split"] .section--dark .panel h3,
[data-layout="split"] .section--dark .hours__today,
[data-layout="split"] .section--dark .contact-line svg { color: var(--accent-on-dark); }
[data-layout="split"] .hours__row { padding-inline: 0; }
[data-layout="split"] .hours__row.is-today { background: none; }

/* ----------------------------------------------------------- split: cards --- */
/*
   The old block's entire statement about a card was a two layer drop shadow
   and a filled circular icon, which is the default recipe in every drag and
   drop builder there is. Both are gone. What separates one thing from the
   next here is a rule and the space over it, which is the same device the
   seam uses, so the page has one idea in it rather than two.
*/
[data-layout="split"] .feature,
[data-layout="split"] .step,
[data-layout="split"] .booking__card,
[data-layout="split"] .service {
  background: none;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
  padding: clamp(16px, 2.2vw, 22px) 0 clamp(10px, 1.6vw, 16px);
}
[data-layout="split"] .service:hover { border-color: var(--ink-3); transform: none; box-shadow: none; }
[data-layout="split"] .service__meta { border-top: 0; padding-top: 8px; }
[data-layout="split"] .service__icon,
[data-layout="split"] .feature__icon {
  width: auto;
  height: auto;
  background: none;
  color: var(--accent-strong);
  padding-top: 3px;
}
[data-layout="split"] .service__icon svg { width: 20px; height: 20px; }

/* The booking card is a form, and a form wants its fields to be the edges on
   it rather than an outline round the lot of them. */
[data-layout="split"] .booking__card { padding-top: clamp(20px, 2.6vw, 28px); }
[data-layout="split"] .bfield input,
[data-layout="split"] .bfield select,
[data-layout="split"] .bfield textarea { background: var(--page); border-color: var(--ink-3); }

/* ------------------------------------------------- split: the price lists --- */
/*
   THE FEE SCHEDULE AS A TABLE, NOT AS A ZEBRA BAND.

   'rows' shipped as alternating tinted bands with a filled accent square at
   the head of each one, which is a data table pretending to be a set of
   cards. What a price list wants is one column of names and one column of
   figures, the figures aligned on their own right edge in tabular numerals so
   a reader can compare them by looking down rather than by reading across.
   The tint goes, the filled square goes, the rule stays.
*/
[data-layout="split"] .svc-row {
  padding-inline: 0;
  margin-inline: 0;
  align-items: baseline;
  gap: 10px 24px;
  border-top-color: var(--line);
}
[data-layout="split"] .svc-row:nth-child(even) { background: none; }
[data-layout="split"] .svc-row__icon { display: none; }
[data-layout="split"] .svc-row__name { font-size: clamp(1.1rem, 2.1vw, 1.3rem); }
[data-layout="split"] .svc-row__desc { margin-top: 6px; font-size: 15px; max-width: 56ch; }
[data-layout="split"] .svc-row__meta { align-items: baseline; flex-direction: row-reverse; gap: 16px; }
[data-layout="split"] .svc-row__price {
  font-size: 1.15rem;
  font-variant-numeric: lining-nums tabular-nums;
  text-align: right;
  min-width: 6ch;
}
[data-layout="split"] .svc-row__time { font-variant-numeric: lining-nums tabular-nums; }

/* The printed index keeps its numerals, which are already small and tracked
   rather than poster sized, and its figures join the same column of ink the
   rows set theirs in, so the two variants read as one house style at two
   weights rather than as two different price lists. */
/* --ink-2, not --ink-3. --ink-3 is mixed far enough towards the page that it
   measures between 3.4 and 4.9 to 1 across these palettes, and a figure a
   reader counts down a list by is not ornament. */
[data-layout="split"] .svc-index__num { color: var(--ink-2); }
[data-layout="split"] .svc-index__name { font-size: clamp(1.15rem, 2.2vw, 1.45rem); }
[data-layout="split"] .svc-index__price {
  color: var(--ink);
  font-variant-numeric: lining-nums tabular-nums;
}

/* The bill of fare. The dotted leader is a restaurant card convention that
   was being reused as a fee schedule on trades that have never printed one,
   and the 2px accent bar under the group name is the last heavy edge left on
   the page. Name left, figure right, one rule per line. */
[data-layout="split"] .menu-item__lead { display: none; }
[data-layout="split"] .menu-item__row { justify-content: space-between; gap: 24px; }
[data-layout="split"] .menu-item__price {
  font-variant-numeric: lining-nums tabular-nums;
  text-align: right;
  min-width: 6ch;
}
[data-layout="split"] .menu-group__name {
  display: block;
  border-bottom: 1px solid var(--ink);
  font-size: 1.05rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding-bottom: 10px;
}
[data-layout="split"] .menu-group__desc { margin-top: 10px; }

/* ------------------------------ split: process, as information not a chart --- */
/*
   A filled disc with a number in it, threaded on a line, is a diagram of a
   process rather than the process. What somebody wants from four stages is
   what happens, in order, and roughly when. So the numeral becomes a small
   tracked figure hanging in the margin, the disc goes, and each stage sits on
   its own rule: a schedule, which is the shape a process has been set in
   since long before any of this.
*/
[data-layout="split"] .steps .step {
  background: none;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
  padding: clamp(18px, 2.4vw, 24px) 0 0;
  gap: clamp(12px, 1.8vw, 18px);
}
[data-layout="split"] .steps .step__num {
  /* Not a grid with its content centred in it: there is no disc left for
     anything to be centred inside, and the numeral has to sit on the same
     left edge as the words under it. */
  display: block;
  width: auto;
  height: auto;
  margin-top: 0;
  padding: 0;
  background: none;
  border-radius: 0;
  /* Same floor as the index numeral above, for the same reason. */
  color: var(--ink-2);
  font-family: var(--font);
  font-size: .9rem;
  font-weight: 600;
  line-height: 1.85;
  letter-spacing: .1em;
  font-variant-numeric: lining-nums tabular-nums;
}
[data-layout="split"] .steps .step h3 { font-size: 1.08rem; }
[data-layout="split"] .steps .step p { max-width: 54ch; }

/* ----------------------------------------------- split: what people wrote --- */

/* The quotation mark is an ornament drawn at 6rem in the accent above a
   sentence somebody actually said. The sentence is the evidence; the mark is
   a graphic asset sitting on top of it. */
[data-layout="split"] .review-quote__mark { display: none; }
[data-layout="split"] .review-quote__text { margin-top: 0; font-size: clamp(1.2rem, 2.8vw, 1.85rem); }
/* The quote and the ledger under it both took a 900px measure of their own,
   which inside the seam's column put two rules on the page ending 200 pixels
   apart from each other. The column is the measure now. */
[data-layout="split"] .review-quote,
[data-layout="split"] .review-lines { max-width: none; }
[data-layout="split"] .review-quote { border-top: 1px solid var(--ink); padding-top: clamp(20px, 2.6vw, 30px); }
[data-layout="split"] .review-quote__text { max-width: 26ch; }
[data-layout="split"] .review-lines { border-top-color: var(--line); }
[data-layout="split"] .review-line { border-bottom-color: var(--line); }

/* The ruled column opens on the same ink rule the pull quote does, so a
   reader moving between two of these sites meets one house style rather than
   two. */
[data-layout="split"] .reviews { border-top-color: var(--ink); }
[data-layout="split"] .reviews .review { border-bottom-color: var(--line); }

/* -------------------------------------------- split: questions and places --- */

[data-layout="split"] .faq--plain { border-bottom-color: var(--line); }
[data-layout="split"] .faq__row { border-top-color: var(--line); }
[data-layout="split"] .faq__a { max-width: 58ch; }

/*
   THE AREAS SERVED, AS A LIST OF PLACES.

   Nine rounded outlines with a coloured dot inside each is the tag component
   out of a component library, and after the review widget it is the most
   generated looking object left on the page. A list of towns is a list: set
   it in columns on hairlines and it reads as information a business
   published rather than as metadata a machine attached.
*/
[data-layout="split"] .areas {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0 clamp(20px, 3vw, 40px);
}
[data-layout="split"] .chip {
  display: block;
  padding: 11px 0;
  background: none;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
}
[data-layout="split"] .chip::before { display: none; }

/* ------------------------------------------------------ split: the photos --- */

/* Every picture on the page is square cornered and still. The slow zoom under
   the cursor is the last piece of motion in the layout and it belongs to a
   gallery widget, not to a photograph somebody took. */
[data-layout="split"] .gallery figure:hover img { transform: none; }
[data-layout="split"] .map { border-radius: 0; }

/* --------------------------------------------------- split: the masthead --- */
/*
   THE BAR THAT SAT ON THE PHOTOGRAPH.

   A translucent white bar was drawn across the whole window, and on the one
   layout whose hero is half paper and half photograph that put a white wash
   over the top 127px of the picture on a laptop and over 46 per cent of it on
   a phone. The old comment in this block claimed the header stayed in ink
   over the pale left half; it never did, because the ground is decided per
   page and not per half of one.

   The answer is not to two-tone the bar, which would leave a navigation link
   landing on whichever side of the seam the width happened to put it, white
   on paper at some widths and ink on a photograph at others. The answer is
   that the masthead is a band in its own right and the page divides
   underneath it: the bar is paper edge to edge, it closes with a hairline,
   and the photograph begins at its foot with nothing over it. What states the
   split up here is one 1px rule dropped down the middle of the bar, which is
   the top of the same seam the hero is cut on.
*/
[data-layout="split"] .header-inner { min-height: 78px; }
[data-layout="split"] .brand__name { font-size: 18px; letter-spacing: var(--heading-track); }
[data-layout="split"] .brand__meta { letter-spacing: .1em; font-size: 11px; text-transform: uppercase; }
[data-layout="split"] .nav { gap: clamp(10px, 1.6vw, 26px); }
[data-layout="split"] .nav a { padding: 8px 0; border-radius: 0; font-weight: 500; }
[data-layout="split"] .nav a:hover { background: none; color: var(--ink); }
[data-layout="split"] .nav a[aria-current="page"] { color: var(--ink); font-weight: 600; }
[data-layout="split"] .nav-toggle:hover { background: none; }

[data-layout="split"].has-hero .site-header {
  background: var(--page);
  backdrop-filter: none;
  border-bottom: 1px solid var(--line);
}
[data-layout="split"].has-hero .site-header.is-stuck {
  background: var(--page);
  box-shadow: none;
}
[data-layout="split"]:not(.has-hero) .site-header { border-bottom: 1px solid var(--line); }

/* The rail hangs the number off the edge of the window, which on this layout
   is where the photograph stops. Squared, so it reads as part of the same
   masthead rather than as a tab stuck onto the picture. */
[data-layout="split"] .phone-rail { border-radius: 0; }

/* ------------------------------------------------------- split: the hero --- */

[data-layout="split"] .hero--split:not(.hero--noimage) {
  align-items: stretch;
  padding: 0;
  min-height: 0;
  max-height: none;
}
[data-layout="split"] .hero--split:not(.hero--noimage) > .wrap { max-width: none; padding: 0; }
[data-layout="split"] .hero--split .hero__grid { gap: 0; align-items: stretch; }
[data-layout="split"] .hero--split .hero__inner { max-width: none; }
[data-layout="split"] .hero--split .hero__figure { margin: 0; }
[data-layout="split"] .hero--split .hero__figure img { border-radius: 0; width: 100%; }
[data-layout="split"] .hero--split h1 { font-size: clamp(2.25rem, 4vw, 3.4rem); line-height: 1.04; }
[data-layout="split"] .hero--split .hero__sub { max-width: 42ch; }
[data-layout="split"] .hero--split .trust { border-top-color: var(--rule); }

/* --------------------------------------------------- split: how a page opens --- */
/*
   The sub-page head, and the one place on the site where per page variation
   is possible at all. Variants are dealt per site, so /galleri and /om-oss
   were the same head over the same band with one section swapped in the
   middle. data-page is on <body>, so the stylesheet can open a page of
   photographs differently from a page of prices without any template having
   to know the rule exists.
*/
[data-layout="split"] .pagehead { border-bottom: 1px solid var(--rule); }
[data-layout="split"] .pagehead h1 { font-size: clamp(2.2rem, 5.4vw, 3.4rem); }
[data-layout="split"] .pagehead__eyebrow { letter-spacing: .1em; font-size: 12px; text-transform: uppercase; }

/* The two pages whose subject is a thing to look at or a person to read
   about open on their own name at full size and nothing else. The other two
   keep the standfirst, because what a page of figures costs needs a sentence
   in front of it. */
[data-layout="split"]:is([data-page="gallery"], [data-page="about"]) .pagehead h1 {
  font-size: clamp(2.6rem, 8vw, 5rem);
  max-width: 13ch;
}
[data-layout="split"]:is([data-page="gallery"], [data-page="about"]) .pagehead__lede { display: none; }
/* A page of photographs meets its photographs. The hairline under the head
   would be a line drawn on top of the edge the ink band already is. */
[data-layout="split"][data-page="gallery"] .pagehead { border-bottom: 0; }

/* -------------------------------------------------- split: how a page closes --- */
/*
   Every page used to end on the same tinted slab with the same heading and
   the same two buttons, five times per site. It is still the ask, because a
   page that does not ask is a leaflet, but it is drawn as the last division
   on the page rather than as a panel: paper, a full width rule in ink over
   it, the sentence on the left and the two ways of answering it in a column
   of their own behind the seam.
*/
[data-layout="split"] .closer,
[data-layout="split"] .section--alt + .closer,
[data-layout="split"] .section--dark + .closer {
  background: var(--page);
  border-top: 1px solid var(--ink);
}
[data-layout="split"] .closer h2 { font-size: clamp(1.4rem, 2.8vw, 2rem); max-width: 22ch; }
[data-layout="split"] .closer p { max-width: 48ch; }
[data-layout="split"] .closer__actions .btn--accent { min-height: 54px; font-size: 15.5px; }

/* --------------------------------------------------- split: the colophon --- */

[data-layout="split"] .site-footer {
  background: var(--surface);
  color: var(--ink-2);
  border-top: 1px solid var(--line);
  padding-top: 40px;
}
[data-layout="split"] .site-footer__name {
  color: var(--ink);
  font-size: 21px;
  letter-spacing: var(--heading-track);
}
[data-layout="split"] .site-footer__heading { font-weight: 600; letter-spacing: .14em; }
[data-layout="split"] .site-footer__top,
[data-layout="split"] .site-footer__legal { border-color: var(--line); }
[data-layout="split"] .site-footer__links a:hover,
[data-layout="split"] .site-footer__contact a:hover,
[data-layout="split"] .site-footer__by a:hover { color: var(--ink); }
[data-layout="split"] .site-footer__social a { color: var(--ink-2); border-radius: 0; }
/* The resting state was ported from the editorial footer and the hover state
   was not, so the 10 per cent white wash from the dark footer was still being
   asked for on a near white ground: invisible, on the one control in the
   block whose only feedback is that wash. */
[data-layout="split"] .site-footer__social a:hover { color: var(--ink); background: var(--line); }
[data-layout="split"] .site-footer__legal { color: var(--ink-2); }

/* The floating bubble is furniture the trade either wants or does not, and
   that decision is not this layout's to make. What is this layout's to make
   is that when it is drawn it is a square label in the corner rather than a
   shadowed lozenge hovering over the page. */
[data-layout="split"] .chat__fab,
[data-layout="split"] .chat__panel,
[data-layout="split"] .chat__send { border-radius: 0; }
[data-layout="split"] .chat__fab { box-shadow: none; }

[data-layout="split"] .skip-link { background: var(--ink); color: var(--page); }

/* ====================================================== split: under 1080 ==== */
/*
   The seam cannot be vertical here: a 248px margin column beside a 560px one
   is two narrow columns rather than a page with a margin. The horizontal rule
   over the section's name, declared above, is what states the division at this
   width; all this does is stop the name running the full width of the page
   under it.
*/
@media (max-width: 1079px) {
  [data-layout="split"] .section > .wrap > .section-head { max-width: 38rem; }
}

/* ======================================================== split: to 859px ==== */
/*
   THE PHONE, WHICH IS MOST OF THE TRAFFIC AND USED TO BE THE DEFAULT PAGE.

   The words come first, on paper, under the bar. The photograph follows them
   and runs the full width of the screen to a long crop, so the division of
   the page is still one straight edge across the whole of it. Nothing here is
   the desktop arrangement stacked: the desktop is type beside a picture, this
   is type above one, and both are the same sentence.
*/
@media (max-width: 859px) {
  [data-layout="split"] .hero--split:not(.hero--noimage) .hero__inner {
    padding: calc(var(--header-top) + var(--header-h) + clamp(26px, 7vw, 46px)) 20px clamp(30px, 7vw, 46px);
  }
  [data-layout="split"] .hero--split .hero__figure img { aspect-ratio: 4 / 4.1; }
  /* Edge to edge, and it is the bottom of the first screen, so there is
     nothing under it inside the hero for a gap to open in. */
  [data-layout="split"] .hero--split:not(.hero--noimage) { padding-bottom: 0; }

  [data-layout="split"] .svc-row__meta {
    flex-direction: row;
    justify-content: space-between;
    width: 100%;
    margin-left: 0;
  }
  [data-layout="split"] .svc-row__price { text-align: left; min-width: 0; }
  [data-layout="split"] .closer__actions { width: 100%; }
}

/* ==================================================== split: 860 and over ==== */

@media (min-width: 860px) {
  /*
     THE HERO.

     The bar is a band of its own and the page divides underneath it, so the
     hero starts at the foot of the header rather than under it. Height is
     clamped at both ends: 88svh on a 1440x900 laptop is a first screen nobody
     can see the bottom of, and on a large monitor it was a photograph two and
     a half thousand pixels tall.
  */
  [data-layout="split"] .hero--split:not(.hero--noimage) {
    padding-top: calc(var(--header-top) + var(--header-h));
  }
  [data-layout="split"] .hero--split .hero__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    min-height: clamp(500px, 74svh, 760px);
  }
  [data-layout="split"] .hero--split .hero__figure img { aspect-ratio: auto; height: 100%; }

  /*
     THE TEXT COLUMN SITS ON THE PAGE GRID, MEASURED THE WAY THE PAGE IS.

     This used to be calc((100vw - 1180px) / 2 + 20px). 100vw includes the
     classic scrollbar and .wrap does not, so on Windows and on most of Linux
     the headline stood 7.5px to the right of every other left edge on the
     page: 150 against 142.5, measured. The column is exactly half the hero,
     so 200 per cent of the column is the width the wrap is centred inside,
     with no viewport unit anywhere in it and nothing left to disagree with.
  */
  [data-layout="split"] .hero--split .hero__inner {
    align-self: center;
    padding: clamp(36px, 4vw, 64px) clamp(30px, 3.4vw, 60px) clamp(36px, 4vw, 64px)
             max(20px, calc((200% - 1180px) / 2 + 20px));
  }

  /* The top of the seam. One rule down the middle of the masthead, in line
     with the edge the photograph is cut on, so the division of the page
     begins at the first pixel of it rather than 78 pixels down.
     .site-header::before is the scrim the dark heroes use and this layout has
     no dark hero, so the element is free. */
  [data-layout="split"].has-hero .site-header::before {
    content: '';
    display: block;
    inset: 0 auto 0 50%;
    width: 1px;
    background: var(--line);
    opacity: 1;
  }
}

/* =================================================== split: 1080 and over ==== */

@media (min-width: 1080px) {
  /*
     THE SEAM, ON EVERY PAGE THAT IS NOT THE FRONT ONE.

     The section's name and standfirst hang in a column of their own and the
     work runs in the wide one, with the rule between them carrying the full
     height of the section. It is the same division the hero is built on, at
     the width a page of text can hold it, and it is what stops the five pages
     of one business reading as five copies of one stack.

     Scoped to a head that is a direct child of .wrap. The about section and
     the free text block have no head and keep the full measure; the booking
     page runs its own two column grid and is left alone.

     The row span is what makes the rule full height. A section with one block
     of content under its head is one row and the head would stretch anyway; a
     section with two or three is not, and -1 resolves to the end of the
     EXPLICIT grid, which here is row one. Spanning a fixed count creates the
     implicit rows instead, and the ones with nothing in them are zero high.
  */
  [data-layout="split"] .section > .wrap:has(> .section-head):not(:has(> .gallery)) {
    display: grid;
    grid-template-columns: minmax(0, 248px) minmax(0, 1fr);
    column-gap: clamp(34px, 3.6vw, 64px);
  }
  [data-layout="split"] .section > .wrap:not(:has(> .gallery)) > .section-head {
    grid-column: 1;
    grid-row: 1 / span 12;
    margin-bottom: 0;
    padding-top: 0;
    padding-right: clamp(22px, 2.4vw, 38px);
    border-top: 0;
    border-right: 1px solid var(--seam);
  }
  [data-layout="split"] .section > .wrap > :not(.section-head) { grid-column: 2; }

  /*
     THE ONE SECTION THAT KEEPS THE WHOLE WIDTH.

     A pair of photographs is drawn to the edges of the window on purpose, by
     a shared rule with a negative margin on it. Placed in the seam's right
     hand column that margin measures from the column and the pictures run 300
     pixels past the right edge of the page, which is a horizontal scrollbar on
     the one page a visitor came to look at. It is also the wrong answer twice
     over: on a layout whose argument is that a photograph deserves half the
     window, the page of photographs is the last place to put them in a
     column. The head keeps the horizontal rule and sits above them.
  */
  [data-layout="split"] .section > .wrap > .gallery { grid-column: auto; }

  /*
     THE SECTIONS WITH NO HEAD TO HANG IN THE MARGIN.

     The about block writes its own heading, the free text block writes its
     own, the booking form opens with an intro instead, and a services or
     features section whose document gave it no title prints no head at all.
     Four shapes, no section-head between them, and left alone they start 300
     pixels to the left of everything around them: a page with two left edges
     has neither. The margin simply stays empty and the content keeps the
     column the rest of the page is read in.

     Stated as the wrap's own padding rather than as a grid, because these
     four already lay their insides out in grids of their own and the point
     here is only where the column starts.
  */
  [data-layout="split"] .section > .wrap:not(:has(> .section-head)) {
    padding-left: calc(20px + 248px + clamp(34px, 3.6vw, 64px));
  }

  /* The page head takes the same geometry, so a sub-page opens on the seam it
     is then read down. The breadcrumb is what sits in the margin column,
     which is what a running head is. */
  [data-layout="split"] .pagehead > .wrap {
    display: grid;
    grid-template-columns: minmax(0, 248px) minmax(0, 1fr);
    column-gap: clamp(34px, 3.6vw, 64px);
    align-items: start;
  }
  [data-layout="split"] .pagehead__eyebrow {
    grid-column: 1;
    grid-row: 1 / span 4;
    /* The wrap aligns its items to the top, so without this the rule beside
       the breadcrumb was as tall as the breadcrumb: thirty pixels of hairline
       against a four line page name. */
    align-self: stretch;
    margin: 0;
    padding-right: clamp(22px, 2.4vw, 38px);
    border-right: 1px solid var(--rule);
  }
  [data-layout="split"] .pagehead h1 { grid-column: 2; grid-row: 1; max-width: 18ch; }
  [data-layout="split"] .pagehead__lede { grid-column: 2; grid-row: 2; margin: 18px 0 0; max-width: 52ch; }

  /* And the closer closes on it: the ask in the wide column, the two ways of
     answering in a column of their own behind the rule. */
  [data-layout="split"] .closer__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 300px);
    column-gap: clamp(34px, 3.6vw, 64px);
    align-items: start;
  }
  [data-layout="split"] .closer__actions {
    display: grid;
    gap: 10px;
    align-self: stretch;
    padding-left: clamp(26px, 2.8vw, 44px);
    border-left: 1px solid var(--rule);
  }
  [data-layout="split"] .closer__actions .btn { width: 100%; }
}

/* The colophon divides too, at the width its own four columns appear. */
@media (min-width: 900px) {
  [data-layout="split"] .site-footer__brand {
    padding-right: clamp(24px, 2.6vw, 40px);
    border-right: 1px solid var(--line);
  }
}

/* ============================================================================
   DARK
   ============================================================================
   A DARK ROOM WITH THE WORK LIT IN IT.

   Five businesses are drawn with this layout and every one of them sells how
   something looks: a photographer, two barbers, a sushi counter and a tattoo
   studio. On a page for any of them the photographs are the subject and
   everything else is the label beside the photograph. That is one idea and it
   decides every rule below.

   WHAT WAS HERE BEFORE. Seventeen lines: a stuck header ground, a heavier
   hero scrim, one border, a call bar tint and a ten per cent ring round the
   monogram. Not one of them touched a heading, a section opening, a price, a
   review, a photograph, a control, the closing band or the footer, so a dark
   page was the classic page with Theme.php's ink scale flipped. A recolour.

   THE THREE THINGS THAT ARE DIFFERENT ABOUT A DARK PAGE, and what follows
   from each:

   1. A DARK PAGE HAS NO BANDS. The renderer's whole rhythm is value steps
      between grounds, and on a near-black primary they do not exist: measured
      on the live pages, --surface is 1.12:1 against --page, --card 1.19:1 and
      --deep 1.04:1. Four grounds that are one ground. Widening them is a fight
      with nowhere to go, because below the page there is no room and above it
      any lift big enough to be seen stops the page being dark.

      So the bands are abolished rather than repaired. Every section on this
      layout sits on the page's own black and is separated from the next by a
      rule that can be seen: --rule is white at 34 per cent, 3.1:1 against the
      page and 3.06:1 against the darkest ground in the set, which is the
      contrast a control edge owes a reader and therefore well past what a
      drawn line needs. The sections are full width already, so the rule is
      their own border and nothing is positioned to produce it. On a phone,
      where there is no grid and no wall of pictures to break the run, those
      rules and the number beside them are the only structure the page has,
      and both are now legible.

   2. A DARK PAGE CANNOT AFFORD A FILL. A rectangle one per cent lighter than
      the ground is not a card, it is a border that failed to load. Every
      filled object is emptied here: the service card, the fact card, the
      stage card, the review card, the booking card, the two contact panels,
      the area pill, the today pill and the form field. What is left is type
      on black, ruled, which is the register the photographs want around them.
      The single exception is the primary button, which keeps the accent: one
      saturated object per screen, and it is the one the reader is meant to
      press.

   3. THE PICTURES RUN TO THE EDGES. A photograph inside a 1180px column with
      twenty pixels of padding each side is a photograph in a slot. Here the
      wall escapes the column and runs to the window, the hero photograph is a
      full width plate with nothing over it, and the about photograph carries
      its own words with no panel laid on top of it. Those are the only wide
      objects on the site and they are the reason to scroll it.

   HOW A SECTION OPENS, AND WHY THERE IS A NUMBER IN THE MARGIN. Every layout
   in this file used to open a section the same way: a tracked eyebrow behind
   a short accent bar, a serif h2, a grey line of lede, stacked in a 640px
   column. Fifteen times across five pages that is not a heading, it is a
   stamp, and on the services page of one of these sites the eyebrow read the
   same four words as the h2 forty pixels under it. The eyebrow goes, from
   every section. What replaces it is the label a gallery hangs beside a
   print: a two figure plate number in the left margin, counted by CSS so no
   document has to carry it, with the heading and the standfirst set off it on
   one baseline. The sequence restarts on every page, so the four pages of one
   business open on 01 and run to a different last number, which is a
   difference a reader can see before reading a word.

   Specificity note, the same one the atelier block carries: nearly every
   selector here is [data-layout="dark"] X, which is (0,2,0) and beats the
   plain (0,1,0) rules inside the shared media queries at every width. It also
   ties with the variant blocks' own (0,2,0) rules and wins on source order,
   because this is the last block in the file. Anything that has to change
   WITH the viewport is written into this block's own media queries at the
   end, never up here.
   ========================================================================= */

body[data-layout="dark"] {
  /*
     SQUARE. Three of these five documents asked for four pixels of rounding,
     and on this register four pixels is a tell: a print hung on a wall has
     corners, and a photograph with softened ones reads as a component in a
     page builder. Every photograph, every field and every control here is cut
     square.
  */
  --radius: 0px;

  /*
     A MISSING CUT MUST FAIL RATHER THAN BE FAKED. The display faces this
     layout is dealt are a Bodoni, a Playfair, a Cormorant and a Bricolage, and
     the first three are high contrast: a browser-synthesised bold on a face
     cut for stroke modulation is a smear. With synthesis off, a weight the
     file has not got simply does not arrive.
  */
  font-synthesis: none;

  /*
     TWO RULE WEIGHTS, because a layout with no fills has nothing else to
     separate anything with.

     The shipped --line is white at fourteen per cent, 1.48:1 against the page.
     Inside a list, between one price and the next, something that quiet is
     right: the eye reads a run of them as a ruled column and the repetition
     carries it. As the boundary between two subjects it is invisible, which is
     what made every dark page one unbroken black column.

     --rule       white at 34 per cent, 3.1:1. Structure: the line between two
                  sections, the top of a panel, the top of the closing band,
                  the top of the footer, the edge of the call bar.
     --rule-soft  white at 20 per cent, 1.85:1. The hairlines inside a list,
                  lifted a step from the shipped value because at 1.48 on a
                  black page a run of eight of them is a smudge rather than a
                  set of rules. --line takes the same value, so anything not
                  named below is lifted with them.

     Both are stated as white over the page rather than as mixes of the
     primary, which is what --line already does on this side of the scale.
  */
  --rule: rgb(255 255 255 / .34);
  --rule-soft: rgb(255 255 255 / .2);
  --line: rgb(255 255 255 / .2);

  /* The plate numbers. Reset on the body, counted on every section head, so a
     page numbers the sections it actually has. */
  counter-reset: plate;
}

/* --------------------------------------------------------- dark: rhythm --- */

/*
   ONE GROUND, AND A RULE BETWEEN SUBJECTS.

   .section--alt and .section--dark are value steps of 1.12:1 and 1.04:1, so
   they are not drawn at all here. The shared rule that halves the seam where
   two sections happen to share a ground is not restated either: on this
   layout EVERY pair of sections shares a ground, the rule between them is
   always drawn, and the padding is therefore always the same. One rhythm, and
   no exceptions to keep in step.
*/
[data-layout="dark"] .section {
  padding: clamp(66px, 9vw, 132px) 0;
  border-top: 1px solid var(--rule);
}
[data-layout="dark"] .section--tight { padding: clamp(46px, 6vw, 78px) 0; }
[data-layout="dark"] .section--alt {
  background: none;
  border-block: 0;
  border-top: 1px solid var(--rule);
}
[data-layout="dark"] .section--dark { background: none; }
/* The first of those rules is drawn by the section under the page head, so
   the head must not draw a second one directly above it. */
[data-layout="dark"] .pagehead { border-bottom: 0; }

/* ------------------------------------------ dark: how a section opens --- */

/*
   THE PLATE NUMBER, THE HEADING AND THE STANDFIRST, ON ONE BASELINE.

   The eyebrow goes from every section. A page is allowed one and the front
   page already has it over the headline, where it names the street; every
   other one on the site was repeating the navigation label immediately above
   a heading that said the same thing larger.

   What the section gets instead is the number. It is a counter, so nothing in
   any document has to carry it and no two pages of one site can end on the
   same figure. It hangs in a margin of its own and sits on the heading's first
   baseline rather than above it, which is the difference between a label
   printed beside a picture and a kicker printed over one.

   The standfirst moves out from under the heading into a column beside it,
   held to a short measure. Stacked, it was the third line of the identical
   grey block every section on every layout opened with.
*/
[data-layout="dark"] .section-head { counter-increment: plate; }
[data-layout="dark"] .section .eyebrow { display: none; }

[data-layout="dark"] .wrap > .section-head {
  max-width: none;
  display: grid;
  grid-template-areas: 'folio' 'title' 'lede';
  gap: 10px 0;
  margin-bottom: clamp(34px, 5vw, 58px);
}
[data-layout="dark"] .wrap > .section-head::before {
  content: counter(plate, decimal-leading-zero);
  grid-area: folio;
  font-family: var(--font);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .2em;
  line-height: 1.2;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="dark"] .wrap > .section-head h2 { grid-area: title; }
[data-layout="dark"] .wrap > .section-head p:not(.eyebrow) { grid-area: lede; margin-top: 6px; }
[data-layout="dark"] .section-head--compact { margin-bottom: clamp(24px, 3vw, 34px); }

/* The questions nest their head inside one column of a two column grid, so
   there is no margin out there to hang a number in. It goes above the heading
   and that head keeps its stack. */
[data-layout="dark"] .faq-grid > .section-head::before {
  content: counter(plate, decimal-leading-zero);
  display: block;
  margin-bottom: 12px;
  font-family: var(--font);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .2em;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="dark"] .faq-grid .section-head h2 { font-size: clamp(1.5rem, 3.2vw, 2.1rem); }

/* ----------------------------------------------------------- dark: type --- */

[data-layout="dark"] .section-head h2,
[data-layout="dark"] .about__body h2,
[data-layout="dark"] .booking__intro h2 {
  font-size: clamp(1.8rem, 4.2vw, 2.9rem);
  line-height: 1.06;
}
[data-layout="dark"] .section-head h2.h2--small { font-size: clamp(1.45rem, 3vw, 1.95rem); }
[data-layout="dark"] .section-head p:not(.eyebrow) { color: var(--ink-2); max-width: 44ch; }
[data-layout="dark"] .about__body p,
[data-layout="dark"] .prose p { line-height: 1.72; }
[data-layout="dark"] .about__body,
[data-layout="dark"] .prose { max-width: 62ch; }
/* A 54 by 3 block of the accent under a heading is a widget's underline. A
   hairline the width of a thumb is a printed rule. */
[data-layout="dark"] .about__rule {
  width: 64px;
  height: 1px;
  background: var(--rule);
  margin: 24px 0;
}

/* ------------------------------------------------------- dark: controls --- */

/*
   ONE COLOURED OBJECT PER SCREEN, AND IT IS THE ONE TO PRESS.

   The accent is the only saturated thing anywhere on this layout, so it is
   spent on the primary button and on the stars and nowhere else. Everything
   that used to take it because it was the nearest token to hand (the panel
   heading, the contact icons, the today pill, the current navigation item)
   takes a white instead, which is both quieter and, at 9.4:1, readable, which
   the raw accent was not: measured on the darkest two palettes in the set it
   lands at 2.98:1 and 3.55:1 on the deep ground, under the 4.5 a label owes.
*/
[data-layout="dark"] .btn {
  border-radius: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: 17px 28px;
  /* An uppercase label runs about a third wider than the same words in
     sentence case, and nothing in the schema caps a ctaLabel. A flex item that
     cannot wrap overflows its track instead of shrinking, so it wraps and
     balances its lines. */
  white-space: normal;
  text-wrap: balance;
}
[data-layout="dark"] .btn:hover { transform: none; }
[data-layout="dark"] .btn--accent { box-shadow: none; }
[data-layout="dark"] .btn--ghost,
[data-layout="dark"] .btn--outline {
  --btn-bg: transparent;
  --btn-ink: var(--ink);
  /* --line is a hairline for separating blocks and measures 1.85:1 here. The
     edge of a control is the whole of the control and owes a reader 3:1;
     --ink-3 is 9.4:1 and is what the call bar and the closing band already
     reach for on every other layout, for exactly this reason. */
  border: 1px solid var(--ink-3);
  backdrop-filter: none;
}
[data-layout="dark"] .btn--ghost:hover,
[data-layout="dark"] .btn--outline:hover {
  background: rgb(255 255 255 / .1);
  border-color: var(--ink);
}
/* The fixed bar holds two controls across the whole width of a phone and
   tracked capitals do not fit there. It keeps the sentence setting, which is
   also the right register for a control following the reader down the page
   rather than sitting in the composition. */
[data-layout="dark"] .callbar .btn {
  text-transform: none;
  letter-spacing: -0.005em;
  font-size: 15px;
  padding: 13px 16px;
}
/* A meaningful graphic rather than decoration, so it holds 3:1 on the ground
   it is drawn on. The lifted accent clears 4.8:1 on every palette in the set
   and the raw one does not. */
[data-layout="dark"] .stars__fill { color: var(--accent-strong); }

/* --------------------------------------------------- dark: the masthead --- */

/*
   A WORDMARK, NOT A MONOGRAM IN A BOX.

   Two capital letters in a filled accent square is what a placeholder looks
   like in a design tool, and it is named in the brief as a template tell. It
   is furniture and already off for these trades; this makes it a property of
   the layout, so a niche that switches it back on does not switch it on here.

   What carries the identity instead is the name, set in the display face at
   the size a wordmark is set, with the district under it in the small tracked
   capitals every label on this layout is set in. The navigation goes into the
   same capitals: at eleven and a half pixels with two tenths of an em between
   the letters it is a gallery's own signage rather than a row of links, and
   the current page is marked by a rule under the word rather than by the raw
   accent, which measured 2.86:1 over the hero on the darkest palette.
*/
[data-layout="dark"] .brand__mark { display: none; }
[data-layout="dark"] .brand > span { align-content: center; }
[data-layout="dark"] .brand__name {
  font-size: clamp(17px, 1.7vw, 21px);
  font-weight: var(--heading-weight);
  letter-spacing: .01em;
}
[data-layout="dark"] .brand__meta {
  display: block;
  margin-top: 4px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .26em;
  text-transform: uppercase;
}
[data-layout="dark"] .nav a {
  position: relative;
  font-family: var(--font);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
  padding: 12px 0;
  margin-inline: clamp(9px, 1.3vw, 17px);
  border-radius: 0;
}
[data-layout="dark"] .nav a:hover { background: none; }
[data-layout="dark"] .nav a[aria-current="page"] { color: #fff; font-weight: 600; }
[data-layout="dark"] .is-stuck .nav a[aria-current="page"],
[data-layout="dark"]:not(.has-hero) .nav a[aria-current="page"] { color: var(--ink); }
[data-layout="dark"] .nav a[aria-current="page"]::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 6px;
  height: 1px;
  background: currentColor;
  opacity: 1;
}
[data-layout="dark"] .header-tel {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .18em;
}

/* The bar floats over the plate from the first pixel of the page, so the
   gradient behind it is not decoration: it is what makes an eleven pixel
   tracked capital readable over a photograph nobody vetted. */
[data-layout="dark"] .site-header::before {
  background: linear-gradient(to bottom, rgb(0 0 0 / .74), rgb(0 0 0 / .3) 58%, rgb(0 0 0 / 0));
}
[data-layout="dark"] .site-header.is-stuck {
  background: rgb(var(--primary-rgb) / .92);
  backdrop-filter: saturate(140%) blur(16px);
  border-bottom-color: var(--rule);
  box-shadow: none;
}
[data-layout="dark"] .is-stuck .brand__name,
[data-layout="dark"] .is-stuck .nav a,
[data-layout="dark"] .is-stuck .nav-toggle,
[data-layout="dark"] .is-stuck .header-tel,
[data-layout="dark"] .is-stuck .status-pill { color: #fff; }
[data-layout="dark"] .is-stuck .brand__meta { color: rgb(255 255 255 / .62); }
[data-layout="dark"] .is-stuck .nav a:hover,
[data-layout="dark"] .is-stuck .nav-toggle:hover { background: rgb(255 255 255 / .1); }

/* The drawer is the whole screen on this layout, so it takes the page's own
   black rather than the deep tint nobody can tell apart from it. */
[data-layout="dark"] .mobile-nav { background: var(--page); }
[data-layout="dark"] .mobile-nav a { border-bottom-color: var(--rule-soft); }

/* The number hung off the edge of the window, on the sites dealt the rail. It
   was --card on --page, which is 1.19:1: a tab with no edge on it. */
[data-layout="dark"] .phone-rail {
  background: var(--page);
  border-color: var(--ink-3);
  border-radius: 0;
  color: var(--ink);
  box-shadow: none;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
}
[data-layout="dark"] .phone-rail svg { color: var(--accent-strong); }
[data-layout="dark"] .phone-rail:hover { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }

/* ----------------------------------------------------------- dark: hero --- */

/*
   THE PHOTOGRAPH IS NOT A BACKGROUND.

   This hero used to be classic's, shared branch and all: one picture behind
   the words with a scrim over it heavy enough to hold white type over any
   brightness. On a layout whose five businesses all sell how something looks,
   that scrim is the design deciding the photograph does not matter. Measured
   on the live pages it took the picture to within a point or two of the page
   colour across the top two thirds of the screen, so five sites opened on a
   rectangle of nearly nothing.

   The picture is a plate now: full width, nothing over it but the header's own
   gradient, its own hard bottom edge, and the words beginning on the black
   underneath it where they need no scrim to be read. It is the only hero in
   this file where the type and the photograph do not overlap at all, which is
   the argument of the whole layout stated once at the top of the page.
*/
.hero--dark {
  display: block;
  min-height: 0;
  max-height: none;
  overflow: visible;
  padding: 0 0 clamp(44px, 6vw, 88px);
  background: var(--page);
}
.hero--dark .hero__plate {
  margin: 0;
  overflow: hidden;
  background: var(--deep);
}
.hero--dark .hero__plate img {
  display: block;
  width: 100%;
  /* svh rather than vh: on a phone the address bar collapses on the first
     scroll and a vh plate would grow by eighty pixels while the reader was
     looking at it. Capped, so a tall desktop window does not hand the whole
     first screen to one photograph and leave the name of the business below
     the fold. */
  height: clamp(370px, 74svh, 760px);
  object-fit: cover;
  object-position: center 45%;
}
.hero--dark > .wrap { padding-top: clamp(26px, 3.4vw, 48px); }
.hero--dark h1 {
  font-size: clamp(2.3rem, 6.4vw, 4.6rem);
  /* 1.0 is solid leading, and solid leading is only safe in a language whose
     capitals are flat on top. Swedish puts a ring on one of its vowels and two
     dots on two more, and at 74px a line that breaks with a descender above
     one of them has the two touching. */
  line-height: 1.04;
  max-width: 15ch;
}
body[data-layout="dark"] .hero--dark .eyebrow {
  color: var(--accent-strong);
  letter-spacing: .26em;
  font-size: 11px;
  font-weight: 600;
  margin-bottom: 14px;
}
/* The 26 by 2 block of accent in front of the label is a card's mark, and on
   the black there is nothing for it to mark. The words say what it is. */
body[data-layout="dark"] .hero--dark .eyebrow::before { display: none; }
.hero--dark .hero__sub {
  margin-top: 0;
  color: var(--ink-2);
  max-width: 44ch;
  font-size: clamp(1.02rem, 2vw, 1.16rem);
  line-height: 1.65;
}
.hero--dark .hero__actions { margin-top: clamp(22px, 3vw, 30px); }
/* The meta row measures itself against the column it is in, and on this hero
   that column is the foot rather than .hero__inner, which is not in the tree
   at all. Named here so the shared container query still has something to
   ask. */
.hero--dark .hero__foot {
  container-type: inline-size;
  container-name: heroinner;
  margin-top: clamp(26px, 4vw, 42px);
}
.hero--dark .hero__foot:empty { display: none; }
.hero--dark .trust {
  margin-top: 0;
  border-top-color: var(--rule);
  color: var(--ink-2);
}
.hero--dark .trust__score { color: var(--ink); }

/* ---------------------------------------------- dark: how a page opens --- */

/*
   THE RUNNING HEAD AND THE PLATE TITLE.

   The shared page head sets its breadcrumb as a line of body type on purpose,
   because at 13px uppercase it rhymed with the section eyebrow forty pixels
   below it and every sub-page opened with the same recipe twice over. On this
   layout there is no section eyebrow left anywhere to rhyme with, so the rhyme
   is gone and the capitals are free to do the job they are good at: a running
   head over a title, which is how the wall text beside a print is set.
*/
[data-layout="dark"] .pagehead { padding-bottom: clamp(30px, 5vw, 66px); }
[data-layout="dark"] .pagehead__eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--ink-3);
}
[data-layout="dark"] .pagehead h1 { font-size: clamp(2.4rem, 7.6vw, 4.8rem); line-height: 1.04; }
[data-layout="dark"] .pagehead__lede { color: var(--ink-2); }

/*
   AND THE PICTURE PAGE OPENS ON PICTURES.

   Variants are dealt per site rather than per page, so every page of a site
   carries the same shapes and the only thing that differs between them is
   which sections are present. That is what makes five pages look stamped. The
   attribute the renderer already prints on <body> is the way out of it inside
   one layout's own scope: on the page whose subject is the work, the head
   stops taking a third of the first screen and the photographs start inside
   it. It is the one page of the five that does not open on a rule.
*/
[data-layout="dark"][data-page="gallery"] .pagehead { padding-bottom: clamp(18px, 3vw, 34px); }
[data-layout="dark"][data-page="gallery"] .pagehead + .section {
  border-top: 0;
  padding-top: clamp(26px, 4vw, 46px);
}

/* ----------------------------------------------------- dark: the lists --- */

/*
   THERE ARE NO CARDS LEFT, AND NOTHING HERE STYLES A SHAPE THIS LAYOUT CANNOT
   BE DEALT.

   Variants::BY_LAYOUT narrows this layout to the shapes that survive with no
   fills: the ruled schedule and the printed index for services, the hairline
   strip and the plain grid for facts, the column and the pull quote for
   reviews, the wall and the lead plate for photographs, one ruled list for
   questions. Every rule below is written against one of those. The shapes it
   can no longer be dealt have no rules here rather than rules nobody will ever
   see.
*/

/* ----- what the work costs, as a schedule rather than as a menu ----- */

/*
   THE FIGURES ARE A COLUMN, NOT A PUNCHLINE.

   Three things were wrong with a price on this layout. It was set in the
   accent, which turns a column of numbers into a column of links and gets them
   scanned before any of the names. It was set in the display face, which on a
   Bodoni or a Cormorant means old style figures of four different heights in
   what is meant to be a table. And in the price list it hung off a row of
   dotted leaders, which is a restaurant card being reused as a fee schedule
   for a haircut and a tattoo session.

   So: the body face, tabular lining figures, the page's own white, and a
   column wide enough that four digits and a currency never reflow. The leaders
   are gone and the two columns are a grid, so a reader can run a finger down
   the right hand edge and the numbers line up digit under digit.
*/
[data-layout="dark"] .svc-list__price,
[data-layout="dark"] .svc-index__price,
[data-layout="dark"] .menu-item__price,
[data-layout="dark"] .service__price {
  font-family: var(--font);
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: .01em;
  color: var(--ink);
  font-variant-numeric: tabular-nums lining-nums;
  min-width: 6ch;
  text-align: right;
}
[data-layout="dark"] .svc-list { border-top: 1px solid var(--rule); }
[data-layout="dark"] .svc-list__item { border-bottom-color: var(--rule-soft); }
[data-layout="dark"] .svc-list__name,
[data-layout="dark"] .svc-index__name { font-weight: var(--heading-weight); }
[data-layout="dark"] .svc-list__desc,
[data-layout="dark"] .svc-index__desc { color: var(--ink-2); max-width: 52ch; }
[data-layout="dark"] .svc-list__time {
  font-size: 11.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
}

/* The index numeral is a folio like the plate number above it, not a display
   figure: small, tracked, in the quiet white, hanging in a fixed column so
   every name starts on the same vertical. */
[data-layout="dark"] .svc-index { border-top: 1px solid var(--rule); }
[data-layout="dark"] .svc-index__item { border-bottom-color: var(--rule-soft); }
[data-layout="dark"] .svc-index__num {
  color: var(--ink-3);
  font-family: var(--font);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: .2em;
  line-height: 2.4;
}

/* The price list, with the dotted leaders taken out of it. */
[data-layout="dark"] .menu-groups { gap: clamp(34px, 5vw, 58px); }
[data-layout="dark"] .menu-group__name {
  display: block;
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: 4px;
  font-size: clamp(1.15rem, 2.4vw, 1.45rem);
  font-weight: var(--heading-weight);
}
[data-layout="dark"] .menu-group__desc { color: var(--ink-2); margin: 4px 0 14px; }
[data-layout="dark"] .menu-list { border-top: 1px solid var(--rule); }
[data-layout="dark"] .menu-item { border-bottom-color: var(--rule-soft); padding: 14px 0; }
[data-layout="dark"] .menu-item:last-child { border-bottom: 1px solid var(--rule-soft); }
[data-layout="dark"] .menu-item__lead { display: none; }
[data-layout="dark"] .menu-item__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: clamp(16px, 3vw, 44px);
  align-items: baseline;
}
[data-layout="dark"] .menu-item__name {
  font-family: var(--font-heading);
  font-weight: var(--heading-weight);
}
[data-layout="dark"] .menu-item__desc { color: var(--ink-2); max-width: 56ch; }
[data-layout="dark"] .menu-note { border-top-color: var(--rule); color: var(--ink-2); }

/* ----- the facts, on hairlines ----- */

[data-layout="dark"] .features { gap: 0 clamp(24px, 3vw, 40px); }
[data-layout="dark"] .feature {
  background: none;
  border: 0;
  border-top: 1px solid var(--rule-soft);
  border-radius: 0;
  padding: 16px 0 22px;
  gap: 12px;
}
[data-layout="dark"] .feature__icon {
  width: auto;
  height: auto;
  background: none;
  border-radius: 0;
  color: var(--accent-strong);
}
[data-layout="dark"] .feature__icon svg { width: 18px; height: 18px; }
[data-layout="dark"] .feature p { color: var(--ink-2); }
[data-layout="dark"] .feat-strip { border-block-color: var(--rule); }
[data-layout="dark"] .feat-strip__item + .feat-strip__item { border-top-color: var(--rule-soft); }
[data-layout="dark"] .feat-strip__icon { color: var(--accent-strong); }

/* ----- the process, as a programme rather than as a diagram ----- */

/*
   FOUR NUMBERED DISCS IN A ROW IS A DIAGRAM OF A PROCESS, NOT A PROCESS, and
   the timeline that threads them on a line is the same diagram with the line
   drawn in. Both are out of this layout's pool.

   What is left is set the way a programme is set: a rule, the stage on the
   left in the display face, and what happens in it on the right at a reading
   measure. The figure is dropped rather than shrunk. It was an ordinal and
   nothing else, and the order of four things down a page is already told by
   the order of four things down a page; keeping it as a small grey number
   beside every stage is a footnote marker with nothing to point at.
*/
[data-layout="dark"] .steps { grid-template-columns: minmax(0, 1fr); gap: 0; }
[data-layout="dark"] .steps .step {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  margin: 0;
  padding: clamp(20px, 3vw, 30px) 0;
  background: none;
  border: 0;
  border-top: 1px solid var(--rule-soft);
  border-radius: 0;
  box-shadow: none;
}
[data-layout="dark"] .steps .step:first-child { border-top-color: var(--rule); }
[data-layout="dark"] .steps .step__num { display: none; }
[data-layout="dark"] .steps .step h3 {
  font-size: clamp(1.1rem, 2.2vw, 1.35rem);
  font-weight: var(--heading-weight);
  line-height: 1.2;
}
[data-layout="dark"] .steps .step p { margin-top: 0; color: var(--ink-2); max-width: 58ch; }

/* ----- what people wrote ----- */

/*
   THE SCOREBOARD IS A SENTENCE, AND THE PULL QUOTE HANGS OFF A RULE.

   The big numeral, the star row and the third party badge beside it are
   furniture and already off for these five trades, so what draws is the single
   line of type that replaced them. On this layout that line is set as a
   caption: small, tracked, in the quiet white, on the rule the quotations hang
   from, which puts the fact about the section above the section rather than
   floating between the heading and the first quote.

   The oversized quotation glyph goes. It is deliberately set below the
   contrast floor because it is an ornament, and this layout has no ornaments.
   A rule down the left of the quote says the same thing and says it in the
   vocabulary the rest of the page is written in.
*/
[data-layout="dark"] .rating-line {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-bottom: clamp(18px, 2.6vw, 26px);
  margin-bottom: clamp(26px, 4vw, 40px);
  border-bottom: 1px solid var(--rule);
}
[data-layout="dark"] .review-quote__mark { display: none; }
[data-layout="dark"] .review-quote {
  border-left: 1px solid var(--rule);
  padding-left: clamp(20px, 4vw, 52px);
}
[data-layout="dark"] .review-quote__text { margin-top: 0; color: var(--ink); }
[data-layout="dark"] .review-lines { border-top-color: var(--rule); }
[data-layout="dark"] .review-line { border-bottom-color: var(--rule-soft); }
[data-layout="dark"] .review-line__text { color: var(--ink-2); }
[data-layout="dark"] .review__name,
[data-layout="dark"] .review-line__name {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-2);
}
[data-layout="dark"] .review-quote__when,
[data-layout="dark"] .review__when,
[data-layout="dark"] .review-line__when { letter-spacing: .14em; color: var(--ink-3); }
/* The initial in a circle is the loudest object on a card, and there are no
   cards here. */
[data-layout="dark"] .review__avatar { display: none; }
[data-layout="dark"] .reviews { border-top-color: var(--rule); }
[data-layout="dark"] .reviews .review {
  background: none;
  border: 0;
  border-bottom: 1px solid var(--rule-soft);
  border-radius: 0;
}
[data-layout="dark"] .reviews .review__text { color: var(--ink); }
[data-layout="dark"] .reviews .review__author { border-top-color: var(--rule-soft); }

/* ----- the questions and the places ----- */

[data-layout="dark"] .faq--plain { border-bottom-color: var(--rule); }
[data-layout="dark"] .faq__row { border-top-color: var(--rule-soft); }
[data-layout="dark"] .faq__row:first-child { border-top-color: var(--rule); }
[data-layout="dark"] .faq__q {
  font-family: var(--font-heading);
  font-weight: var(--heading-weight);
  font-size: clamp(1.1rem, 2vw, 1.28rem);
}
[data-layout="dark"] .faq__a { color: var(--ink-2); max-width: 62ch; }

/* A rounded outline with a coloured dot inside it, repeated eleven times, is
   the most template-shaped object left on the page. They become what they are:
   a list of place names, ruled. */
[data-layout="dark"] .chip {
  background: none;
  border: 0;
  border-bottom: 1px solid var(--rule-soft);
  border-radius: 0;
  padding: 8px 2px;
  color: var(--ink-2);
}
[data-layout="dark"] .chip::before { display: none; }
[data-layout="dark"] .areas { gap: 6px clamp(22px, 3vw, 40px); }

/* ------------------------------------------------ dark: the photographs --- */

/*
   OUT OF THE COLUMN AND ON TO THE WALL.

   A photograph inside a 1180px measure with twenty pixels of padding either
   side is a photograph in a slot. These are the only wide objects on the site
   and the reason anybody scrolls it, so the wall escapes the column and runs
   to the window at every width. On a phone that means the pictures touch both
   edges of the screen while the type keeps its margin, which is the clearest
   statement this layout can make about which of the two is the subject.

   Nothing rounds, and nothing zooms under the cursor: a print does not move
   when you look at it.
*/
[data-layout="dark"] .gallery,
[data-layout="dark"] .gallery-strip { --bleed: max(20px, calc((100vw - 1180px) / 2 + 20px)); }
[data-layout="dark"] .gallery { margin-inline: calc(-1 * var(--bleed)); }
[data-layout="dark"] .gallery figure { border-radius: 0; }
[data-layout="dark"] .gallery figure:hover img { transform: none; }
[data-layout="dark"] .gallery-hint { color: var(--ink-3); }
[data-layout="dark"] .project__media,
[data-layout="dark"] .project-line__media,
[data-layout="dark"] .about__media img,
[data-layout="dark"] .person__portrait { border-radius: 0; }
[data-layout="dark"] .project__facts { border-top-color: var(--rule); }
[data-layout="dark"] .project__facts > div { border-bottom-color: var(--rule-soft); }
[data-layout="dark"] .project__facts dt { font-size: 11px; letter-spacing: .18em; color: var(--ink-3); }
[data-layout="dark"] .project__body > p,
[data-layout="dark"] .project-line__note,
[data-layout="dark"] .project-row__body { color: var(--ink-2); }
[data-layout="dark"] .project-line,
[data-layout="dark"] .project-row { border-top-color: var(--rule-soft); }

/*
   THE PHOTOGRAPH THAT CARRIES ITS OWN WORDS.

   The overlay about section draws a panel over the picture: a fill, a border
   and a fifty pixel drop shadow. On a near-black page that panel is a
   rectangle one per cent lighter than the wash behind it, which reads as a
   border that failed to load rather than as a raised object, and it is the one
   place on the site where a photograph is deliberately covered up.

   The panel goes and the wash does the work instead, weighted so that the
   ground under the words is the site's own primary for contrast purposes
   wherever the words actually reach. Measured against a fully white
   photograph, the palest thing the fetcher can return: at the right hand edge
   of the text column the composite is 10.8:1 for white type, against the 4.5 a
   paragraph owes a reader.
*/
[data-layout="dark"] .about-overlay__panel {
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0;
  max-width: 34rem;
}
[data-layout="dark"] .about-overlay__wash {
  background:
    linear-gradient(to right, rgb(var(--primary-rgb) / .94) 0%, rgb(var(--primary-rgb) / .82) 52%, rgb(var(--primary-rgb) / .45) 100%),
    linear-gradient(to bottom, rgb(var(--primary-rgb) / .3), rgb(var(--primary-rgb) / .5));
}

/* ------------------------------------------- dark: where and when open --- */

/*
   A PANEL IS A CARD WITH THE WORD CARD TAKEN OUT OF ITS NAME.

   The two contact blocks and the booking form kept a fill, a border and, on
   the form, a sixty pixel drop shadow, on a page where nothing else is drawn
   with an edge. They become columns of a printed sheet: a rule over each, the
   label under it in the same tracked capitals every small label here is set
   in, and nothing else drawn at all.

   Today's row was a filled strip with a pill on it, which is two pieces of
   furniture marking one line on a page that has neither. Weight and full white
   mark it instead.
*/
[data-layout="dark"] .panel,
[data-layout="dark"] .booking__card {
  background: none;
  border: 0;
  border-top: 1px solid var(--rule);
  border-radius: 0;
  padding: clamp(18px, 2.6vw, 26px) 0 0;
  box-shadow: none;
}
[data-layout="dark"] .panel h3 {
  color: var(--ink-3);
  font-weight: 600;
  font-size: 11.5px;
  letter-spacing: .2em;
}
[data-layout="dark"] .contact-line svg { color: var(--ink-3); }
[data-layout="dark"] .contact-line dt { font-size: 11px; letter-spacing: .18em; }
[data-layout="dark"] .contact-status {
  background: none;
  padding: 0;
  border-radius: 0;
  letter-spacing: .1em;
}
[data-layout="dark"] .hours { gap: 0; }
[data-layout="dark"] .hours__row {
  padding: 11px 0;
  border-radius: 0;
  border-bottom: 1px solid var(--rule-soft);
}
[data-layout="dark"] .hours__row.is-today { background: none; }
[data-layout="dark"] .hours__today {
  padding: 0;
  border-radius: 0;
  background: none;
  color: inherit;
  font-weight: 600;
  letter-spacing: .18em;
  opacity: .66;
}
[data-layout="dark"] .map { border-radius: 0; border-color: var(--rule); }

/*
   THE FORM, RULED RATHER THAN BOXED.

   Six filled rectangles stacked down a black page is the heaviest object on
   the site, and the fill they take is --surface, which is 1.12:1 against the
   ground: six boxes with no visible edge, and a focus ring in the raw accent
   painted behind them. Underlined fields are what a form looks like on a
   printed sheet, the rule is --ink-3 at 9.4:1 so the edge of the control is
   the most legible line in the block, and focus moves that rule to the accent
   and doubles its weight rather than casting a halo. The message field keeps a
   full box, because a rule under an eighty pixel empty area says nothing about
   where the area starts.
*/
[data-layout="dark"] .bfield > span {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-3);
}
[data-layout="dark"] .bfield input,
[data-layout="dark"] .bfield select,
[data-layout="dark"] .bfield textarea {
  background: none;
  border: 0;
  border-bottom: 1px solid var(--ink-3);
  border-radius: 0;
  padding: 11px 0;
  color: var(--ink);
}
[data-layout="dark"] .bfield input:focus,
[data-layout="dark"] .bfield select:focus,
[data-layout="dark"] .bfield textarea:focus {
  border-bottom-color: var(--accent-strong);
  box-shadow: 0 1px 0 0 var(--accent-strong);
}
[data-layout="dark"] .bfield textarea {
  border: 1px solid var(--ink-3);
  padding: 11px 12px;
}
[data-layout="dark"] .bfield textarea:focus { border-color: var(--accent-strong); box-shadow: none; }
[data-layout="dark"] .bfield__hint,
[data-layout="dark"] .bform__privacy,
[data-layout="dark"] .booking__note { color: var(--ink-3); }
[data-layout="dark"] .booking__lede { color: var(--ink-2); }

/* --------------------------------------------- dark: how a page closes --- */

/*
   TWO CLOSING BANDS THAT ARE NOT THE SAME BAND TWICE.

   A page ends with either the document's own cta section or the generic
   closer, and both shipped as a heading on the left and a filled button on the
   right, so a reader met the same slab on every page and could not tell which
   of the two they were looking at. The cta band made it worse here by being a
   full bleed field of the raw saturated accent dropped into an otherwise
   monochrome page: the only colour on the site, and an advertisement inserted
   into it rather than a part of it.

   Both are now the page's own black between two rules, which is what every
   other subject on this layout sits on. What separates them is what they are.
   The cta band is a paragraph with a control at the end of it. The closer is
   the last plate on the wall: the ask set larger than any heading on the page
   above it, hard against the foot of the band, with the two actions sitting on
   its last baseline. The accent button is the one coloured object left, and
   the number beside it is an underlined word rather than a second button
   competing with the first.
*/
[data-layout="dark"] .cta-band {
  background: var(--page);
  color: var(--ink);
  border-block: 1px solid var(--rule);
}
[data-layout="dark"] .cta-band p { color: var(--ink-2); opacity: 1; }
[data-layout="dark"] .cta-band .btn--accent {
  --btn-bg: var(--accent);
  --btn-ink: var(--accent-ink);
}
[data-layout="dark"] .cta-band .btn--accent:hover { --btn-bg: var(--accent-deep); filter: none; }

[data-layout="dark"] .closer,
[data-layout="dark"] .section--alt + .closer { background: var(--page); }
[data-layout="dark"] .closer { border-top: 1px solid var(--rule); }
[data-layout="dark"] .closer__inner {
  align-items: flex-end;
  padding-block: clamp(56px, 9vw, 118px);
}
[data-layout="dark"] .closer h2 {
  font-size: clamp(1.9rem, 5.4vw, 3.6rem);
  line-height: 1.04;
  max-width: 15ch;
}
[data-layout="dark"] .closer p { color: var(--ink-2); max-width: 42ch; }
[data-layout="dark"] .closer .status-pill {
  color: var(--ink-3);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
}
[data-layout="dark"] .closer__actions { align-items: center; gap: 10px clamp(20px, 3vw, 34px); }
[data-layout="dark"] .closer__actions .btn--accent {
  min-height: 56px;
  padding: 18px 30px;
  font-size: 13px;
}
[data-layout="dark"] .closer__actions .btn--outline {
  border: 0;
  padding-inline: 2px;
  background: none;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
}
[data-layout="dark"] .closer__actions .btn--outline:hover {
  background: none;
  color: var(--accent-strong);
}

/* -------------------------------------------------- dark: the colophon --- */

/*
   The footer took --deep, which is 1.04:1 against the page, so the closing ask
   and the small print under it were one unbroken black run with a 1.48:1
   hairline somewhere in the middle of it. It takes the page's own black and a
   rule that can be seen, and it stops being a four column directory: the name
   is set as a wordmark at the head of it, the column labels drop to the same
   tracked capitals the rest of the site labels things with, and the week is
   ruled line by line so the times read as a table rather than as a list of
   pairs.
*/
[data-layout="dark"] .site-footer {
  background: var(--page);
  border-top: 1px solid var(--rule);
  padding-top: clamp(46px, 6vw, 78px);
}
[data-layout="dark"] .site-footer__top {
  border-bottom-color: var(--rule-soft);
  padding-bottom: 30px;
}
[data-layout="dark"] .site-footer__name {
  font-size: clamp(19px, 2.2vw, 26px);
  font-weight: var(--heading-weight);
  letter-spacing: .01em;
}
[data-layout="dark"] .site-footer__heading {
  font-size: 10.5px;
  letter-spacing: .22em;
  color: rgb(255 255 255 / .62);
}
[data-layout="dark"] .site-footer__hours > div {
  padding: 6px 0;
  border-bottom: 1px solid var(--rule-soft);
}
[data-layout="dark"] .site-footer__hours > div:last-child { border-bottom: 0; }
[data-layout="dark"] .site-footer__legal { letter-spacing: .1em; }

/* ----------------------------------------------------- dark: the phone --- */

/*
   A FIXED BAR PAINTED IN THE PAGE COLOUR, OVER THE PAGE COLOUR.

   The bar was the primary at 94 per cent over a page that IS the primary, and
   its only separations were a 1.48:1 hairline and a shadow cast in the page
   colour on to the page colour, which is to say none. A layer over a dark page
   cannot be lighter than the page by enough to matter, so what says it is a
   layer is its edge: a bright rule at 9.4:1 with a black shadow under it,
   which is how the bottom of a lit screen actually looks.
*/
[data-layout="dark"] .callbar {
  background: rgb(var(--primary-rgb) / .97);
  border-top: 1px solid var(--ink-3);
  box-shadow: 0 -20px 40px -18px rgb(0 0 0 / .9);
}
[data-layout="dark"] .callbar .btn--outline { border-color: var(--ink-3); }

/* ================================================================ 620px ==== */

@media (max-width: 619.98px) {
  /*
     THE FACTS ROW ON A PHONE.

     The rules between the rating, the opening state and the address are drawn
     by a container query that wants 620px, and a phone never gives it one, so
     on every phone the row fell back to the wrapped three line run of grey
     text those rules were written to abolish. Here it becomes what it should
     have been at that width: a short ruled list, one fact to a line, which is
     also the only shape three facts have ever had room for on a 375px screen.
  */
  .hero--dark .trust {
    display: grid;
    gap: 0;
    padding-top: 0;
    border-top: 0;
  }
  .hero--dark .trust__item {
    padding: 12px 0;
    border-top: 1px solid var(--rule-soft);
  }
  .hero--dark .trust__item:first-child { border-top: 1px solid var(--rule); }
}

/* ================================================================ 860px ==== */

@media (min-width: 860px) {
  /*
     THE SECTION HEAD, ACROSS THE MEASURE.

     Baseline rather than top alignment: the plate number and the first line of
     the standfirst both sit on the heading's first baseline, which is what
     turns three blocks stacked in a column into one line of type with a number
     hung in the margin beside it.
  */
  [data-layout="dark"] .wrap > .section-head {
    grid-template-columns: clamp(60px, 6.5vw, 100px) minmax(0, 1.1fr) minmax(0, .9fr);
    grid-template-areas: 'folio title lede';
    column-gap: clamp(26px, 4vw, 56px);
    align-items: baseline;
  }
  [data-layout="dark"] .wrap > .section-head p:not(.eyebrow) { margin-top: 0; }

  /* The stages take their two columns: the stage on the left, what happens in
     it on the right, which is the shape a programme is set in and the reason
     the numerals are not missed. */
  [data-layout="dark"] .steps .step {
    grid-template-columns: minmax(0, .72fr) minmax(0, 1.28fr);
    column-gap: clamp(26px, 4vw, 64px);
    align-items: baseline;
    padding: clamp(22px, 2.6vw, 30px) 0;
  }

  /* The facts keep the shared count aware grid and only lose their boxes. */
  [data-layout="dark"] .feature { padding: 18px 0 6px; }
}

/* =============================================================== 1080px ==== */

@media (min-width: 1080px) {
  /* Under the plate the page splits: the headline in the wider column, the
     standfirst and the actions in the narrower one beside it, the facts full
     width on a rule under both. At 900px those two columns put a 74px headline
     next to a 44 character paragraph and neither had room, so the split waits
     for a laptop and everything under it meets one column. */
  .hero--dark > .wrap {
    display: grid;
    grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr);
    column-gap: clamp(40px, 5vw, 88px);
    align-items: end;
    padding-top: clamp(34px, 3.4vw, 52px);
  }
  .hero--dark .hero__head { grid-column: 1; }
  .hero--dark .hero__body { grid-column: 2; padding-bottom: .5em; }
  .hero--dark .hero__foot { grid-column: 1 / -1; }
  .hero--dark .hero__sub { max-width: none; }
}

/* ------------------------------------------- dark: the second pass --- */
/*
   Everything below was found by photographing the twenty-four pages this
   layout draws and reading them. It is written after the block above, not
   folded into it, only where source order is doing work; the rest is here
   because it belongs to a subject that block has already closed.
*/

/* THE PAGE TITLE OUTRANKS THE SECTION LABEL.

   On the two pages whose first section starts immediately under the page
   head, the reader met a 76px title and then a 46px heading forty pixels
   later, both flush against the same two column shape, and on those documents
   the two say nearly the same words. The label under a title is a label: it
   comes down two steps so the page has one headline on it and not two. */
[data-layout="dark"] .pagehead + .section .wrap > .section-head h2 {
  font-size: clamp(1.4rem, 2.6vw, 1.85rem);
}

/* THE PLATE NUMBER IS THE ONLY NUMBER IN THE MARGIN.

   The printed index sets an ordinal beside every service, in the same
   position, at nearly the same size, as the plate number the section head
   hangs out there. Two unrelated sequences in one column, both starting at 01
   fifty pixels apart, and a reader cannot tell which is counting what. The
   service ordinal goes, for the same reason the stage numeral went: it is an
   ordinal and the order of the list already tells it. What is left is the
   three column shape, which is what actually distinguishes this variant from
   the schedule beside it. */
[data-layout="dark"] .svc-index__num { display: none; }

/* And with the numeral gone, the name and the description take the tracks it
   was hanging beside. */
[data-layout="dark"] .svc-index__item { grid-template-columns: minmax(0, 1fr); }
[data-layout="dark"] .svc-index__head,
[data-layout="dark"] .svc-index__desc { grid-column: 1; }

/* The right hand column of figures belongs to the two lists that have one.
   The printed index sets its price under the name rather than in a column, so
   a six character minimum and a right edge there pushed the word a document
   writes instead of a number away from the name it belongs to. */
[data-layout="dark"] .svc-index__price {
  min-width: 0;
  text-align: left;
}

/* ONE RULE PER BOUNDARY, NOT TWO. Both price lists already draw a rule over
   their first entry and under their last, so the container rules the block
   above added sat one pixel away from those and the two lists opened on a
   two tone double line. The weight goes on to the rules that exist. */
[data-layout="dark"] .svc-list,
[data-layout="dark"] .svc-index { border-top: 0; }
[data-layout="dark"] .svc-index__item { border-top-color: var(--rule-soft); }
[data-layout="dark"] .svc-list__item:first-child,
[data-layout="dark"] .svc-list:has(> :nth-child(4)) > .svc-list__item:nth-child(2),
[data-layout="dark"] .svc-index__item:first-child { border-top-color: var(--rule); }
[data-layout="dark"] .svc-index__item:last-child { border-bottom-color: var(--rule); }

@media (min-width: 860px) {
  /* The index keeps its two measures, the name and its price on the left and
     the description in a narrow column beside them. It is the shape, not the
     numeral, that told this variant apart from the schedule. */
  [data-layout="dark"] .svc-index__item {
    grid-template-columns: minmax(0, 1fr) minmax(0, 25rem);
    column-gap: clamp(26px, 4vw, 56px);
    align-items: start;
  }
  [data-layout="dark"] .svc-index__head { grid-column: 1; grid-row: 1; }
  [data-layout="dark"] .svc-index__desc { grid-column: 2; grid-row: 1; margin-top: 0; }
}

/* One rule, not two. The line of type that replaced the scoreboard already
   closes itself with a rule across the measure, and the column of reviews
   then drew its own directly under it at half the width. */
[data-layout="dark"] .rating-line + .reviews,
[data-layout="dark"] .rating-line + .review-lines { border-top: 0; }

/* --------------------------------------------------- dark: the booking --- */

/*
   THE SLOT PICKER.

   Two forms reach these pages: the plain enquiry form, which the block above
   rules rather than boxes, and the slot picker, which is a day rail, three
   rows of times and a short form under them. Unstyled here it drew about
   twenty filled rectangles in --card, which is 1.19:1 against the ground: on
   this page that is twenty invisible boxes and then a bright accent one
   wherever the reader has chosen.

   The fill goes and the edge does the work. --rule-edge is white at 42 per
   cent, 4.1:1, which clears the 3:1 a control boundary owes a reader without
   putting twenty 9:1 white rectangles on a black page. The chosen day and the
   chosen time keep the accent: they are the one place on the site where a
   fill is carrying meaning rather than decoration.
*/
body[data-layout="dark"] { --rule-edge: rgb(255 255 255 / .42); }

[data-layout="dark"] .slotbook__field > label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-3);
}
[data-layout="dark"] .slotbook__field input,
[data-layout="dark"] .slotbook__field select {
  background: none;
  border: 0;
  border-bottom: 1px solid var(--ink-3);
  border-radius: 0;
  padding: 11px 0;
}
[data-layout="dark"] .slotbook__field input:focus,
[data-layout="dark"] .slotbook__field select:focus {
  border-bottom-color: var(--accent-strong);
  box-shadow: 0 1px 0 0 var(--accent-strong);
}
/* A rule under an empty eighty pixel area says nothing about where the area
   starts, so the two message fields keep a box. At 4.1:1 it is the edge of a
   control and not a panel. */
[data-layout="dark"] .slotbook__field textarea,
[data-layout="dark"] .bfield textarea {
  background: none;
  border: 1px solid var(--rule-edge);
  border-radius: 0;
  padding: 11px 12px;
}
[data-layout="dark"] .slotbook__field textarea:focus {
  border-color: var(--accent-strong);
  box-shadow: none;
}
[data-layout="dark"] .slotbook__day,
[data-layout="dark"] .slotbook__time span {
  background: none;
  border: 1px solid var(--rule-edge);
  border-radius: 0;
  color: var(--ink);
  font-variant-numeric: tabular-nums lining-nums;
}
[data-layout="dark"] .slotbook__day span { color: var(--ink-3); }
[data-layout="dark"] .slotbook__partname,
[data-layout="dark"] .slotbook__times legend {
  letter-spacing: .18em;
  color: var(--ink-3);
}
[data-layout="dark"] .slotbook__privacy,
[data-layout="dark"] .slotbook__empty { color: var(--ink-3); }

/* ----------------------------------------------- dark: the two floaters --- */

/*
   The assistant's button is the one object on these pages that is still
   shaped like something bought in: a rounded accent pill with a coloured glow
   under it, floating over the bottom right corner of every page. It cannot
   leave, it is the demo's own control, but on this layout it can at least be
   drawn in the same hand as everything else: square, on the page's own black,
   with the edge of a control round it and the accent kept for the icon.
*/
[data-layout="dark"] .chat__fab {
  border-radius: 0;
  background: var(--page);
  color: var(--ink);
  border: 1px solid var(--ink-3);
  box-shadow: 0 18px 40px -20px rgb(0 0 0 / .9);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
}
[data-layout="dark"] .chat__fab svg { color: var(--accent-strong); }

/*
   THE STAGE AND WHAT HAPPENS IN IT, SIDE BY SIDE.

   The template wraps the heading and the body of a step in one div, so with
   the numeral gone the list item has a single child and the two column
   programme above had nothing to put in its second track. The grid moves down
   on to the wrapper, which is where the two things that want columns actually
   are.
*/
[data-layout="dark"] .steps .step > div { display: grid; gap: 8px; }

@media (min-width: 860px) {
  [data-layout="dark"] .steps .step { grid-template-columns: minmax(0, 1fr); }
  [data-layout="dark"] .steps .step > div {
    grid-template-columns: minmax(0, .72fr) minmax(0, 1.28fr);
    column-gap: clamp(26px, 4vw, 64px);
    align-items: baseline;
  }
  [data-layout="dark"] .steps .step h3 { grid-column: 1; }
  [data-layout="dark"] .steps .step p { grid-column: 2; grid-row: 1; }
}

/* ------------------------------------------------ long words in headings --- */
/* Swedish compounds are long and a display heading is where they break the
   page. "Salongen pa Svartbacksgatan" and "Rorfirman pa Kungsbacksvagen" both
   overflowed their column by about 45px at 360, pushed the wrapper out with
   them, and were then cut off by the overflow-x guard on body: nobody got a
   sideways scrollbar and nobody saw the end of the street name either.

   hyphens first, because the pages declare lang="sv" and a browser given a
   language hyphenates at a syllable a reader recognises. overflow-wrap is the
   fallback for the faces and browsers that will not, and breaks anywhere
   rather than not at all. */
h1, h2, h3, h4,
.brand__name,
.hero h1,
.pagehead h1 {
  overflow-wrap: break-word;
  hyphens: auto;
}

/* ========================================================================
   PREVIEW RIBBON AND MARK

   A demo texted to someone and not theirs yet (App\Demos\DemoLifecycle).
   The ribbon is an .example-bar, so the header, the drawer and every hero
   already clear it through --example-bar on all eight layouts; this block
   only says what it looks like and how tall it is.

   The ribbon carries two sentences and shows one: the long one from 561px,
   a short one below that. The mark is a fixed layer of faint diagonal words
   under the header (100), the chat (96) and the call bar (95). It takes no
   clicks and no room, so nothing under it moves or stops working.

   THE BANDS, MEASURED in the browser (natural height of the ribbon with its
   min-height taken off) on Jana Bilverkstad (pro) and one site of every other
   layout, each in its own face, with an end date (the longest sentence):

     720px and up    long form, one line      29.0 needed, 34 declared
     561 to 719px    long form, two lines     46.0 needed, 48 declared
     360 to 560px    short form, one line     27.2 needed, 34 declared
     359px and down  short form, two lines    42.4 needed, 48 declared

   The long form is one line from 700px on every face measured; the band
   starts at 720 for the face nobody has measured yet. 34 is the example
   bar's own one-line number, so a ribbon and an example bar are the same
   object at the same height.
   ======================================================================== */
.preview-bar { gap: 2px 14px; letter-spacing: .005em; }
.preview-bar a { color: inherit; text-underline-offset: 2px; }
.preview-bar__num { font-variant-numeric: tabular-nums; font-weight: 700; }
.preview-bar__dot { opacity: .6; padding: 0 2px; }
.preview-bar__ask { opacity: .92; font-weight: 500; }
.preview-bar__short { display: none; }

body.has-preview { --example-bar: 34px; }
@media (max-width: 719px) {
  body.has-preview { --example-bar: 48px; }
}
@media (max-width: 560px) {
  .preview-bar__long { display: none; }
  .preview-bar__short { display: inline; }
  body.has-preview { --example-bar: 34px; }
}
@media (max-width: 359px) {
  body.has-preview { --example-bar: 48px; }
}

/* The basket and checkout have a sticky header and no hero, so the page
   itself moves down by the ribbon and the header sticks under it. The body
   is the header's sticky container (overflow-x), so its padding already
   clears the ribbon; the example bar's top offset on top of that left a
   34px gap above the header and the header over the first 34px of main. */
body.bookingpage.has-preview { padding-top: var(--example-bar); }
body.bookingpage.has-preview .site-header { top: 0; }

.preview-mark {
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  background-image: var(--preview-ink);
  background-repeat: repeat;
  background-size: 480px 340px;
}
[data-layout="dark"] .preview-mark { background-image: var(--preview-ink-light); }
@media (prefers-contrast: more) {
  .preview-mark { opacity: .5; }
}
@media print {
  .preview-bar,
  .preview-mark { display: none; }
}
