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

/* 4 columns, 16px gutters, 16px margin. --col is derived from the same numbers
   the grid uses, so the logo is exactly one column wide by construction. */
:root {
  --margin: 16px;
  --gutter: 16px;
  --col: calc((100vw - (var(--margin) * 2) - (var(--gutter) * 3)) / 4);
  --ease: cubic-bezier(.16, 1, .3, 1);
  /* Where a rule sits above the bottom of a link box. The baseline lands about
     this far up once half-leading and the font's descent are accounted for, so
     both the resting underline and the laser use it and align exactly. */
  --rule: 0.09em;
  /* Slack below each reveal mask for descenders. Shared by the mask's padding
     and the resting offset of the line inside it, so the line always starts
     fully clear of the mask however this is tuned. */
  --descend: 0.26em;
}

html, body { height: 100%; overflow: hidden; }

body {
  background: #fff;
  color: #000;
  /* Small text is Helvetica Neue, exactly as on the Gotham site. Neue Haas
     Grotesk is kept for the large type and the marks, where its Display cut is
     at home — at 14px that cut's spacing closes up, which Helvetica's does
     not. */
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 14px;
  line-height: 1.35;
  -webkit-font-smoothing: antialiased;
}

.stage {
  position: relative;
  z-index: 1;        /* over the watermark */
  width: 100vw;
  height: 100vh;
  height: 100svh;
  padding: var(--margin);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--gutter);
  overflow: hidden;
}

/* ---------- media: columns 1–3, bleeding off three edges ----------
   Negative margins cancel the stage padding on top, left and bottom, so the
   footage runs to the edge of the viewport while its right edge stays on the
   column-3 grid line. */
.media {
  grid-column: 1 / 4;
  position: relative;
  overflow: hidden;
  background: #0a0a0a;
  margin: calc(var(--margin) * -1) 0 calc(var(--margin) * -1) calc(var(--margin) * -1);
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1.1s var(--ease);
}
body.ready .media { clip-path: inset(0 0 0 0); }

.media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Puts the Matterhorn's summit (41.4% across the source) on the centre line
     of the frame, clear of the logo. The frame is always narrower than 16:9
     here, so the video is scaled to the frame's height and is 100svh * 16/9
     wide. At 50% its centre sits on the frame's; the summit is 8.6% of the
     video's width left of that centre, so slide it right by that much
     (0.086 * 16/9 = 15.3svh). min() stops at 0% — flush left — on frames
     wide enough that the full shift would open a gap. */
  object-position: min(calc(50% + 15.3svh), 0%) 50%;
  filter: grayscale(1);
}

/* The logo keeps the margin the footage gives up. A column and a tenth —
   10% over the single column it started at. */
.logo {
  position: absolute;
  top: var(--margin);
  left: var(--margin);
  width: calc(var(--col) * 1.1);
  pointer-events: none;
  /* Deliberately no z-index and no blend on the wrapper: either one makes it a
     stacking context, and "Four" would then blend against this empty box
     instead of the footage. It still paints above the video by source order. */
}

.logo img { display: block; width: 100%; height: auto; }

/* White + difference keeps "Four" legible whatever frame is underneath. */
.logo-four { mix-blend-mode: difference; }

/* "56" in brand red under the same difference blend as "Four", so both halves
   carry the footage's texture. Difference is |backdrop - colour|: against the
   dark sky behind the logo that returns the red, deepened to burgundy; it
   would only swing to cyan over a light backdrop. A pre-inverted cyan does
   the opposite here — it inverts to burgundy over white, but over dark sky it
   comes back cyan. Same viewBox as the layer below, so the two register. */
.logo-56 { position: absolute; inset: 0; mix-blend-mode: difference; }

/* ---------- the wide text side of the about page ----------
   The wrapper spans columns 1-3; .essay below sets the actual measure (2.6
   columns) and the type scale. 3.6vw is ~69px at a 1920 viewport and scales
   down from there, with the clamp stopping it before it gets unreadably
   small. */
.essay-wrap {
  grid-column: 1 / 4;
  align-self: start;
}

