/* ==========================================================================
   M07 CAPITAL

   Cream white, night blue, one elegant serif. No photography, no icons, no
   cards, no shadows, no gradients. The whitespace is the design - the brief
   is explicit that empty space is not a problem to be solved.

   Everything that moves here moves slowly and only once. The house style is
   a mask that lifts rather than an element that flies in: the type is
   already in place and the page simply uncovers it. That reads as
   composure. Anything faster than about 700ms reads as a website trying to
   impress you, which is the one thing this client is not.
   ========================================================================== */

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

:root {
  /* The brief allows exactly two colours. Every line, every quiet label and
     every hover state below is one of these two - the faint rules are night
     blue at low alpha, not a third invented grey. That is what keeps a
     two-colour palette from quietly becoming a five-colour one. */
  --paper:      #ede6d8;   /* cream white                                  */
  --ink:        #0b1d33;   /* night blue          13.7:1 on cream          */

  /* "Optional fuer sekundaeren Text ein leicht abgeschwaechtes Nachtblau."
     Both are the same hue lightened, and both are explicit colours rather
     than opacity: 55% of --ink on cream measures 4.17:1, just under AA, and
     the eye cannot see the difference between that and a pass. */
  --ink-body:   #33485e;   /* body copy            7.6:1 on cream          */
  /* Solved against the darkest ground it ever sits on - a sector hover wash,
     not bare cream - so it clears AA everywhere rather than only where it
     was eyeballed. On plain paper it has 5.7:1, which is headroom, not
     waste. */
  --ink-quiet:  #475b6f;   /* meta, labels, legal  4.8:1 worst case        */

  --rule:        rgba(11, 29, 51, 0.16);  /* the hairline divider          */
  --rule-strong: rgba(11, 29, 51, 0.30);  /* where one needs to be seen    */

  /* One colour per business, and that is the whole of the colour system.
     They are not decoration: each identifies a sector, so the same colour
     always means the same thing and a page can be read by hue before it is
     read by word. Night blue stays the voice of the holding itself - every
     heading, every name and every body paragraph is still --ink.

     Each is tuned to 4.9-5.7:1 on cream, a deliberately tight band. They
     carry small uppercase labels, so they all have to clear AA, and one much
     darker than the rest would read as more important rather than as merely
     different. */
  --hospitality: #91452c;   /* terracotta */
  --technology:  #186360;   /* teal       */
  --mobility:    #795510;   /* sun gold   */
  --realestate:  #53612e;   /* olive      */
  --investments: #864860;   /* plum       */

  /* How strongly a sector colour tints a panel. One number, so every band on
     the site carries the same weight of colour and no single sector can end
     up shouting louder than the others.

     Raising it is not free. A sector label sits on its own tint and the row
     wash is this plus a half again, so the accents were solved against the
     *washed* ground, not against bare cream: each clears 4.6:1 on the
     heaviest surface it ever appears on, which is why they read a shade
     darker than a colour picker would suggest. At 8% the whole set holds. If
     this number goes up, re-solve all five and --ink-quiet with it - every
     one of them was under AA at the values that looked right on paper. */
  --tint: 8%;

  /* The bar floats, so it costs more vertical space than its own height:
     the pill plus the air above and below it. Anything that has to clear
     the bar - body padding, anchor scroll targets - uses --nav-space, never
     --nav-h. Getting that wrong parks in-page links under the pill. */
  --nav-gap:   0.9rem;
  --nav-space: calc(var(--nav-h) + var(--nav-gap) * 2);

  --serif: "Cormorant Garamond", Cormorant, Garamond, "Times New Roman",
           Times, serif;
  --sans:  "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
           Helvetica, Arial, sans-serif;

  /* Wide gutters and a narrow measure. The page is mostly margin on
     purpose - maximum whitespace is a layout instruction, not a mood. */
  --gutter: clamp(1.5rem, 7vw, 6rem);
  --page:   1180px;
  --measure: 34rem;

  --nav-h: 4.25rem;   /* the pill itself                              */

  /* Motion. Long durations and a single deep ease-out: things decelerate
     into place and stay there. --ease-mask is slower still at the tail,
     which is what makes an uncovering read as deliberate rather than as a
     wipe. Nothing on this site bounces, spins or slides sideways. */
  --ease-out:   cubic-bezier(0.16, 1, 0.3, 1);
  --ease-inout: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-mask:  cubic-bezier(0.22, 1, 0.36, 1);

  --t-base:  340ms;
  --t-slow:  620ms;
  --t-enter: 1100ms;   /* the mask lift                                    */
}

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

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

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

