/* ============================================================== tokens ===
   Palette, fonts and sizes are the site's own, read off the builder theme:
   Cormorant Garamond / Montserrat, deep green + cream + copper accent.
   ======================================================================== */

:root {
  --green-900: #063831;   /* rgb(6,56,49)     primary dark   */
  --olive-600: #5c6756;   /* rgb(92,103,86)                  */
  --sage-300:  #c7cec9;   /* rgb(199,206,201)                */
  --sage-200:  #dbe2dd;   /* rgb(219,226,221)                */
  --cream-100: #f8f4e6;   /* rgb(248,244,230)                */
  --stone-100: #ebe9e2;   /* rgb(235,233,226)                */
  --slate-500: #6d7d8b;   /* rgb(109,125,139)                */
  --teal-200:  #a3d2d5;   /* rgb(163,210,213)                */
  --copper-500:#b5764d;   /* rgb(181,118,77)  nav + accent   */
  --copper-200:#f4d1b3;   /* rgb(244,209,179) hover          */
  --white: #fff;
  --ink: #1c1c1c;

  --font-display: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --font-body: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;

  /* scale from the sizes actually rendered on the old site:
     85/64 hero, 48 section, 40 sub, 24/20 label, 16 body */
  --fs-body: 1rem;
  --fs-small: 0.875rem;

  --measure: 68ch;
  --max-w: 1224px;        /* the builder's own content width */
  --header-h: 83px;       /* the builder's nav height; 141px from 760px up */

  --bg: var(--cream-100);
  --fg: var(--ink);
  --muted: color-mix(in srgb, var(--fg) 68%, transparent);
  --accent: var(--copper-500);
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-underline-offset: .2em; text-decoration-thickness: 1px; }
a:hover { color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--green-900); color: var(--white); padding: .75rem 1rem;
}
.skip-link:focus { left: 0; }

/* ============================================================= sections === */

.section {
  background: var(--bg);
  color: var(--fg);
  position: relative;
  display: grid;
  align-content: start;
}
@media (min-width: 760px) {
  /* the block's own min-height, and the offset the first element sat at */
  .section { min-height: var(--min-h, 0); }
  .section__inner > * { margin-top: var(--y, 0); }
}

.section--image { background-size: cover; background-position: center; }
/* tinted only where the builder set an overlay — site-wide that is 0 or 0.14 */
.section--image::before {
  content: ''; position: absolute; inset: 0;
  background: rgba(0, 0, 0, var(--overlay, 0));
  pointer-events: none;
}

/* Each block carries its own width and padding. Desktop padding is
   horizontally zero site-wide — which is why images sit flush to the page
   edge on the original — with 16px side padding on mobile. */
.section__inner {
  position: relative;
  width: 100%;
  max-width: var(--content-w, var(--max-w));
  margin-inline: auto;
  padding: var(--pad-m, 80px 16px);
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.75rem);
}
@media (min-width: 760px) {
  .section__inner { padding: var(--pad, 16px 0); }
  /* The form block was authored with no bottom padding at all — the builder's
     recorded height was enough to clear the submit button. At our type the
     form grows past that height, so the button ended flush against the next
     section. Sit the space under the form itself, which adds to whatever
     padding the section already has instead of replacing it. */
  .form { padding-bottom: 56px; }
}

/* dark sections flip the foreground */
.section--dark { --fg: var(--cream-100); --muted: color-mix(in srgb, var(--cream-100) 75%, transparent); }
.section--dark a:hover { color: var(--copper-200); }

/* ------------------------------------------------- reconstructed layout --
   `stack` = elements that sat above one another, `columns` = elements that
   sat side by side, `place` = an element's own indent and width within its
   parent, kept proportional. All collapse to one column on narrow screens. */

/* The three-up service block (home). The builder reserved 173px of box for a
   one-line heading, which opened a hole above the round images, and its 16px
   bottom padding left the buttons sitting on the next section. Both are set
   here rather than in the generator: the recorded geometry is still correct
   for every other block, this one row just reads badly at our type size. */
.section:has(.columns--grouped) .stack > .place:first-child { min-height: 0; }
.section:has(.columns--grouped) .stack > .place:first-child + .place { margin-top: 56px; }
.section:has(.columns--grouped) { padding-bottom: 40px; }   /* +16px from the button row's own margin */

