/*
  UCHI
  ====

  The page composition and interaction model follow isu-antwerp.com, carrying
  the UCHI wordmark and its tagline.

  Every value here was measured off the live ISU site (its source HTML, its
  css/style.css, and computed styles read in the browser) on 2026-08-17 —
  none of it is eyeballed:

    header        absolute, top 50px / right 100px, right-aligned. The slot is
                  wider than ISU's 145px because the UCHI lockup carries its
                  rule in the same image, where ISU splits the mark and the
                  tagline into separate elements
    home figure   3:2 rather than ISU's 634/358 - see the note at #home .figure
    nav           absolute, bottom 80px / left 100px, Bebas Neue 22px;
                  li margin-bottom 6px, line-height 20px, float + clear;
                  ::before wipe in #888 driven by data-text, .35s ease-in
    home figure   ~60% of viewport width, vertically centred
    intro         Abel 16px / 20px, width 70%, max-width 640px, centred
    prices box    500px wide, 6px black vertical rule down the centre,
                  .desc 50% right-aligned / .value 50% left-aligned,
                  both Bebas Neue 22px, padding 0 20px, item margin-bottom 5px
    legend        Abel 16px / 19px, offset to calc(50% + 20px)
    contact box   as prices, translateX(40px), .mt rows margin-top 25px,
                  .value span Abel 16px block, padding-top 10px
    mobile        burger 40x24 at left 7.5% / top 76px (3 bars: 50% / 100% / 50%),
                  nav overlay background #888888, ul left 15% centred, li 7vw,
                  boxes 100% wide in normal flow, rule 5px, cells padding 0 10px

  ONE DELIBERATE CORRECTION, verified rather than copied. ISU's stylesheet
  carries `#v-res.mobile … { font-size: 6vw }` and then `6vh` for the price and
  contact cells. No element on the page has id="v-res" — "v-res" is a class on
  <body> — so neither rule ever applies, and the size that actually renders on a
  phone is 22px, confirmed by reading the computed style at a 375px viewport.
  Copying 6vh literally would have set ~50px type inside a ~175px column and
  overflowed every row. This uses the 22px that really renders.

  TWO STRUCTURAL SIMPLIFICATIONS, visually identical but sturdier: vertical
  centring is done with CSS grid rather than ISU's JS-assigned section heights,
  and the legend sits in normal flow rather than absolutely positioned, so it
  can never collide with the nav or overflow the viewport.
*/

/* ------------------------------------------------------------------ fonts */

@font-face {
  font-family: 'Bebas Neue';
  src: url('fonts/bebas-neue-latin.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Abel';
  src: url('fonts/abel-latin.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}

/* ----------------------------------------------------------------- tokens */

:root {
  --paper: #fcfcfc;   /* sampled from ISU's body background */
  --ink: #000;
  --grey: #888;       /* ISU's nav wipe + mobile menu ground */
  --ease1: cubic-bezier(.37, 1.12, .51, .9);
  --ease2: cubic-bezier(.19, 1, .22, 1);

  --display: 'Bebas Neue', 'Arial Narrow', Arial, sans-serif;
  --text: 'Abel', Arial, sans-serif;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--text);
  line-height: 1;
}
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
img { max-width: 100%; height: auto; border: 0; }
a { color: inherit; text-decoration: none; }

:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

.page { position: relative; min-height: 100svh; }

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

.head {
  position: absolute;
  top: 50px;
  right: 100px;
  max-width: 200px;   /* the UCHI lockup is 648x239: four Helvetica Bold
                         capitals over a rule, with "hair is hair" in
                         Helvetica Regular right-aligned under it. At 200px
                         the caps stand about 40px tall, a mark rather than a
                         headline, in ISU's register */
  text-align: right;
  z-index: 900;
}
.head__title { margin: 0; font-size: inherit; font-weight: inherit; line-height: 0; }
.head__mark { display: block; }
.head__mark img { width: 100%; height: auto; display: block; }

/* ------------------------------------------------------------------ main -- */

#main-content {
  position: relative;
  width: 100%;
  min-height: 100svh;
  display: grid;
  place-items: center;
  overflow: hidden;
}
.section { display: none; width: 100%; grid-area: 1 / 1; }
.section.is-active { display: block; }

/* --------------------------------------------------------------- #home ---- */

#home .figure {
  position: relative;
  height: min(66svh, 40rem);
  aspect-ratio: 1440 / 1920;   /* the photograph's own ratio - nothing is cropped */
  width: auto;
  margin: 0 auto;
  overflow: hidden;
}
#home .figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;   /* frame matches the source ratio, so this crops nothing */
  object-position: 50% 50%;
  display: block;
}