body {
  margin: 0;
  padding-top: var(--nav-space);
  overflow-x: clip;
  background: var(--paper);
  color: var(--ink-body);
  font-family: var(--sans);
  font-size: clamp(0.9375rem, 0.875rem + 0.28vw, 1.0625rem);
  line-height: 1.8;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg { max-width: 100%; }
h1, h2, h3, p, figure, blockquote { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

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

/* Reachable by a screen reader, invisible to everyone else. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The one thing on the site that is allowed to be loud. */
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}

/* --- Language switching --------------------------------------------------
   Both languages live in the markup; the active one is selected by the lang
   attribute on <html>. Still readable with JavaScript disabled (German).
   ------------------------------------------------------------------------- */

html[lang="de"] [lang="en"],
html[lang="en"] [lang="de"] { display: none !important; }

/* Anything carrying a sector sets --accent once; the label, the rule above
   it, the index and the thumbnail frame all read from it. Nothing else in
   this file needs to know which sector it is in, and a new one is one line. */
[data-sector="hospitality"] { --accent: var(--hospitality); }
[data-sector="technology"]  { --accent: var(--technology); }
[data-sector="mobility"]    { --accent: var(--mobility); }
[data-sector="real-estate"] { --accent: var(--realestate); }
[data-sector="investments"] { --accent: var(--investments); }

/* --- Layout ------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: clamp(5rem, 13vw, 11rem);
  scroll-margin-top: var(--nav-space);
}

/* The two prose sections alternate: one on the paper, one on a wash of the
   same colour the portfolio uses for that sector, so the home page carries
   colour without inventing a palette of its own. */
.section--tint {
  background: var(--paper);
  background: color-mix(in srgb, var(--accent, var(--ink)) var(--tint), var(--paper));
}

/* --- Typography ----------------------------------------------------------
   Serif for anything that is a name or a heading, sans for anything you
   read at paragraph size or below. Cormorant is a fine, high-contrast face:
   it is superb at 48px and unreadable at 14px, so the line is drawn there
   and never crossed.
   ------------------------------------------------------------------------- */

.display,
.page-title,
.heading,
.entry__name,
.row__name,
.brand { font-family: var(--serif); color: var(--ink); }

/* The hero wordmark. Letter-spacing does the work that weight would do in a
   sans - it is what makes four syllables occupy a whole screen without ever
   raising its voice. */
.display {
  /* Sized to hold one line at every width. Broken over two it reads as a
     stack of two words rather than as one name. */
  white-space: nowrap;
  font-size: clamp(1.6rem, 8.5vw, 7rem);
  font-weight: 400;
  font-variant-numeric: lining-nums;
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* The trailing letter-space pushes optical centre off by half a space. */
  text-indent: 0.12em;
}

.display .brand__mark { font-weight: 600; }

.page-title {
  font-size: clamp(2.5rem, 8vw, 5.5rem);
  font-weight: 300;
  line-height: 1.02;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.heading {
  font-size: clamp(1.75rem, 4vw, 3rem);
  font-weight: 300;
  line-height: 1.18;
  letter-spacing: 0.005em;
  text-wrap: balance;
  margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}

/* The section label: the smallest type on the page, in the sans, with a
   hairline over it that draws itself when the section arrives. */
.eyebrow {
  position: relative;
  padding-top: 1.75rem;
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--accent, var(--ink-quiet));
}

/* Drawn, not printed. The rest state is the drawn one on purpose: main.js
   strips the .reveal classes once an entrance is over, and a rule that
   depended on those classes to stay visible would collapse the moment they
   went. So it is held back only while its block is genuinely still waiting,
   and every other condition leaves it drawn. */
.eyebrow::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 3.5rem;
  height: 1px;
  background: var(--accent, var(--ink));
  transform: scaleX(1);
  transform-origin: left center;
  transition: transform var(--t-slow) var(--ease-mask) 120ms;
}