/* Mark only, no wordmark, dead centre of the viewport and behind everything.
   The grey is baked into four56-mark.svg as #F2F2F2 rather than faked with opacity —
   an opacity value only lands on that colour while the backdrop stays white,
   whereas the fill is exact whatever ends up behind it. */
.watermark {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* The (4)56 mark is 2.4:1 where the square Gotham mark it replaces was
     1:1, so the width bounds are scaled up by 1.75 together — at the same
     width it would have come out less than half the height. */
  width: clamp(238px, 28.56vw, 500px);
  height: auto;
  opacity: 0;
  z-index: 0;
  pointer-events: none;
  transition: opacity 900ms var(--ease) 200ms;
}


/* Carried over from the previous page: the mark occupies the same point on
   about and trade, so fading it up from nothing reads as it being rebuilt.
   On a repeat visit it is already there, dimmed, and just comes back up. */
html.mark-carry .watermark {
  opacity: 0.35;
  transition: opacity 320ms linear;
}

body.ready .watermark { opacity: 1; }

.essay {
  /* 2.6 columns — re-measured for Neue Haas Grotesk rather than inherited
     from the serif this was first tuned on. Swept 920-2600px in 10px steps:
     2.6 is 95% widow-free with the only failing bands at 1950-2010 and 2380,
     clear of every standard resolution; 2.7 widows across 920-1940. The box
     and the type scale on different curves — --col carries a fixed 80px of
     margin and gutter, the font-size clamp does not — so the ratio between
     them drifts with the viewport and has to be checked across it. */
  width: calc(var(--col) * 2.6 + var(--gutter) * 2);
  /* Named outright, not inherited — the body is Helvetica Neue. The lowercase
     name is what an Adobe Fonts kit registers, so a kit needs no CSS change. */
  font-family: "Neue Haas Grotesk Display Pro", "neue-haas-grotesk-display",
               "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: clamp(36px, 4.32vw, 84px);
  /* Roman (55). This family's weight classes are offset — 45 Light is
     registered as 400, 55 Roman as 500 — so a plain `normal` would land on
     Light. */
  font-weight: 500;
  line-height: 1.03;
  letter-spacing: -0.03em;
}

/* ---------- column 4 ---------- */
.col {
  grid-column: 4 / 5;
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--gutter);
  white-space: nowrap;
}

.col p { margin-top: 34px; }

/* Column flow so the label and the link each get their own reveal box —
   a <br> would leave the two of them in a single line and one mask. */
.contact {
  margin-top: 24px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Dead centre of the viewport, not of the leftover space. The column spans the
   full height between equal margins, so 50% of it is 50% of the page. */
.mid {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  transform: translateY(-50%);
}

.foot { margin-top: auto; color: #b0b0b0; text-align: right; }

/* Images are furniture, not content to be pulled out of the page. The
   attribute alone is ignored by some browsers, and the property alone still
   allows a selection-drag, so both are set. */
img {
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
}

a { color: inherit; text-decoration: none; position: relative; display: inline-block; }

/* The resting underline is drawn as a pseudo-element rather than with
   text-decoration, so it shares an anchor with the hover laser below. Left as
   text-decoration the two are measured from different things — the baseline
   versus the element box — and the laser lands below the static rule. */
.u::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--rule);
  height: 1px;
  background: currentColor;
}

/* inline-block so cta.js can lock the width while the label scrambles —
   `width` is ignored on an inline box, which lets the link twitch. */
.cta { display: inline-block; }

/* Highlights are black across the site: the live text selection and the baked
   .hl run below are the same treatment, so a selection dragged over a
   highlighted sentence does not change its look. */