/* -------------------------------------------------------------- #intro ---- */

#intro .content {
  width: 70%;
  max-width: 640px;
  margin: 0 auto;
  font-family: var(--text);
  font-size: 16px;
  line-height: 20px;
}
#intro .content p + p { margin-top: 20px; }

/* --------------------------------------------- #prices and #contact boxes -- */

/*
  The signature ISU layout: a 500px column with a 6px black rule straight down
  the middle, labels right-aligned into it and values left-aligned off it.
*/
.box {
  position: relative;
  width: 500px;
  margin: 0 auto;
  padding: 40px 0 30px;
}
.box .rule {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 0;
  width: 6px;
  height: 100%;
  background: var(--ink);
}
.item { width: 100%; margin: 0 0 5px 0; }
.item::after { content: ''; display: block; clear: both; }
.item .desc,
.item .value {
  width: 50%;
  float: left;
  box-sizing: border-box;
  padding: 0 20px;
  font-family: var(--display);
  font-size: 22px;
  line-height: 22px;
}
.item .desc { text-align: right; }
.item .value { text-align: left; }

/*
  Contact values float RIGHT, prices float LEFT. This is not a stylistic whim,
  it is load-bearing, and ISU's stylesheet does exactly the same.

  Several contact rows deliberately carry an empty label — the two address
  lines, the Instagram row — so the value sits alone beside the rule. An empty
  floated <p> has zero height, and a zero-height float reserves no vertical
  band, so a following left-floated value slides right past it to the left edge
  and lands on the WRONG side of the centre rule. Floating the value right pins
  it to the right half whether or not its label has content.
*/
#contact .item .value { float: right; }
.item .value a:hover { text-decoration: underline; }
.item .value span {
  font-family: var(--text);
  display: block;
  padding-top: 10px;
  font-size: 16px;
  line-height: 16px;
}
/* Group separation inside the contact list. */
.item.mt { margin-top: 25px; }

/* ISU keeps this to a single line that runs past the 500px column rather than
   wrapping inside it; the copy is kept short enough that it cannot reach the
   viewport edge even at the 900px breakpoint. */
.legend {
  margin-top: 30px;
  margin-left: calc(50% + 20px);
  font-family: var(--text);
  font-size: 16px;
  line-height: 19px;
  white-space: nowrap;
}

#contact .box { transform: translateX(40px); }

/* -------------------------------------------------------------------- nav -- */

#main-navigation {
  position: absolute;
  bottom: 80px;
  left: 100px;
  z-index: 10;
  font-family: var(--display);
  font-size: 22px;
}
#main-navigation li {
  margin: 0 0 6px 0;
  cursor: pointer;
  position: relative;
  color: var(--ink);
  float: left;
  clear: both;
  line-height: 20px;
  white-space: nowrap;
}
/*
  ISU's nav hover: a grey copy of the label, taken from data-text, wiping in
  from the left over the black original.
*/
#main-navigation li::before {
  content: attr(data-text);
  position: absolute;
  left: 0;
  top: 0;
  color: var(--grey);
  transition: width 0.35s ease-in;
  transform-origin: left center;
  width: 0%;
  overflow: hidden;
  white-space: nowrap;
  pointer-events: none;
}
#main-navigation li:hover::before,
#main-navigation li.selected::before { width: 100%; }

@media (prefers-reduced-motion: reduce) {
  #main-navigation li::before { transition: none; }
}

/* ----------------------------------------------------------------- burger -- */

#ico-nav {
  display: none;
  position: absolute;
  left: 7.5%;
  top: 76px;
  width: 40px;
  height: 24px;
  z-index: 1001;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