.anim .reveal--scroll:not(.is-visible) .eyebrow::before,
.anim:not(.is-ready) .reveal .eyebrow::before { transform: scaleX(0); }

.prose { max-width: var(--measure); }
.prose p { text-wrap: pretty; }
.prose p + p { margin-top: 1.6em; }

/* The opening sentence of a section, one step up in size and in the serif.
   It is the only typographic emphasis on the site - there is no bold, no
   italic and no colour change anywhere in the body copy. */
.lede {
  font-family: var(--serif);
  font-size: clamp(1.25rem, 2.2vw, 1.625rem);
  font-weight: 300;
  line-height: 1.5;
  color: var(--ink);
  margin-bottom: 1.4em;
  text-wrap: pretty;
}

/* --- Header --------------------------------------------------------------
   A pill that floats clear of the page edges. The outer .header is only the
   air around it - it is transparent and passes the pointer straight through,
   so the strip of page either side of the pill stays selectable and
   clickable. Only the pill itself and the menu take events back.

   At rest the pill is fully transparent: no fill, no border, no blur. It
   only becomes a surface once the page has scrolled, at which point it has
   content passing underneath and needs to stay legible against it. Then it
   is translucent over a blur rather than solid, so type moving behind it
   reads as movement behind glass instead of disappearing at a hard edge.
   There is no shadow: the brief rules them out, and the hairline plus the
   blur already read as depth.

   The home page puts a photograph behind the bar, which inverts the problem:
   over the picture the labels have to be cream, and over the cream page they
   have to be ink. .has-hero carries that, and only while unscrolled - the
   moment the pill takes its fill, the ink defaults are correct again on
   every page.
   ------------------------------------------------------------------------- */

.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  padding: var(--nav-gap) var(--gutter);
  pointer-events: none;
}

.header__inner {
  pointer-events: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: var(--nav-h);
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 2.5vw, 2.25rem);
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  transition: background-color var(--t-slow) var(--ease-inout),
              border-color var(--t-slow) var(--ease-inout),
              backdrop-filter var(--t-slow) var(--ease-inout);
}

/* Once there is content behind it the pill firms up - it has something to
   stay legible against now. Colour only, never size, so nothing shifts. */
.header.is-scrolled .header__inner {
  background: rgba(237, 230, 216, 0.88);
  border-color: var(--rule);
  -webkit-backdrop-filter: blur(16px) saturate(1.08);
  backdrop-filter: blur(16px) saturate(1.08);
}

/* Over the hero photograph, before the pill has any fill of its own. */
.has-hero .header:not(.is-scrolled) .brand,
.has-hero .header:not(.is-scrolled) .menu-toggle,
.has-hero .header:not(.is-scrolled) .nav__link[aria-current="page"],
.has-hero .header:not(.is-scrolled) .lang__btn[aria-current="true"] {
  color: var(--paper);
}

.has-hero .header:not(.is-scrolled) .nav__link,
.has-hero .header:not(.is-scrolled) .lang__btn {
  color: rgba(237, 230, 216, 0.78);
}

.has-hero .header:not(.is-scrolled) .nav__link:hover,
.has-hero .header:not(.is-scrolled) .nav__link:focus-visible,
.has-hero .header:not(.is-scrolled) .lang__btn:hover { color: var(--paper); }

.has-hero .header:not(.is-scrolled) .lang__sep {
  color: rgba(237, 230, 216, 0.4);
}

.has-hero .header:not(.is-scrolled) :focus-visible { outline-color: var(--paper); }