/* Centre image, copy and button on their own column. The builder's recorded
   offsets already put the image and the copy in the middle, but it sized the
   button's box to the wrapped two-line label (130px); at one line the label is
   180px and spilled out to the right, so that box is given the full column. */
.section:has(.columns--grouped) .col > .place { margin-inline: auto; }
.section:has(.columns--grouped) .col > .place:has(.actions) { width: 100%; }

/* Custom properties inherit, so a nested wrapper carrying none of its own
   would silently pick up an ancestor's — which pushed the footer badges 85px
   right and shrank them. Every layout variable is reset on the element that
   consumes it, so an inline value only ever applies to the element it is on. */
.place { --x: 0%; --w: 100%; --sg: 0px; --sh: 0px; }
.col { --yo: 0px; --gcm: auto; }
.columns { --rows: 1; }

.stack { display: grid; gap: clamp(1rem, 2vw, 1.75rem); align-content: start; }
.columns { display: grid; gap: clamp(1.25rem, 3vw, 2.75rem); align-items: start; }

/* grid items default to min-width:auto and refuse to shrink below their
   content, which pushes nested rows a few pixels wider than the space they
   were given; every item here is allowed to shrink to its track instead */
.stack > *, .columns > *, .place > * { min-width: 0; }

@media (min-width: 760px) {
  /* tracks include the original's empty space, so each child keeps the width
     and the position it had rather than stretching to fill a share of the row */
  .columns { grid-template-columns: var(--cols, 1fr); column-gap: 0; }
  .columns > .col {
    grid-column: var(--gc, auto); grid-row: 1; min-width: 0;
    margin-top: var(--yo, 0);   /* each column's own start height */
  }
  /* Stacked items are spaced by the gap the builder left above each one
     (--sg), not by a single CSS gap, so the copy sits where it did. Mobile
     keeps the uniform rhythm below. */
  .stack { gap: 0; }
  .place {
    margin-inline-start: var(--x, 0);
    width: var(--w, 100%);
    margin-top: var(--sg, 0);
    min-height: var(--sh, 0);   /* the room the builder gave it, as a floor */
  }

  /* A three-up block was authored as separate rows of images, captions and
     buttons. We regroup it per column so a phone reads image-then-its-caption;
     subgrid then puts the rows back in line across the columns here, so the
     captions and buttons still align as they did originally. */
  .columns--grouped > .col {
    grid-row: span var(--rows, 1);
    display: grid;
    grid-template-rows: subgrid;
    align-content: start;
  }
}

/* Without subgrid the columns still group correctly, they just size their own
   rows — worth having rather than falling back to the interleaved order. */
@supports not (grid-template-rows: subgrid) {
  @media (min-width: 760px) {
    .columns--grouped > .col { display: grid; gap: clamp(1rem, 2vw, 1.75rem); }
  }
}

/* ------------------------------------------------------------- collage --
   A few sections were composed by hand out of overlapping pieces: coloured
   cards behind text, images running underneath them. Rows and columns cannot
   describe that, so those sections keep their original coordinates.

   Every offset is a fraction of the container width in `cqw`, so the whole
   arrangement — type included — scales with the column rather than being
   pinned to 1224px. Below the layout breakpoint it falls back to a stack. */

.collage {
  position: relative;
  width: 100%;
  container-type: inline-size;
}