#ico-nav span {
  background: var(--ink);
  height: 4px;
  display: block;
  position: absolute;
  transition: all 0.25s ease-in;
}
#ico-nav .ln1 { width: 50%; top: 0; left: 0; }
#ico-nav .ln2 { width: 100%; top: 0; bottom: 0; margin: auto 0; }
#ico-nav .ln3 { width: 50%; bottom: 0; right: 0; }
/* Collapses to an X, as ISU's does. */
#ico-nav.open { width: 24px; }
#ico-nav.open .ln1 { transform-origin: left bottom; transform: rotate(45deg); width: 55%; }
#ico-nav.open .ln2 { transform-origin: center center; transform: rotate(-45deg); }
#ico-nav.open .ln3 { transform-origin: right top; transform: rotate(45deg); width: 55%; left: 9px; }

@media (prefers-reduced-motion: reduce) {
  #ico-nav span { transition: none; }
}

#main-navigation-mobile {
  display: none;
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  background: #888888;
  font-family: var(--display);
  z-index: 1000;
}
#main-navigation-mobile.open { display: block; }
#main-navigation-mobile ul {
  position: absolute;
  left: 15%;
  top: 50%;
  transform: translateY(-50%);
}
#main-navigation-mobile li {
  margin: 0 0 2px 0;
  cursor: pointer;
  position: relative;
  color: var(--ink);
  float: left;
  clear: both;
  font-size: 7vw;
  line-height: 7vw;
}

/* --------------------------------------------------- reservation page ----- */

/*
  The footer is absolutely positioned at the bottom of the page, so the centred
  booking column has to leave room for it. Without this padding the column
  centres against the full viewport and, on a short list, lands on top of the
  address. That is exactly what happened when the price list went from twelve
  rows to eight: nothing overflowed, nothing was clipped, the two simply
  overlapped. verify.mjs now asserts they do not.
*/
.reservation #main-content {
  display: grid;
  place-items: center;
  padding-bottom: 150px;
}
#reservation-box { width: 560px; margin: 0 auto; padding: 40px 0 30px; }
#reservation-box .box { padding-top: 0; }

/* ==========================================================================
   BOOKING
   ==========================================================================

   Built out of the same two pieces the rest of the site is made of: the 500px
   column with the 6px rule down its middle, and Bebas at 22/22. A booking form
   arriving in its own visual language would read as a widget dropped into the
   page, which is exactly what this replaces.
   ========================================================================== */

.step { margin: 0 0 4px; }

/* Steps 3, 4 and 5 stay shut until the step before them is answered. The
   max-height is a ceiling, not a measurement - it only has to exceed the
   tallest the panel can get, and the eased opacity is what the eye actually
   reads, so the height is never seen arriving at a wrong value. */
.step[data-step="3"],
.step[data-step="4"],
.step[data-step="5"] {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  transition: max-height 0.55s var(--ease2),
              opacity 0.40s var(--ease2);
}
.step.is-open {
  max-height: 1600px;
  opacity: 1;
  overflow: visible;
  pointer-events: auto;
}

.step__head {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 10px;
  margin: 40px 0 6px;
  font-family: var(--display);
  font-size: 22px;
  line-height: 22px;
  font-weight: normal;
}
.step__n { color: var(--grey); }
.step__t { letter-spacing: 0.02em; }

.step__hint {
  margin: 14px auto 0;
  max-width: 460px;
  text-align: center;
  font-family: var(--text);
  font-size: 15px;
  line-height: 19px;
  color: var(--grey);
}
.step__hint.legend {
  margin-left: auto;
  white-space: normal;
}

/* ------------------------------------------------------- pickable rows --- */

/*
  A row is a real <button>, so it is tabbable and announces its pressed state.
  The reset has to be thorough: a button brings its own font, padding, border
  and background, any one of which would break the lockup.
*/
.item--pick {
  display: block;
  width: 100%;
  margin: 0 0 5px;
  padding: 3px 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: inherit;
  cursor: pointer;
  position: relative;
  z-index: 1;
  transition: background-color 0.28s var(--ease2);
}
.item--pick .desc,
.item--pick .value { transition: color 0.28s var(--ease2); }
.item--pick:hover:not(.is-off) .desc,
.item--pick:hover:not(.is-off) .value { color: var(--grey); }