/* The wordmark has to be unmistakably M-zero-seven. Cormorant sets figures
   old-style by default, which drops the zero to x-height and turns the mark
   into "Mo7" - a real misreading of the client's name, not a nicety. Lining
   figures are what fix it, and every place a digit appears in the serif
   carries them. */
.brand {
  font-size: 1.3125rem;
  font-weight: 500;
  font-variant-numeric: lining-nums;
  letter-spacing: 0.2em;
  line-height: 1;
  white-space: nowrap;
  text-transform: uppercase;
  text-indent: 0.2em;
}

.brand__mark { font-weight: 700; letter-spacing: 0.14em; }

.header__right {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 3vw, 2.75rem);
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(0.5rem, 1.5vw, 1.25rem);
}

.nav__link,
.lang__btn,
.menu-toggle {
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1;
}

.nav__link {
  position: relative;
  padding: 0.65rem 0;
  color: var(--ink-quiet);
  transition: color var(--t-base) var(--ease-inout);
}

.nav__link:hover,
.nav__link:focus-visible { color: var(--ink); }

/* Links may take a fine underline on hover. One rule, one pixel, wiping in
   from the left and retracting to the right. It is the only hover effect on
   the entire site, and every link on it shares this one declaration. */
.nav__link::after,
.link::after,
.row__name::after,
.entry--link .entry__name::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform var(--t-base) var(--ease-inout);
}

.nav__link:hover::after,
.nav__link:focus-visible::after,
.link:hover::after,
.link:focus-visible::after,
.row:hover .row__name::after,
.row:focus-visible .row__name::after,
.entry--link:hover .entry__name::after {
  transform: scaleX(1);
  transform-origin: left center;
}

/* The page you are on keeps the rule permanently. No block, no fill - the
   brief rules out anything that reads as a box. */
.nav__link[aria-current="page"] { color: var(--ink); }
.nav__link[aria-current="page"]::after { transform: scaleX(1); }

/* Language toggle */

.lang {
  display: flex;
  align-items: center;
  gap: 0.45rem;
}

.lang__btn {
  color: var(--ink-quiet);
  padding-block: 0.35rem;
  transition: color var(--t-base) var(--ease-inout);
}

.lang__sep { color: var(--rule-strong); font-size: 0.6875rem; }
.lang__btn:hover { color: var(--ink); }
.lang__btn[aria-current="true"] { color: var(--ink); cursor: default; }

/* Mobile menu */

.menu-toggle {
  display: none;
  padding: 0.65rem 0;
  color: var(--ink);
  position: relative;
}

.menu {
  pointer-events: auto;
  display: none;
  max-width: var(--page);
  margin: 0.55rem auto 0;
  border: 1px solid var(--rule);
  border-radius: 1.75rem;
  background: rgba(237, 230, 216, 0.96);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}

.menu[data-open="true"] {
  display: block;
  animation: menu-in var(--t-slow) var(--ease-out) backwards;
}

@keyframes menu-in {
  from { opacity: 0; }
}

.menu__list {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 1.25rem clamp(1.5rem, 4vw, 2.25rem) 1.5rem;
}

.menu__list .nav__link {
  font-size: 0.8125rem;
  padding-block: 0.6rem;
  align-self: flex-start;
}

/* --- Hero ----------------------------------------------------------------
   The wordmark over a photograph, and nothing else. No claim, no button.

   A whole screen holding four syllables. The wordmark is optically centred
   rather than mathematically centred - it sits a little above the middle,
   because a block of type parked on the exact centre line always reads as
   having sunk.
   ------------------------------------------------------------------------- */

.hero {
  position: relative;
  display: grid;
  place-items: center;
  /* The bar floats over the picture rather than above it, so the hero starts
     at the very top of the page - it pulls back the space body reserved for
     the bar, and is a full viewport tall rather than a viewport minus a bar
     it no longer sits below. Take the negative margin without also taking
     the full height and the first screen ends a bar's height short, showing
     a strip of the next section. */
  margin-top: calc(var(--nav-space) * -1);
  min-height: 100vh;
  min-height: 100dvh;
  padding-block: calc(var(--nav-space) + clamp(2rem, 6vh, 5rem)) clamp(6rem, 16vh, 12rem);
  text-align: center;
  background: var(--ink);
  overflow: hidden;
  isolation: isolate;
}