::selection { background: #000; color: #fff; }

/* A marked phrase inside reveal copy, underlined rather than boxed. reveal.js
   rebuilds each line and re-wraps the run, so a phrase crossing a line break
   comes back as one element per line and each gets its own rule — which is
   what makes the underline stop at the line end and pick up again below,
   instead of one rule stretching under the gap.

   inline-block and nowrap because decipher.js pins each fragment to its
   resting width while the cipher runs: width is ignored on an inline box, and
   without the pin the substitute glyphs would reflow the copy around them.
   Shares --rule with the link underline so the two sit at the same height. */
.hl {
  position: relative;
  display: inline-block;
  white-space: nowrap;
  /* The cipher glyphs run 16-25% wider than the real text and up to 88% in the
     worst case, so without clipping the scramble spills over the words after
     it. Clipped with clip-path rather than overflow: an inline-block whose
     overflow is not visible takes its BOTTOM MARGIN EDGE as its baseline
     (CSS 2.1 10.8.1), which lifts the phrase off the line it sits on.
     clip-path is a paint operation and leaves layout and baseline untouched.
     Open vertically so ascenders and descenders are never cut. */
  clip-path: inset(-0.4em 0 -0.4em 0);
}

.hl::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--rule);
  height: 1px;
  background: currentColor;
}

/* ---------- hover laser ----------
   Draws in from the left, holds while the pointer is on the link, then exits
   to the right. Each hover appends its own element, so a second hover starts a
   second line instead of restarting the first — the passes overlap rather than
   cutting each other off, and each removes itself when it leaves.

   Driven by clip-path, not scaleX: retracting a scaled line means flipping
   transform-origin from left to right mid-sweep, which re-anchors the visible
   segment and makes it jump across the link. Clip insets interpolate
   continuously, so the exit can pick up exactly where the entry got to. */
.laser {
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--rule);
  height: 1px;
  background: currentColor;
  clip-path: inset(0 100% 0 0);
  pointer-events: none;
}

/* ---------- line reveal ----------
   Each line gets its own clipping box and slides up into it from below. The
   padding/margin pair keeps descenders from being shaved by overflow:hidden. */
/* The padding/margin pair gives the box room for descenders that a tight
   line-height would otherwise put outside it, without adding any layout
   height. It has to exceed the gap between the line box and the font's
   descender, which is why it grew when the leading was tightened. */
.line {
  display: block;
  overflow: hidden;
  padding-bottom: var(--descend);
  margin-bottom: calc(var(--descend) * -1);
}

/* The resting offset must clear the mask's FULL visible height — the line box
   plus that descender padding — not just 100% of the line. A flat 110% left
   the top of the displaced text showing through the padding strip, which is
   the sliver that was peeking before the animation ran. */
.line-in {
  display: block;
  /* +2px on top of the exact figure: landing flush with the mask edge leaves
     a sub-pixel row of antialiasing showing. */
  transform: translateY(calc(100% + var(--descend) + 2px));
  transition: transform 900ms var(--ease);
}

.shown .line-in { transform: translateY(0); }

/* Placed, not animated — used for chrome that carried over from the last page. */
.line.instant .line-in { transition: none; }

/* Held invisible until reveal.js has built the masks, otherwise the copy is
   painted in full for the moment before the script runs — a wait that got
   longer once it started holding for webfonts. Gated on .js so the text stays
   readable if the script never runs at all. */
.js [data-reveal],
.js [data-reveal-rows] { visibility: hidden; }

.js.reveal-set [data-reveal],
.js.reveal-set [data-reveal-rows] { visibility: visible; }

@media (prefers-reduced-motion: reduce) {
  .line-in { transform: none; transition: none; }
  .media { clip-path: none; transition: none; }
  .laser { animation-duration: 1ms; }
}

/* ---------- trade ----------
   The only page that scrolls, so it opts out of the global overflow lock. */
html.scrolls, html.scrolls body { height: auto; overflow-y: auto; overflow-x: hidden; }

/* Everything but the plates is fixed. Each of these is a direct child of body
   so that the difference blends can still see the plates scrolling underneath
   — any wrapper that formed a stacking context would cut them off. */
.trade-nav {
  position: fixed;
  top: var(--margin);
  right: var(--margin);
  width: var(--col);          /* the 4th column, as on the hero */
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--gutter);
  white-space: nowrap;
  color: #fff;                /* white + difference = black on the page,
                                 inverted where a plate passes behind it */
  mix-blend-mode: difference;
  z-index: 5;
}