/* Chosen: the row inverts and paints over the centre rule, so the selection
   reads as one solid bar rather than two halves that happen to be dark. */
.item--pick.is-picked { background: var(--ink); }
.item--pick.is-picked .desc,
.item--pick.is-picked .value { color: var(--paper); }

/* Excluded by the other axis: Labi with a colour service, or a colour service
   with Labi. Greyed rather than hidden - someone who came in for balayage
   should see that it exists and that it is Donovan's, not be handed a shorter
   list with no explanation. */
.item--pick.is-off { cursor: not-allowed; }
.item--pick.is-off .desc,
.item--pick.is-off .value,
.item--pick.is-off:hover .desc,
.item--pick.is-off:hover .value { color: #c9c9c9; }

/* A running total under the service list, so the cost and the length of the
   visit are visible while services are still being added rather than only at
   the end. Empty until something is chosen, so it reserves no space. */
.step__total {
  margin: 16px auto 0;
  text-align: center;
  font-family: var(--display);
  font-size: 20px;
  line-height: 20px;
}
.step__total:empty { display: none; }

/* ------------------------------------------------------- days and times -- */

.strip, .grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  margin-top: 14px;
}
.chip {
  border: 1px solid var(--ink);
  background: none;
  color: var(--ink);
  font-family: var(--display);
  cursor: pointer;
  padding: 8px 10px;
  line-height: 1;
  transition: background-color 0.28s var(--ease2), color 0.28s var(--ease2);
}
.chip:hover, .chip.is-picked { background: var(--ink); color: var(--paper); }

.chip--day {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 58px;
}
.chip__dow { font-size: 13px; color: var(--grey); transition: color 0.28s var(--ease2); }
.chip--day:hover .chip__dow,
.chip--day.is-picked .chip__dow { color: var(--paper); }
.chip__num { font-size: 24px; }
.chip__mon { font-size: 13px; }
.chip--time { font-size: 18px; min-width: 62px; }

/* -------------------------------------------------------------- details -- */

.bform { max-width: 460px; margin: 18px auto 0; }
.bfield { display: block; margin-bottom: 14px; }
.bfield__l {
  display: block;
  margin-bottom: 5px;
  font-family: var(--display);
  font-size: 16px;
  line-height: 16px;
  color: var(--grey);
}
.bfield input,
.bfield textarea {
  width: 100%;
  padding: 9px 10px;
  border: 1px solid var(--ink);
  border-radius: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--text);
  font-size: 16px;
  line-height: 20px;
  transition: border-color 0.28s var(--ease2);
}
.bfield textarea { resize: vertical; }
.bfield input:focus,
.bfield textarea:focus { outline: none; border-color: var(--grey); }

.bsummary {
  margin: 18px 0 14px;
  padding: 12px 14px;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--text);
  font-size: 15px;
  line-height: 20px;
  text-align: center;
}

.bsubmit {
  display: block;
  width: 100%;
  padding: 12px 26px;
  border: 0;
  border-radius: 0;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--display);
  font-size: 22px;
  line-height: 22px;
  text-align: center;
  cursor: pointer;
  transition: background-color 0.28s var(--ease2);
}
.bsubmit:hover { background: var(--grey); }
.bnote { margin-top: 12px; }

/* The confirmation that replaces the form once the request is composed. */
.bdone { max-width: 460px; margin: 18px auto 0; text-align: center; }
.bdone__h { font-family: var(--display); font-size: 22px; line-height: 22px; margin-bottom: 8px; }
.bdone__p { font-family: var(--text); font-size: 16px; line-height: 20px; margin-bottom: 14px; }
.bdone__pre {
  text-align: left;
  margin: 0 0 16px;
  padding: 14px;
  border: 1px solid var(--ink);
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 18px;
  white-space: pre-wrap;
  word-break: break-word;
}