/* Everything here stacks upward from zero rather than downward from the
   content: the picture is a positioned layer, its scrim is a pseudo-element
   on the picture, and the wordmark is lifted above both. The negative
   z-index version of this reads more cleanly but relies on the one corner of
   the painting order that browsers and renderers disagree about - and when
   it goes wrong it does not warn you, it silently serves a flat rectangle
   where the photograph should be. */
.hero__media {
  position: absolute;
  inset: 0;
  margin: 0;
  z-index: 0;
}

.hero__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A photograph cannot be trusted to stay dark where the type lands, and the
   wordmark has to hold at every crop and on every replacement image. The
   scrim is the cheapest honest fix: night blue over the whole frame so the
   picture joins the palette rather than fighting it, deepening toward the
   foot where the type sits. Cream on this measures better than 9:1 over the
   lightest part of the current photograph.

   This is the one gradient on the site. It is here for legibility, not
   decoration - without it the wordmark is at the mercy of whatever
   photograph replaces hero.jpg. */
.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom,
      rgba(11, 29, 51, 0.74) 0%,
      rgba(11, 29, 51, 0.64) 45%,
      rgba(11, 29, 51, 0.80) 100%);
}

.hero__inner {
  position: relative;
  z-index: 1;
  width: 100%;
}

.hero .hero__cue { z-index: 1; }

/* Inverted, because it now sits on the picture. */
.hero .display { color: var(--paper); }
.hero .hero__rule { background: rgba(237, 230, 216, 0.55); }
.hero .hero__cue { background: rgba(237, 230, 216, 0.3); }
.hero .hero__cue::after { background: var(--paper); }

/* The hairline under the wordmark draws itself out from the centre once the
   letters have settled. It is the only ornament on the page. */
.hero__rule {
  width: min(12rem, 34vw);
  height: 1px;
  margin: clamp(2.5rem, 6vw, 4rem) auto 0;
  background: var(--rule-strong);
  transform: scaleX(0);
  transition: transform 1200ms var(--ease-mask) 700ms;
}

.is-ready .hero__rule { transform: scaleX(1); }

/* A whole screen holding two words gives no sign that a page follows it. One
   hairline at the foot, with a short segment travelling down it, is the
   smallest honest way to say so - no text to translate, no arrow glyph, and
   it is a real link, so it works for a keyboard too. */
.hero__cue {
  position: absolute;
  left: 50%;
  bottom: clamp(1.5rem, 4vh, 2.75rem);
  transform: translateX(-50%);
  display: block;
  width: 1px;
  height: 3.25rem;
  overflow: hidden;
  background: var(--rule);
  opacity: 0;
  transition: opacity var(--t-slow) var(--ease-inout) 1500ms;
}

.is-ready .hero__cue { opacity: 1; }

.hero__cue::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ink);
  animation: cue 2.8s var(--ease-inout) infinite;
}

@keyframes cue {
  0%       { transform: translateY(-100%); }
  55%,100% { transform: translateY(100%); }
}

.page-head {
  padding-block: clamp(5rem, 14vw, 10rem) clamp(3rem, 8vw, 6rem);
}

/* The 404 is the only page head that carries a link under its title. */
.page-head .link { margin-top: clamp(2rem, 4vw, 3rem); }

/* --- Blocks --------------------------------------------------------------
   A narrow label column on the left, the copy on the right. The label sits
   at the top of its column and stays there - it is a margin note, not a
   heading.
   ------------------------------------------------------------------------- */

.block {
  display: grid;
  grid-template-columns: minmax(0, 11rem) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 5rem);
}

.block__body { min-width: 0; }

@media (max-width: 46.875em) {
  .block { grid-template-columns: minmax(0, 1fr); gap: 1.75rem; }
}