@media (min-width: 900px) {
  .collage {
    /* aspect-ratio, not min-height: the ratio is unitless, whereas a cqw
       length set on .collage itself would resolve against the viewport rather
       than the collage — the same trap as the type sizing below. */
    aspect-ratio: var(--cw) / var(--ch);
    /* Declared here, used only by the children. An element that establishes a
       container cannot resolve its own container's units, so `cqw` in a
       property set on .collage itself would fall back to the viewport — which
       made the type 1600/1224 too large and pushed it out of the cards. */
    --u: calc(100cqw / var(--cw));
  }
  .collage__item {
    position: absolute;
    left: calc(var(--l) * var(--u));
    top: calc(var(--t) * var(--u));
    width: calc(var(--w) * var(--u));
    height: calc(var(--h) * var(--u));
    font-size: calc(16 * var(--u));
    line-height: 1.5;
  }
  /* A row of backdrop cards. They sit at the builder's coordinates but take
     their height from their content, and the grid stretches them to a common
     height — the recorded heights left a lot of empty card, and more once our
     text sets shorter than the builder's. */
  .collage__cards {
    position: absolute;
    left: calc(var(--l) * var(--u));
    top: calc(var(--t) * var(--u));
    width: calc(var(--w) * var(--u));
    display: grid;
    grid-template-columns: var(--cols, 1fr);
    align-items: stretch;
    column-gap: 0;
  }
  /* A collage holding a self-sizing card row takes its height from that row
     in normal flow, so it must not also be pinned to a ratio. */
  .collage--fluid { aspect-ratio: auto; }

  /* the one row that sizes to its content sits in normal flow, so the
     section ends where the cards end instead of at the recorded height */
  .collage__cards--flow {
    /* relative, not static: the row still lays out in normal flow, but a
       static element ignores z-index and the absolutely positioned photos
       above it would paint over the cards that are meant to overlap them.
       left/top come from .collage__cards and must be cancelled, or the
       margins would offset the row a second time. */
    position: relative;
    left: auto;
    top: auto;
    margin-left: calc(var(--l) * var(--u));
    margin-top: calc(var(--t) * var(--u));
  }
  .collage__card {
    grid-column: var(--gc, auto);
    grid-row: 1;
    min-width: 0;
    min-height: calc(var(--minh, 0) * var(--u));
    background: var(--card-bg, transparent);
    padding: calc(var(--pt, 0) * var(--u)) calc(var(--pr, 0) * var(--u))
             calc(var(--pt, 0) * var(--u)) calc(var(--pl, 0) * var(--u));
    font-size: calc(16 * var(--u));
    line-height: 1.5;
  }

  /* Images and cards keep the exact box they were drawn in. Text only takes
     it as a floor: our font metrics are not the builder's, so a caption can
     need a few pixels more than the height it recorded, and clipping it would
     lose a line. */
  .collage__item--text {
    height: auto;
    min-height: calc(var(--h) * var(--u));
  }

  /* type scales with the collage instead of the page */
  .collage :where(p, li) { font-size: 1em; max-width: none; }
  /* inside a collage the recorded size is relative to the collage's own
     16px unit, so it scales with the container rather than the viewport */
  .collage :where(h1, h2, h3, h4) { font-size: calc(var(--fs) / 16 * 1em); }
  .collage .prose { gap: 0.75em; }
  .collage .prose ul { padding-left: 1.1em; gap: 0.35em; max-width: none; }
  .collage .figure, .collage .figure img { height: 100%; }
  .collage .figure img { object-fit: cover; }
}

/* narrow screens: plain stack, in the order the pieces were written */
@media (max-width: 899px) {
  .collage {
    container-type: normal;
    display: grid;
    gap: clamp(1rem, 3vw, 1.75rem);
  }
  .collage__item { position: static; }
  /* loose backdrops have nothing on them once the text is in normal flow */
  .collage__item--shape { display: none; }
  /* cards keep their background here, because they hold their own text */
  .collage__cards {
    position: static;
    display: grid;
    gap: clamp(1rem, 3vw, 1.75rem);
  }
  .collage__card { background: var(--card-bg, transparent); padding: 1.25rem; }
}

.shape { width: 100%; height: 100%; }

/* Rows the builder also keeps side by side on a narrow screen — the ICF
   badges in the footer. Without this they collapse one per row and a 90px
   badge stretches to the full width of the page. */
@media (max-width: 759px) {
  .columns--row-on-mobile {
    grid-template-columns: var(--cols-m, 1fr);
    column-gap: 0;
    align-items: center;
  }
  .columns--row-on-mobile > .col { grid-column: var(--gcm, auto); grid-row: 1; min-width: 0; }
}

/* =========================================================== typography === */

/* Leading is the builder's: 1.3 at every size it uses, with the single 72px
   display heading tightened to 1.2. That ratio is not in the decoded model, so
   build.py carries the exception as an inline --lh; the reset here keeps a
   nested heading from inheriting its ancestor's value. */
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  --lh: 1.3;
  line-height: var(--lh);
  margin: 0;
  text-wrap: balance;
}
/* Every heading carries the size the builder recorded for it, as a unitless
   px number in --fs. That number is for the 1224px canvas inside a 1440px
   window, so it scales with the viewport below that, caps at the recorded
   value above it, and never falls below 60% of it on a phone. The per-level
   values here are only the fallback for a heading with nothing recorded —
   an inline --fs always wins. */