.reserve-fallback {
  margin: 34px auto 0;
  text-align: center;
  font-family: var(--text);
  font-size: 16px;
  line-height: 19px;
}
.reserve-fallback a { text-decoration: underline; text-underline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .step, .item--pick, .chip, .bsubmit, .bfield input, .bfield textarea,
  .chip__dow, .item--pick .desc, .item--pick .value { transition: none !important; }
}

#main-footer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 40px;
  text-align: center;
  font-family: var(--text);
  font-size: 16px;
  line-height: 20px;
}
#main-footer p + p { margin-top: 4px; }
#main-footer a:hover { text-decoration: underline; }

/* ---------------------------------------------------------------- mobile -- */

@media (max-width: 759px) {
  #ico-nav { display: block; }
  #main-navigation { display: none; }

  /* ISU hides the tagline entirely on mobile — only the mark remains. */
  .head { top: 34px; right: 7.5%; max-width: 40vw; }

  #main-content {
    min-height: 0;
    display: block;
    padding: 150px 0 60px;
  }

  /* Full bleed at the photograph's own 3:4 - no crop on a phone either. */
  #home .figure { width: 100%; height: auto; aspect-ratio: 1440 / 1920; }
  #home .figure img { height: 100%; object-fit: cover; }

  #intro .content { width: 80%; }

  .box {
    width: 100%;
    padding: 20px 0 18px;
    transform: none;
  }
  #contact .box { transform: none; }
  .box .rule { width: 5px; }
  .item .desc, .item .value { padding: 0 10px; }

  .legend {
    width: 80%;
    margin: 20px auto 0;
    text-align: center;
    white-space: normal;   /* ISU releases the nowrap below desktop too */
  }
  /*
    Inside a box with a rule, a centred legend sits directly on the rule, which
    then strikes through the middle of the sentence. Keep it in the value
    column instead, as on desktop, where the rule passes beside it.
  */
  .box .rule ~ .legend {
    width: auto;
    margin: 20px 0 0 calc(50% + 10px);
    padding-right: 10px;
    text-align: left;
  }
  /* The longest value on the site is a 19-character handle. It fits at 390px;
     on the narrowest phones it may break rather than run off the screen. */
  #contact .item .value a { overflow-wrap: anywhere; }

  #reservation-box { width: 100%; padding: 20px 0 18px; }
  .reservation #main-content { display: block; padding: 150px 0 140px; }
  #main-footer { position: static; margin-top: 50px; }

}

/* ==========================================================================
   MOTION
   ==========================================================================

   The reveal is ISU's, mechanism and timing both. Their intro does not fade
   anything in: it lays #fcfcfc covers ("tapa") over the logo and the hero and
   then scales those covers to zero from the right, so the artwork is uncovered
   left to right. Straight from their js/app/Ui.js showHeader():

     .tapa-line   1.15s  scaleX 1 -> 0, origin right, ease2, at t+0
     .tapa-isu    0.85s  scaleX 1 -> 0, origin right, ease2, at t+0.70
     .tapa-trazo  0.85s  scaleX 1 -> 0, origin right, ease2, at t+1.00
     h2 .cov      0.65s  scaleX 1 -> 0, origin right, ease1, at t+1.60

   The UCHI lockup is one image where ISU's is four layered pieces, so the
   covers sit over its three ink regions. Measured off the shipped 648x239
   file by scanning its alpha channel row by row:

     wordmark  y  5.02% - 58.58%,  x  2.62% - 68.06%
     rule      y 65.27% - 71.55%,  x  1.85% - 98.15%
     tagline   y 79.92% - 94.98%,  x 64.51% - 98.15%

   The covers below are set slightly outside those bounds so no hairline of
   ink is left showing at the start of the wipe. Three beats rather than ISU's
   four: rule, wordmark, tagline.
========================================================================== */

.tapa {
  position: absolute;
  background: var(--paper);
  transform: scaleX(1);
  transform-origin: right center;
  pointer-events: none;
  z-index: 5;
}
.head__mark { position: relative; }

/* Measured regions of the 648x239 lockup, as percentages. Each seam sits in
   the clear gap between two bands. */