/* --- Photography ---------------------------------------------------------
   Eight photographs by eight photographers will read as eight photographs
   whatever is done to them. The grade below only pulls them toward a common
   temperature - it cannot make them one shoot, and it is not trying to. A
   single coherent set is the real fix and is tracked in
   todo/manual-tasks.md; every file in assets/img is still a placeholder.

   Rounded to the same language as the navigation pill, because a square
   photograph next to a fully round bar reads as two different websites.
   ------------------------------------------------------------------------- */

.media {
  display: block;   /* the row thumbnails are spans, which would stay inline */
  position: relative;
  overflow: hidden;
  border-radius: 1.25rem;
  /* What a lazy image shows while it is still arriving. A deeper mix of the
     panel's own sector colour, so the gap reads as part of the page rather
     than as a hole punched in it. */
  background: var(--rule);
  background: color-mix(in srgb, var(--accent, var(--ink)) 26%, var(--paper));
  isolation: isolate;
}

.media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.92) contrast(1.03);
  transition: transform 900ms var(--ease-out);
}

/* A photograph inside something clickable opens up under the pointer. On its
   own it stays still - moving would promise a link that is not there. */
a:hover .media img,
a:focus-visible .media img,
.entry--link:hover .media img { transform: scale(1.03); }

.media--wide { aspect-ratio: 16 / 9; }

.media--thumb {
  aspect-ratio: 1;
  width: clamp(3.25rem, 6vw, 4.5rem);
  flex: none;
  border-radius: 0.85rem;
}

/* A photograph that runs the width of the page grid, under the block that
   introduces it. */
.band { margin-top: clamp(2.5rem, 5vw, 4rem); }

@media (max-width: 46.875em) {
  .media--wide { aspect-ratio: 4 / 3; }
  .media { border-radius: 0.9rem; }
}

/* --- Split ---------------------------------------------------------------
   A block and its photograph side by side once the page is wide enough:
   copy on the left, picture on the right, the two centred on each other.
   The label loses its own column here - half the page cannot afford a
   margin note - and sits above the copy instead, as it does on a phone.
   On a phone nothing below applies and the pair stacks, picture
   under copy, exactly as .band lays it out.
   ------------------------------------------------------------------------- */

@media (min-width: 46.9375em) {
  .split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: clamp(2.5rem, 5vw, 5rem);
    align-items: center;
  }

  .split .block { grid-template-columns: minmax(0, 1fr); gap: 1.75rem; }
  .split .band { margin-top: 0; }
  .split .media--wide { aspect-ratio: 4 / 3; }
}

/* --- Links ---------------------------------------------------------------
   A line of type and an arrow, nothing filled and nothing boxed. The arrow
   is a character, not an icon: the brief bans icons and writes the arrow
   into the copy itself.
   ------------------------------------------------------------------------- */

.link {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 0.7rem;
  padding-bottom: 0.35rem;
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
  transition: gap var(--t-base) var(--ease-out);
}

.link:hover,
.link:focus-visible { gap: 1.1rem; }

.link--lg {
  font-size: 0.8125rem;
  letter-spacing: 0.2em;
}

/* --- Selected activities -------------------------------------------------
   Extremely reduced. No boxes and no logos.

   So: a name, a category, and a hairline between them. The whole row is the
   link, but nothing about it lights up, fills or lifts - the name takes the
   same one-pixel underline every other link on the site takes.
   ------------------------------------------------------------------------- */

.rows { margin-top: clamp(2.5rem, 6vw, 4.5rem); }

/* The one link that closes a section, set off from what it follows. */
.section__foot { margin-top: clamp(3rem, 6vw, 4.5rem); }

.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  padding: clamp(1.5rem, 3.5vw, 2.5rem) 0;
  border-bottom: 1px solid var(--rule);
  color: var(--ink);
}

.rows .row:first-child { border-top: 1px solid var(--rule); }

.row {
  position: relative;
  isolation: isolate;
  transition: color var(--t-base) var(--ease-inout);
}