/* Logotype only — the mark already sits in the middle of this page, so
   repeating it in the corner would say the same thing twice.
   Plain black, no difference blend: the plates stop at the half-way line and
   never come within ~680px of this corner, so a blend would buy nothing and
   cost a composited layer — which is what made the hero logo rasterise soft on
   HiDPI back when it was an inverted filter rather than a shipped asset. */
.trade-logotype {
  position: fixed;
  top: var(--margin);
  left: var(--margin);
  width: clamp(65px, 4.59vw, 88px);
  z-index: 5;
  pointer-events: none;
}

.trade-logotype img { display: block; width: 100%; height: auto; }

.trade-meta {
  position: fixed;
  left: var(--margin);
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  grid-template-columns: var(--col) var(--col);
  gap: var(--gutter);
  width: calc(var(--col) * 2 + var(--gutter));
  z-index: 4;
}

.trade-link { margin-top: 18px; }

.trade-back {
  position: fixed;
  left: var(--margin);
  bottom: var(--margin);
  z-index: 4;
}

/* The scrolling column. Every plate is the same slot — reaching the page's
   middle and bleeding off the right edge — and the one crossing the viewport
   centre is the one at full size. Stacked flush: the only separation between
   them is what the scaling opens up.

   --plate-h is the figure the padding and the scroll wrap both derive from, so
   a plate sits dead centre whenever scrollY is a whole multiple of it. */
:root {
  --plate-w: 50vw;
  --plate-h: calc(var(--plate-w) * 4 / 5);   /* 5:4 landscape */
}

.plates {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0;
  padding-top: calc((100svh - var(--plate-h)) / 2);
  padding-bottom: calc((100svh - var(--plate-h)) / 2);
}

/* Size lives in the layout width, not in a transform. Height follows from the
   ratio, so normal flow keeps every plate touching the one above it however
   much their heights differ — a transform would shrink a plate away from its
   neighbours and open a gap. Right alignment comes from the flex container, so
   only the left edge ever moves. */
.plate {
  margin: 0;
  width: var(--plate-w);
  aspect-ratio: 5 / 4;
  overflow: hidden;
  background: #ededed;        /* holds the frame while the photo loads */
}

/* Colour is focus. Only the plate crossing the centre line carries it; every
   other one is drained to monochrome. plates.js writes --gray per plate on the
   same pass that sizes it, so the drain tracks the scroll exactly — a
   transition here would lag a frame-by-frame value and smear it. Defaults to
   1 so the stack is monochrome before the script runs, and stays that way
   under reduced motion, where nothing is ever centred. */
.plate img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(var(--gray, 1));
}

/* Wipes the plate column in from the top, same motion as the hero. It covers
   the column rather than clipping .plates itself — that element is three
   viewport-heights tall, so a clip on it would be measured against the whole
   scrolling stack instead of what is on screen. */
.plates-veil {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 50vw;              /* the widest a plate ever gets */
  background: #fff;
  z-index: 1;               /* over the plates, under the mark */
  pointer-events: none;
  clip-path: inset(0 0 0 0);
  transition: clip-path 1.1s var(--ease);
}
body.ready .plates-veil { clip-path: inset(100% 0 0 0); }

/* White fill + difference: reads black against the white page and inverts
   whatever plate passes beneath it. A literal black fill would difference to
   nothing on both. */
.watermark--invert {
  mix-blend-mode: difference;
  z-index: 2;
}

/* ---------- custom cursor ---------- */
html, body, a { cursor: none; }

.cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px; /* centres the mark on the pointer */
  z-index: 20;
  pointer-events: none;
  mix-blend-mode: difference; /* visible over both the white page and the footage */
  opacity: 0;
}
.cursor::before,
.cursor::after {
  content: '';
  position: absolute;
  background: #fff;
}
.cursor::before { left: 0; top: 50%; width: 100%; height: 1.5px; margin-top: -0.75px; }
.cursor::after { top: 0; left: 50%; height: 100%; width: 1.5px; margin-left: -0.75px; }