h1 { --fs: 64; }
h2 { --fs: 48; }
h3 { --fs: 40; }
h4 { --fs: 24; }
.hero h1 { --fs: 76; }
:where(h1, h2, h3, h4) {
  font-size: clamp(min(max(1.25rem, calc(var(--fs) * 0.6px)), 10vw),
                   calc(var(--fs) * 100vw / 1440),
                   calc(var(--fs) * 1px));
}
h4 {
  margin: 0; line-height: 1.3;
  font-family: var(--font-body); font-weight: 600;
}

p { margin: 0; max-width: var(--measure); text-wrap: pretty; }

.eyebrow {
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0;
}
.section--dark .eyebrow { color: var(--copper-200); }

.prose { display: grid; gap: 1rem; }

/* the builder stores alignment per element; centred blocks also centre their
   measure-limited paragraphs rather than leaving them ragged to the left */
.prose.center { text-align: center; justify-items: center; }
.prose.center p, .prose.center ul { margin-inline: auto; }
.actions.center { text-align: center; }
.actions { max-width: none; }
.prose ul { margin: 0; padding-left: 1.25rem; display: grid; gap: .5rem; max-width: var(--measure); }
.prose strong { font-weight: 600; }

/* ============================================================== pieces === */

.figure { margin: 0; }
/* The builder crops each image to a fixed box; --ar is that box's ratio and
   --op the focal point it cropped around, so size and framing match. */
.figure img {
  width: 100%;
  aspect-ratio: var(--ar, auto);
  object-fit: cover;
  object-position: var(--op, 50% 50%);
  border-radius: var(--radius, 0);
}

/* Some images are cut to a shape with an inline SVG mask rather than a border
   radius — the circular service thumbnails, for one. */
.figure--masked img {
  -webkit-mask-image: var(--mask);
          mask-image: var(--mask);
  -webkit-mask-size: contain;
          mask-size: contain;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-position: center;
}

/* Colours and radius come from the button itself where the builder set them
   (the service buttons are dark-green pills); these are the fallbacks. */
.button {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;          /* "Read more" was setting as two lines */
  padding: .9rem 2.5rem;
  background: var(--btn-bg, var(--green-900));
  color: var(--btn-fg, var(--cream-100));
  border: var(--btn-border-width, 1px) solid var(--btn-border-color, var(--btn-bg, var(--green-900)));
  border-radius: var(--btn-radius, 0);
  text-decoration: none;
  cursor: pointer;
  transition: background .18s ease, color .18s ease, border-color .18s ease;
}
.button:hover {
  background: var(--btn-bg-hover, transparent);
  color: var(--btn-fg-hover, var(--btn-bg, var(--green-900)));
  border-color: var(--btn-border-color, var(--btn-bg, var(--green-900)));
}
.section--dark .button {
  background: var(--btn-bg, var(--copper-500));
  border-color: var(--btn-border-color, var(--btn-bg, var(--copper-500)));
  color: var(--btn-fg, var(--white));
}
.section--dark .button:hover {
  background: var(--btn-bg-hover, transparent);
  color: var(--btn-fg-hover, var(--copper-200));
}

.gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; }

/* The zcal booking widget carries its own inline min-width:320px. Between the
   layout breakpoint and about 1024px its column is narrower than that, so it
   pushed the page sideways. Stack that row early instead, which also gives the
   calendar the full width rather than a cramped scrolling box. */
@media (max-width: 1023px) {
  .columns:has(.booking) { grid-template-columns: 1fr; }
  .columns:has(.booking) > .col { grid-column: 1; grid-row: auto; }
}
/* fallback where :has() is unavailable — contain it rather than move the page */
.booking { max-width: 100%; overflow-x: auto; }
/* Below 360px even the 16px gutter is more than the widget's own 320px floor
   can spare, so give it the full screen rather than a clipped box the visitor
   has to drag sideways. */