/* The whole band is the hit target, so the whole band answers - in that
   row's own sector colour, bleeding a little past the text edges so it reads
   as the row lighting up rather than as a box appearing. The bleed stays
   well inside --gutter at every width. */
.row::before {
  content: "";
  position: absolute;
  inset: 0 calc(var(--gutter) * -0.35);
  z-index: -1;
  border-radius: 0.75rem;
  background: color-mix(in srgb, var(--accent, var(--ink)) 12%, var(--paper));
  opacity: 0;
  transition: opacity var(--t-base) var(--ease-inout);
}

.row:hover::before,
.row:focus-visible::before { opacity: 1; }

.row__main {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.5vw, 1.75rem);
  min-width: 0;
}

.row__name {
  position: relative;
  display: inline-block;
  font-size: clamp(1.5rem, 3.2vw, 2.25rem);
  font-weight: 300;
  line-height: 1.15;
  letter-spacing: 0.01em;
  padding-bottom: 0.1rem;
}

.row__cat {
  flex: none;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent, var(--ink-quiet));
  text-align: right;
}

/* --- Portfolio entries ---------------------------------------------------
   Same shape as a block, with an index in the label column. The numbers are
   the only concession to ornament and they earn it: five entries with no
   images need something to tell you where you are in the list.
   ------------------------------------------------------------------------- */

.entries { padding-bottom: clamp(5rem, 12vw, 9rem); }

/* Each entry sits on its own sector colour, mixed down to --tint so the
   panel reads as a wash rather than a block. One declaration gives the
   portfolio five distinct fields of colour without a single new hex value,
   and without any label needing to shout.

   The plain --paper line is the fallback: color-mix is well supported now,
   but a browser without it must still get a page, not a transparent panel
   with body copy showing through. */
.entry {
  padding: clamp(2.5rem, 6vw, 4.5rem) clamp(1.5rem, 4vw, 3.5rem);
  border-radius: clamp(1.25rem, 2.5vw, 2rem);
  scroll-margin-top: var(--nav-space);
  background: var(--paper);
  background: color-mix(in srgb, var(--accent, var(--ink)) var(--tint), var(--paper));
}

.entry + .entry { margin-top: clamp(1rem, 2.5vw, 1.75rem); }

.entry__index {
  display: block;
  margin-top: 1.1rem;
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.18em;
  color: var(--accent, var(--ink-quiet));
  font-variant-numeric: tabular-nums;
}

/* A portfolio entry with a live website behind it is clickable end to end,
   which the brief allows explicitly. The pointer is the only thing that
   says so - there is no surface to light up. */
.entry--link { cursor: pointer; }

.entry__name {
  position: relative;
  display: inline-block;
  font-size: clamp(2rem, 5vw, 3.5rem);
  font-weight: 300;
  line-height: 1.06;
  letter-spacing: 0.01em;
  margin-bottom: clamp(1.25rem, 3vw, 2rem);
  padding-bottom: 0.1rem;
}

.entry__link { margin-top: clamp(2rem, 4.5vw, 3rem); }

/* --- Legal pages ---------------------------------------------------------- */

.legal { padding-block: clamp(2rem, 5vw, 3rem) clamp(5rem, 11vw, 8rem); }

.legal__block + .legal__block { margin-top: clamp(2.75rem, 5.5vw, 4rem); }

.legal h2 {
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  margin-bottom: 1.1rem;
}

.legal p { max-width: 42rem; text-wrap: pretty; }
.legal p + p { margin-top: 1.3em; }

.placeholder {
  color: var(--ink-quiet);
  border-bottom: 1px dashed var(--rule-strong);
}

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

/* The one solid field of night blue on the site. The page opens on the
   colour behind a photograph and closes on it flat - and after five tinted
   sector panels the eye needs somewhere to land that is not a wash. */
.footer {
  background: var(--ink);
  color: rgba(237, 230, 216, 0.62);
  padding-block: clamp(3.5rem, 7vw, 5.5rem);
  margin-top: clamp(4rem, 9vw, 7rem);
}