.tapa--word { left: 0;   top: 1%;  width: 72%;  height: 61%; }
.tapa--line { left: 0;   top: 62%; width: 101%; height: 13%; }
.tapa--tag  { left: 62%; top: 75%; width: 39%;  height: 24%; }

/* The hero carries one cover, as ISU's #home figure .tapa does. */
#home .figure .tapa { left: 0; top: 0; width: 101%; height: 101%; }

/* Nothing is uncovered until the script says so, but only when the script is
   actually running - no JS means no covers, so the page is simply there. */
.js .tapa { transition: transform 1.15s var(--ease2); }
.js .is-revealed .tapa,
.js .tapa.is-revealed { transform: scaleX(0); }

/* ISU's own numbers: the rule draws first and longest, the wordmark follows
   it out, and the tagline closes on ISU's h2 beat (0.65s, ease1). */
.js .head .tapa--line { transition-duration: 1.15s; transition-delay: 0s; }
.js .head .tapa--word { transition-duration: 0.85s; transition-delay: 0.70s;
                        transition-timing-function: var(--ease1); }
.js .head .tapa--tag  { transition-duration: 0.65s; transition-delay: 1.00s;
                        transition-timing-function: var(--ease1); }
#home .figure .tapa    { transition-duration: 1.15s; transition-delay: 0.35s; }

/* The nav arrives last, on ease1 like ISU's final beat. */
.js #main-navigation { opacity: 0; transform: translateY(6px); }
.js #main-navigation {
  transition: opacity 0.65s var(--ease1) 1.25s, transform 0.65s var(--ease1) 1.25s;
}
.js .is-revealed #main-navigation { opacity: 1; transform: none; }

/* --------------------------------------------------------- the curtain --- */

/*
   ISU's page transition, from Ui.js showPreload():
     .bck   0.85s scaleX 0 -> 1, origin left   (sweeps in)
     wrap   0.65s scaleX 1 -> 0, origin right, at +0.90  (sweeps away)

   Kept for the first paint. For a nav click the same move runs compressed, so
   it reads as the reference site's transition without making the visitor wait
   1.5s for a section that is already in the document.
*/
#curtain {
  position: fixed;
  inset: 0;
  z-index: 2000;
  pointer-events: none;
  transform: scaleX(1);
  transform-origin: right center;
}
#curtain .bck {
  position: absolute;
  inset: 0;
  background: var(--paper);
  transform: scaleX(0);
  transform-origin: left center;
}
#curtain.sweep-in .bck {
  transform: scaleX(1);
  transition: transform 0.32s var(--ease2);
}
#curtain.sweep-out {
  transform: scaleX(0);
  transition: transform 0.36s cubic-bezier(.25, .46, .45, .94);
}
#curtain.idle { display: none; }

/* ------------------------------------------------------- motion blur ----- */

/*
   ISU's stylesheet carries `#page { transition: all 600ms ease-in }` with
   `#page.blured { filter: blur(20px) }`. 20px is a full defocus; this uses a
   much smaller value so it reads as motion on the swap rather than as a
   focus-pull, and it is only ever on for the length of the transition.
*/
.js #main-content { transition: filter 0.3s var(--ease2), opacity 0.3s var(--ease2); }
.js #main-content.is-shifting { filter: blur(5px); opacity: 0; }

/* ------------------------------------------------------------- grain ----- */

/*
   A little tooth on the hero so a flat greyscale photograph does not read as
   plastic on a bright screen. feTurbulence rendered once into a data URI,
   tiled at a fixed pixel size so it never scales with zoom or DPR, and kept
   under the image's own contrast at 4%.
*/
#home .figure::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: 0.055;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
}

/* ------------------------------------------------- reduced motion -------- */

/*
   Everything above is decoration over content that is already in the document,
   so switching it off leaves a complete page rather than a broken one.
*/
@media (prefers-reduced-motion: reduce) {
  .js .tapa,
  .js #main-navigation,
  .js #main-content,
  #curtain,
  #curtain .bck { transition: none !important; }
  .js .tapa { transform: scaleX(0); }
  .js #main-navigation { opacity: 1; transform: none; }
  .js #main-content.is-shifting { filter: none; opacity: 1; }
  #curtain { display: none; }
}

}