@media (max-width: 359px) {
  .section__inner:has(.booking) { padding-left: 0; padding-right: 0; }
}
.embed iframe { width: 100%; border: 0; }

/* ================================================================ form === */

.form { display: grid; gap: 1.1rem; max-width: 620px; }
.field { display: grid; gap: .4rem; }
.field label { font-size: var(--fs-small); font-weight: 600; letter-spacing: .04em; }
.field .req { color: var(--accent); }
.field input, .field textarea {
  font: inherit; font-size: var(--fs-body);
  padding: .8rem .9rem;
  border: 1px solid color-mix(in srgb, var(--fg) 28%, transparent);
  background: var(--white); color: var(--ink);
  border-radius: 2px;
}
.field textarea { min-height: 9rem; resize: vertical; }
.form__note { font-size: var(--fs-small); color: var(--muted); max-width: var(--measure); }

/* The inline answer after submitting. Only ever shown by /form.js; without
   JavaScript the form navigates to send.php's own confirmation page instead.
   Guarded on :not([hidden]) so the hidden attribute keeps working. */
.form__result:not([hidden]) {
  display: grid;
  gap: .4rem;
  padding: 1rem 1.1rem;
  border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--fg) 6%, transparent);
  font-size: var(--fs-small);
  max-width: var(--measure);
}
.form__result strong { font-family: var(--font-display); font-size: 1.25rem; font-weight: 400; }
.form__result ul { margin: 0; padding-left: 1.1rem; display: grid; gap: .25rem; }
.form__result--ok { border-left-color: var(--olive-600); }
.form__result--error { border-left-color: var(--copper-500); }
.section--dark .form__result:not([hidden]) {
  background: color-mix(in srgb, var(--cream-100) 10%, transparent);
}

/* Spam trap. Positioned off-screen rather than display:none — some bots skip
   fields they can tell are hidden, and this one is meant to be filled in. */
.hp {
  position: absolute; left: -9999px; top: auto;
  width: 1px; height: 1px; overflow: hidden;
}

/* ============================================================== chrome === */
/* Header height and logo size come from the builder's nav block:
   desktop 141 / logo 73, mobile 83 / logo 35, logo aspect ratio 2. */

.masthead {
  background: var(--green-900); color: var(--cream-100);
  position: sticky; top: 0; z-index: 40;
}
.masthead__inner {
  max-width: var(--max-w); margin-inline: auto;
  padding-inline: 16px;
  min-height: var(--header-h);
  display: flex; align-items: center; gap: 1rem; flex-wrap: nowrap;
}
.masthead__logo img { height: 35px; width: auto; }
@media (min-width: 760px) {
  :root { --header-h: 141px; }
  .masthead__inner { gap: 1.5rem; }
  .masthead__logo img { height: 73px; }
}

/* The builder records this header as transparent (`isTransparent: true`): it
   sits *over* the first section rather than above it, and the brand green
   fades in once the page scrolls. Only a page whose hero is a full-bleed image
   can carry that — over a cream section the copper links would disappear — so
   build.py emits `masthead--overlay` and `hero--flush` together or not at all.

   The fill is a pseudo-element rather than a background on .masthead itself:
   fading opacity gives the exact green at every frame, where interpolating
   background-color from `transparent` is a colour animation that has no reason
   to be one. Timing is the builder's own, 0.3s ease-in-out. */
.masthead--overlay { background: transparent; }
.masthead--overlay::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--green-900);
  opacity: 0; transition: opacity .3s ease-in-out;
}
.masthead--overlay.is-filled::before { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .masthead--overlay::before { transition: none; }
}

/* The hero runs up behind the transparent header. This is the builder's rule:
   a padding-top of one header height, cancelled by an equal negative margin,
   so the photograph starts at the top of the page while the copy stays exactly
   where it was. The recorded --min-h measures the area *below* the header, and
   box-sizing is border-box site-wide, so the header height is added back to it
   rather than eaten out of it. */
.section.hero--flush {
  margin-top: calc(-1 * var(--header-h));
  padding-top: var(--header-h);
}
@media (min-width: 760px) {
  .section.hero--flush { min-height: calc(var(--min-h, 0px) + var(--header-h)); }
}