/* Sits off the pointer's lower right, clear of the plus rather than centred on
   it. Flat black — no difference blend here: this has to stay black-on-white
   to read as a label, where the plus wants to invert against whatever it
   crosses. cursor.js moves it with the same transform as the plus, so the two
   never drift apart. */
.cursor-label {
  position: fixed;
  top: 0;
  left: 0;
  margin: 10px 0 0 14px;
  z-index: 21;
  pointer-events: none;
  padding: 5px 9px;
  background: #000;
  color: #fff;
  line-height: 1.2;
  white-space: nowrap;
  /* Parked clipped to its own left edge. Clip rather than opacity so it wipes
     on instead of fading — and clip-path is a paint operation, so it does not
     disturb the transform the cursor script writes here every mousemove. */
  clip-path: inset(0 100% 0 0);
  transition: clip-path 340ms var(--ease);
}

/* Snapping back to the parked state between passes, never animated. */
.cursor-label.reset,
.cursor-label.reset .cursor-label-in { transition: none; }

/* In from the left, and out through the right rather than back the way it
   came — the same pass the hover laser makes across a link. */
.cursor-label.on { clip-path: inset(0 0 0 0); }
.cursor-label.off { clip-path: inset(0 0 0 100%); }

/* The contents ride in slightly behind the wipe, so the box does not arrive
   as one flat block. Held in place through the exit: letting it slide back
   while the clip leaves rightward pulls the two halves apart. */
.cursor-label-in {
  display: flex;
  align-items: center;
  gap: 6px;
  transform: translateX(-12px);
  transition: transform 340ms var(--ease);
}

.cursor-label.on .cursor-label-in,
.cursor-label.off .cursor-label-in { transform: translateX(0); }

.cursor-label img { display: block; width: 14px; height: 14px; }

/* ---------- tap-to-contact sheet (touch only) ----------
   Every rule lives inside (hover: none), matching the condition contact.js
   builds the sheet under. Belt and braces again: with no author styles at all
   on a hovering device, even an element that somehow got built would fall back
   to the UA sheet's [hidden] { display: none } instead of being styled into a
   full-page overlay. */
@media (hover: none) {
  /* The hidden attribute MUST be honoured explicitly. An author-level display
     beats the UA sheet's [hidden] { display: none }, so `display: flex` here
     silently un-hid the element: a full-viewport inset:0 overlay at opacity 0,
     invisible but swallowing every tap on the page — links, nav, all of it.
     Belt and braces, because a closed sheet being interactive is catastrophic
     rather than untidy: the attribute is honoured, AND pointer events are only
     granted while it is actually open. */
  .sheet[hidden] { display: none; }

  .sheet {
    position: fixed;
    inset: 0;
    z-index: 30;
    display: flex;
    align-items: flex-end;
    justify-content: flex-end;   /* corner, not centred, once there is room */
    padding: var(--margin);
    background: rgba(0, 0, 0, 0.55);
    opacity: 0;
    pointer-events: none;
    transition: opacity 240ms var(--ease);
    /* Stops the grey flash iOS paints over whatever is tapped. */
    -webkit-tap-highlight-color: transparent;
  }

  .sheet.on { opacity: 1; pointer-events: auto; }

  /* Rises from the bottom edge — the corner a thumb is already near, rather
     than the middle of the screen. Capped so a tablet gets the same object in
     its corner instead of a band stretched across the full width; on a phone
     the cap never binds and this is simply full width. */
  .sheet-panel {
    position: relative;
    width: 100%;
    max-width: 400px;
    background: #fff;
    padding: 22px var(--margin) var(--margin);
    transform: translateY(12px);
    transition: transform 240ms var(--ease);
  }

  .sheet.on .sheet-panel { transform: translateY(0); }

  /* Focused on open so the dialog owns the keyboard, but it is a container,
     not a control — the ring would read as the close button being selected. */
  .sheet-panel:focus { outline: none; }

  .sheet-close {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 30px;
    height: 30px;
    border: 0;
    background: none;
    color: #000;
    font: inherit;
    line-height: 1;
    cursor: pointer;
  }

  /* Keyboard focus keeps its ring; a tap does not draw one. */
  .sheet-close:focus:not(:focus-visible),
  .sheet-link:focus:not(:focus-visible) { outline: none; }

  .sheet-copy { max-width: 30em; margin-bottom: 18px; padding-right: 30px; }

  .sheet-links { display: flex; gap: 8px; }

  /* Black plates with the white arrow, the same object the cursor label is —
     which is also why arrow-tr.svg can be reused here without a second file. */
  .sheet-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex: 1;
    padding: 11px 13px;
    background: #000;
    color: #fff;
  }

  .sheet-link img { display: block; width: 14px; height: 14px; }
}