.footer__brand,
.footer .nav__link:hover,
.footer .nav__link[aria-current="page"],
.footer .lang__btn:hover,
.footer .lang__btn[aria-current="true"] { color: var(--paper); }

.footer .nav__link,
.footer .lang__btn { color: rgba(237, 230, 216, 0.62); }

.footer .lang__sep { color: rgba(237, 230, 216, 0.3); }

.footer :focus-visible { outline-color: var(--paper); }

.footer__top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 2rem 3rem;
}

.footer__brand {
  font-family: var(--serif);
  font-size: 1.25rem;
  font-weight: 500;
  font-variant-numeric: lining-nums;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-indent: 0.2em;
}

.footer__nav {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
}

.footer__legal {
  margin-top: clamp(2.5rem, 5vw, 4rem);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  color: rgba(237, 230, 216, 0.45);
}

/* --- Reveal --------------------------------------------------------------
   The house entrance, used everywhere: the type is already set and a mask
   lifts off it. clip-path animates on the compositor, so this costs one
   layer and no layout, and because the element never actually moves there
   is nothing left declaring transform to collide with a hover state later.

   The rise underneath is 0.5rem - just enough that the eye reads it as
   arriving rather than as appearing.
   ------------------------------------------------------------------------- */

.anim .reveal > * {
  opacity: 0;
  clip-path: inset(0 0 110% 0);
  transform: translateY(0.5rem);
}

.anim.is-ready .reveal:not(.reveal--scroll) > *,
.anim .reveal--scroll.is-visible > * {
  opacity: 1;
  clip-path: inset(-25% 0 -25% 0);
  transform: none;
  transition:
    opacity var(--t-slow) var(--ease-out) var(--in-delay, 0ms),
    clip-path var(--t-enter) var(--ease-mask) var(--in-delay, 0ms),
    transform var(--t-enter) var(--ease-mask) var(--in-delay, 0ms);
}

/* --- Mobile --------------------------------------------------------------
   The same reduction exactly. Large type, generous spacing. Nothing is
   dropped and nothing is condensed - the type scale above is already fluid,
   so the phone gets the same page with more air per word.
   ------------------------------------------------------------------------- */

@media (max-width: 46.875em) {
  .nav { display: none; }
  .js .menu-toggle { display: inline-block; }

  /* The pill has to hold the wordmark, MENU and DE | EN inside one rounded
     box narrower than a phone. At the desktop sizes it does not: the sum
     runs about 80px past a 320px screen, and because the bar is fixed the
     overflow takes the whole document sideways rather than just clipping
     itself. Everything below trims that sum - the gutter it floats in, its
     own padding, the two gaps, and the wordmark's size and tracking. */
  .header { padding-inline: 1rem; }

  .header__inner {
    gap: 0.75rem;
    padding-inline: 1rem;
  }

  .brand {
    font-size: 1rem;
    letter-spacing: 0.14em;
    text-indent: 0.14em;
  }

  .header__right { gap: 0.85rem; }

  .menu { margin-inline: 0; }

  .row {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.75rem;
  }

  .row__cat { text-align: left; }

  .footer__top {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* --- Motion preferences --------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }

  .anim .reveal > * {
    opacity: 1;
    clip-path: none;
    transform: none;
  }

  .hero__rule,
  .eyebrow::before { transform: scaleX(1); }

  .hero__cue { opacity: 1; }
  .hero__cue::after { animation: none; transform: none; }
}

/* --- Print ---------------------------------------------------------------- */

@media print {
  body { background: #fff; color: #000; padding-top: 0; }

  .header,
  .hero__cue,
  .footer__nav { display: none; }

  .hero { min-height: 0; padding-block: 2rem 4rem; }

  /* Nothing scrolls when printing, so the observer never fires. Without
     this every .reveal--scroll block prints blank. */
  .anim .reveal > * {
    opacity: 1 !important;
    clip-path: none !important;
    transform: none !important;
  }
}