.menu { margin-left: auto; }
.nav ul { list-style: none; display: flex; flex-wrap: wrap; gap: clamp(.9rem, 1.8vw, 1.75rem); margin: 0; padding: 0; }
.nav a {
  font-size: var(--fs-small); letter-spacing: .06em; text-transform: uppercase;
  color: var(--copper-500); text-decoration: none; white-space: nowrap;
}
.nav a:hover, .nav a[aria-current='page'] { color: var(--copper-200); }
.nav a[aria-current='page'] { text-decoration: underline; }

/* On desktop the menu is simply the row of links: the <details> wrapper shows
   its content and the hamburger is not needed. */
@media (min-width: 760px) {
  .menu > summary { display: none; }
}

/* Below that the links move behind a hamburger, so the bar stays the 83px
   the builder used, instead of growing to three wrapped rows. */
@media (max-width: 759px) {
  .menu > summary {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px;
    color: var(--copper-500);
    cursor: pointer;
    list-style: none;
    border: 1px solid transparent; border-radius: 2px;
  }
  .menu > summary::-webkit-details-marker { display: none; }
  .menu > summary::marker { content: ""; }
  .menu > summary:hover { color: var(--copper-200); }
  .menu[open] > summary { color: var(--cream-100); border-color: color-mix(in srgb, var(--copper-500) 45%, transparent); }

  .burger { width: 22px; height: 15px; }
  .burger--close { display: none; }
  .menu[open] .burger { display: none; }
  .menu[open] .burger--close { display: block; }

  /* the panel is absolute so opening it never resizes the bar */
  .menu > .nav {
    position: absolute; left: 0; right: 0; top: 100%;
    z-index: 40;
    background: var(--green-900);
    border-top: 1px solid color-mix(in srgb, var(--copper-500) 30%, transparent);
    padding: .5rem 16px 1rem;
  }
  .menu > .nav ul { flex-direction: column; gap: 0; }
  .menu > .nav a { display: block; padding: .85rem .25rem; font-size: 1rem; }
  .menu > .nav li + li { border-top: 1px solid color-mix(in srgb, var(--cream-100) 10%, transparent); }
}

/* Language switcher: the current language is shown, the other appears on
   click. Built on <details>/<summary> so it opens and closes, and is keyboard
   operable, with no JavaScript — the script in the header only adds the
   niceties (Escape, clicking away). */
.langswitch { position: relative; font-size: var(--fs-small); }

.langswitch > summary {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .3rem .45rem;
  color: var(--copper-500);
  letter-spacing: .06em;
  cursor: pointer;
  border: 1px solid transparent;
  border-radius: 2px;
  list-style: none;            /* hide the default disclosure triangle */
}
.langswitch > summary::-webkit-details-marker { display: none; }
.langswitch > summary::marker { content: ""; }
.langswitch > summary:hover { color: var(--copper-200); }
.langswitch[open] > summary {
  color: var(--cream-100);
  border-color: color-mix(in srgb, var(--copper-500) 45%, transparent);
}

.langswitch .flag { width: 20px; height: 15px; display: block; border-radius: 1px; }
.langswitch .chevron { width: 9px; height: 9px; transition: transform .18s ease; }
.langswitch[open] .chevron { transform: rotate(180deg); }

.langswitch__menu {
  position: absolute;
  right: 0;
  top: calc(100% + .3rem);
  z-index: 30;
  min-width: 100%;
  padding: .2rem;
  background: var(--green-900);
  border: 1px solid color-mix(in srgb, var(--copper-500) 45%, transparent);
  border-radius: 2px;
}
.langswitch__menu a {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem .45rem;
  color: var(--copper-500);
  text-decoration: none;
  letter-spacing: .06em;
  white-space: nowrap;
}
.langswitch__menu a:hover {
  color: var(--copper-200);
  background: color-mix(in srgb, var(--cream-100) 10%, transparent);
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

.footer { background: var(--green-900); color: var(--cream-100); padding-block: clamp(2.5rem, 5vw, 4rem); }
.footer__inner {
  max-width: var(--max-w); margin-inline: auto; padding-inline: 16px;
  display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
}
.footer a { color: var(--copper-200); }
/* The address must be allowed to break: nowrap made it wider than its footer
   column between 760 and ~900px, which pushed every page sideways. */
.email { overflow-wrap: anywhere; }
.footer p { font-size: var(--fs-small); }