@media (pointer: coarse) {
  html, body, a { cursor: auto; }
  .cursor { display: none; }
}

/* Below this the four columns are too narrow for 14px copy, so the media takes
   the full width and column 4 stacks under it. */
@media (max-width: 900px) {
  /* The nav is a single 14px line, so it ends 14 * 1.35 below where it starts.
     Both the logo and the essay clear it by the same amount, which keeps the
     two templates starting their content on the same line. */
  :root { --nav-end: calc(var(--margin) + 19px); }

  html, body { overflow: auto; }
  /* The lower block claims at least 30% of the screen and the media or essay
     takes whatever is left. Sized from the bottom rather than the top so that
     floor is guaranteed: the minmax min holds it at 30svh, and auto lets it
     grow past that if the copy ever needs more. Both tracks are the same on
     either template, so the lower block starts on the same line whether the
     thing above it is the footage or the essay — sizing a track to its content
     is what made about sit higher than index. */
  .stage { grid-template-columns: 1fr; grid-template-rows: 1fr minmax(30svh, auto); height: auto; min-height: 100svh; }
  .media { grid-column: 1 / -1; margin: calc(var(--margin) * -1) calc(var(--margin) * -1) 0; }
  /* A portrait crop of 16:9 footage lands the Matterhorn's peak dead centre —
     straight behind the logo, where the difference blend sinks "ou" into the
     rock. Framed left so the peak clears the logo's right edge instead. */
  .media video { object-position: 21% 50%; }
  .essay-wrap { grid-column: 1 / -1; }
  .essay { width: auto; font-size: clamp(28px, 8.2vw, 32px); }
  .mark { width: 64px; }

  /* Static so the nav below can hang off .stage instead of this. .mid is
     already static at this width, so nothing else here relies on it.
     No top padding: that and the paragraph's 34px margin were holding a space
     for the nav, which now sits at the top of the page, so the copy starts at
     the top of the white area on the grid's own rhythm. */
  .col { grid-column: 1 / -1; padding-top: 0; position: static; }
  .col p { margin-top: var(--gutter); }

  /* The nav leads the page on mobile rather than sitting under the media.
     Absolute rather than fixed: the page scrolls at this width, and a pinned
     header would ride down over the copy. */
  .col > nav.row {
    position: absolute;
    top: var(--margin);
    left: var(--margin);
    right: var(--margin);
    z-index: 3;
  }

  /* On the hero it lies over the footage. White + difference so it stays
     legible whatever frame is under it, exactly as the logo does — and it
     blends against .media because .col is not a stacking context. Before the
     reveal, .media is still clipped away and the same rule renders it black
     against the page. */
  .media ~ .col > nav.row {
    color: #fff;
    mix-blend-mode: difference;
  }

  /* Pushed clear of the nav rather than sharing the top-left corner. */
  .logo { width: 61.6vw; top: calc(var(--nav-end) + 20px); }   /* 56vw + 10% */

  /* On about the nav has no backdrop to sit on, so the copy starts below it.
     Less the stage padding the grid item already carries. */
  .essay-wrap { padding-top: calc(var(--nav-end) + 20px - var(--margin)); }

  /* The systems row is desktop furniture — it belongs on the centre line of a
     full-height column, and there is no such line here. */
  .mid { display: none; }

  /* Copy at the top of the lower block, footer on the floor and ranged left
     with everything else at this width; the right alignment only reads as
     deliberate against a narrow column. */
  .foot { margin-top: auto; text-align: left; }
}
