/* ==========================================================================
   Starfish Group — about.css

   Built to the supplied layout: split hero, a dated timeline down the left
   with a spine and nodes, a pale band for manufacturing and quality, the
   CEO's message beside the company table, and a photographic close.

   An earlier version of this page threw the timeline away on the argument
   that a spine with two nodes on it is decoration rather than information.
   The brief asked for it, and asked for it to animate; the spine is back,
   there are three nodes, and assets/js/about.js draws it as you scroll.

   COLOUR. The reference is navy headings and a gold accent. Both exist in
   base.css already — --sea-deep is the navy and --dawn the gold — so nothing
   here is a new brand colour. The one addition is --dawn-ink, which is --dawn
   darkened until it can carry type, exactly as --coral-ink is to --coral;
   --dawn itself measures 1.55:1 on ivory and cannot be read.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Shared pieces

   ONE SIZE FOR RUNNING TEXT. Every paragraph, table cell, caption and role
   line on this page is --text-body, a step up from the 14px it was. It was three sizes — 14 in the timeline
   and the letter, 12 in the manufacturing points, the company table and the
   captions — and the 12s read as a mistake rather than as a hierarchy. What
   still differs is what should: the hero lede is --text-body-lg because it
   is the one sentence the page opens on, and labels are --text-micro,
   uppercase and tracked, which is a different kind of thing from a sentence.
   -------------------------------------------------------------------------- */
.ab-eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-micro);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dawn-ink);
}
/* The short gold rule under a heading — the reference's one recurring mark. */
.ab-rule {
  width: 44px;
  height: 2px;
  border: 0;
  margin: clamp(20px, 2.4vw, 30px) 0 0;
  background: var(--dawn-ink);
  opacity: 0.75;
}

/* --------------------------------------------------------------------------
   1. HERO
   Copy left on ivory, photograph right, bleeding off the edge of the window.
   -------------------------------------------------------------------------- */
.ah {
  position: relative;
  isolation: isolate;
  overflow: clip;
  background: var(--ivory);
}

/* THE PICTURE IS THE GROUND, AND THE SCRIM IS A GRADIENT RATHER THAN A FLAT
   OPACITY. Held back evenly the fish would have to sit at about 0.15 for navy
   type to clear AA over it, which is a photograph you cannot see. Weighted
   instead: near-solid ivory under the words on the left, clearing to the right
   where there is nothing but the picture. The copy reads on flat ivory and the
   raw material is still the thing the page opens on. */
.ah__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 60% 45%;
}
/* TWO GRADIENTS, BECAUSE THERE ARE TWO PROBLEMS. Across the frame, for the
   headline sitting on the left. And down it, for the facts row, which spans
   the full width and would otherwise put its third column and the scroll cue
   on open photograph. The picture is strongest where nothing is written: the
   upper right. */
.ah::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg,
      rgba(244, 240, 231, 0) 0%,
      rgba(244, 240, 231, 0) 48%,
      rgba(244, 240, 231, 0.55) 70%,
      rgba(244, 240, 231, 0.88) 86%,
      var(--ivory) 100%),
    linear-gradient(90deg,
      var(--ivory) 0%,
      var(--ivory) 30%,
      rgba(244, 240, 231, 0.94) 44%,
      rgba(244, 240, 231, 0.62) 68%,
      rgba(244, 240, 231, 0.34) 100%);
}

.ah__grid {
  position: relative;
  /* One column now the picture is behind rather than beside. The measure is
     what keeps the copy off the part of the frame where the fish shows. */
  max-width: var(--shell-max);
  padding-top: calc(var(--header-h) + clamp(40px, 8vh, 96px));
  padding-bottom: clamp(48px, 8vh, 96px);
  min-height: clamp(380px, 50vh, 540px);
  display: flex;
  align-items: center;
}
.ah__copy { position: relative; z-index: 1; max-width: 34rem; }
.ah__title {
  margin-top: clamp(14px, 1.6vw, 20px);
  max-width: 13ch;
  color: var(--sea-deep);
}
.ah__lede {
  margin-top: var(--s-24);
  font-size: var(--text-body-lg);
  line-height: var(--leading-body);
  color: var(--ink-soft);
  max-width: 42ch;
}

/* THE WAY DOWN. Centred on the section, at its foot. The arrow travels a few
   pixels on hover and breathes on its own otherwise — both transforms, both
   gone under prefers-reduced-motion, where it is simply a link. */
.ah__scroll {
  position: relative;
  z-index: 2;
  /* In the flow under the facts rather than pinned to the foot of the section,
     so it can never ride up over them however tall the row becomes. */
  margin: clamp(30px, 5vh, 56px) auto clamp(30px, 5vh, 56px);
  width: max-content;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-8);
  padding: 6px 10px;
  border-radius: 9999px;
  /* --sea-deep, not --ink-soft. This is the one control on the hero and it
     sits on the photograph rather than on the flat ivory the copy has; at
     --ink-soft it measured 3.10:1 over the fish on a phone. */
  color: var(--sea-deep);
  transition: opacity 200ms var(--ease-out);
}
.ah__scroll-text {
  /* It wraps to two lines on a phone, and a centred block of left-aligned
     lines is not a centred label. */
  text-align: center;
  font-family: var(--font-body);
  font-size: var(--text-micro);
  font-weight: 600;
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
}
.ah__scroll-arrow {
  display: block;
  width: 17px;
  animation: ah-nudge 2.4s var(--ease-out) infinite;
}
.ah__scroll-arrow svg { display: block; width: 100%; height: auto; }
.ah__scroll-text { border-bottom: 1px solid transparent; padding-bottom: 3px;
  transition: border-color 200ms var(--ease-out); }
.ah__scroll:hover .ah__scroll-text { border-bottom-color: currentColor; }
.ah__scroll:hover .ah__scroll-arrow { animation-play-state: paused; transform: translateY(3px); }
.ah__scroll:focus-visible {
  outline: 2px solid var(--sea-deep);
  outline-offset: 4px;
}
@keyframes ah-nudge {
  0%, 62%, 100% { transform: translateY(0); }
  78%           { transform: translateY(4px); }
}

/* --------------------------------------------------------------------------
   2. KEY FACTS
   Three readings off the same company, on the same ivory as the sections
   either side of it.

   NOT CARDS. A card is a thing you click and none of these goes anywhere, so
   what separates them is a hairline and the space around them — and the
   hairline is the palest teal in the palette, because it is a divider and not
   a border. No icons, no shadows, and the figures do not count up: this row
   sits directly under the headline and a number animating beside it would
   pull the eye off the sentence the page opens on.

   SUBORDINATE TO THE HEADLINE, which is the whole reason the figures are set
   at 30px against the h1’s 56. They are a fact each, not three more titles.
   -------------------------------------------------------------------------- */
.facts__grid {
  position: relative;
  max-width: var(--shell-max);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(24px, 4vw, 64px);
}
.facts__item + .facts__item {
  padding-left: clamp(24px, 4vw, 64px);
  border-left: 1px solid var(--seaglass-2);
}
.facts__figure {
  font-family: var(--font-display);
  font-size: clamp(21px, 2.1vw, 30px);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: var(--track-headline);
  color: var(--sea-deep);
}
.facts__label {
  margin-top: var(--s-8);
  font-size: var(--text-body);
  line-height: 1.5;
  /* --ink, not --ink-soft. These sit under the same photograph the headline
     does, and on a phone the row lands where the scrim has thinned: the two
     right-hand labels measured 4.31 and 3.71:1 there. */
  color: var(--ink);
  max-width: 26ch;
}

/* --------------------------------------------------------------------------
   2. THE TIMELINE
   Four columns: the period, the spine, the picture, the words. The spine is
   two lines on top of each other — a full-height track and a progress line
   scaled from nothing by about.js — so what animates is a transform.
   -------------------------------------------------------------------------- */
.tl { background: var(--ivory); }
.tl__inner { position: relative; }

.tl__row {
  display: grid;
  grid-template-columns:
    clamp(56px, 8vw, 94px)             /* the period  */
    22px                               /* the spine   */
    minmax(0, 0.78fr)                  /* the picture */
    minmax(0, 1fr);                    /* the words   */
  gap: clamp(20px, 2.6vw, 40px);
  align-items: start;
}
.tl__row + .tl__row { margin-top: clamp(40px, 6vh, 72px); }

.tl__when {
  font-family: var(--font-body);
  font-size: var(--text-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--sea-deep);
  text-align: right;
  padding-top: 4px;
  line-height: 1.3;
}

/* --- the spine ------------------------------------------------------------
   Positioned against .tl__inner rather than drawn per row, so it is one
   continuous line and not three segments that have to be made to meet. */
.tl__spine {
  position: absolute;
  top: 8px;
  bottom: 0;
  /* the middle of the second column: first column + the gap + half of 22 */
  /* AND THE SHELL’S PADDING. An absolutely positioned child resolves left
     against the padding box, which on .shell starts 40px outside the column
     the grid actually lays out in — so the line drew exactly one --shell-pad
     to the left of every node it was supposed to run through. The first term
     is the same expression the grid’s first column uses, which is why that
     column is a clamp and not a minmax: the two have to agree exactly. */
  left: calc(var(--shell-pad) + clamp(56px, 8vw, 94px) + clamp(20px, 2.6vw, 40px) + 11px);
  width: 2px;
  pointer-events: none;
}
.tl__track,
.tl__draw {
  position: absolute;
  inset: 0;
  border-radius: 2px;
}
.tl__track { background: var(--sea-deep); opacity: 0.16; }
/* Scaled from the top by about.js. Full height without JS, so the line is
   never missing — only ever un-animated. */
.tl__draw {
  background: var(--sea-deep);
  transform-origin: top center;
  /* and it fades away at the foot, as in the reference */
  -webkit-mask-image: linear-gradient(180deg, #000 84%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 84%, transparent 100%);
}

.tl__node {
  position: relative;
  width: 22px;
  height: 22px;
  margin-top: 2px;
  display: grid;
  place-items: center;
}
.tl__node::before {
  content: "";
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--ivory);
  border: 2px solid var(--sea-deep);
  opacity: 0.4;
  transform: scale(0.7);
  transition: transform 420ms var(--ease-out), opacity 420ms var(--ease-out),
              background-color 420ms var(--ease-out);
}
.tl__node.is-on::before {
  background: var(--sea-deep);
  opacity: 1;
  transform: scale(1);
}
/* The last node stays open in the reference. Today has not closed. */
.tl__row--now .tl__node.is-on::before { background: var(--ivory); opacity: 0.9; }

.tl__figure { margin: 0; }
.tl__figure img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 20px;   /* an image in a layout */
}
.tl__caption {
  margin-top: var(--s-8);
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--ink-meta);
}

.tl__title {
  font-family: var(--font-display);
  font-size: clamp(21px, 2vw, 27px);
  font-weight: 600;
  line-height: 1.16;
  letter-spacing: var(--track-headline);
  color: var(--sea-deep);
  max-width: 22ch;
}
.tl__body { margin-top: var(--s-16); }
.tl__body > * + * { margin-top: var(--s-12); }
.tl__body p {
  font-size: var(--text-body);
  line-height: 1.7;
  color: var(--ink-soft);
  max-width: 54ch;
}
/* The one line in the row that is not ordinary. */
.tl__point {
  margin-top: var(--s-16);
  font-size: var(--text-body);
  line-height: 1.6;
  font-weight: 600;
  color: var(--sea-deep);
}

/* The two companies, inside the growth row, divided the way the reference
   divides them — and carrying their own marks, which the reference does not
   have room for but the brief asked for. */
.tl__firms {
  margin-top: clamp(20px, 2.4vw, 28px);
  padding-top: var(--s-20);
  border-top: 1px solid var(--border);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(18px, 2.4vw, 30px);
}
.tl__firm + .tl__firm {
  padding-left: clamp(18px, 2.4vw, 30px);
  border-left: 1px solid var(--border);
}
/* One box height, two artwork sizes: the filled tile and the line-drawn star
   do not weigh the same at the same height, and the names below have to line
   up with each other. */
.tl__firm img {
  display: block;
  /* 44, not 32. The Starfoods mark carries its own wordmark under the star,
     and at 32 that word was five pixels tall — present, and unreadable. */
  height: 44px;
  object-fit: contain;
  object-position: left center;
  margin-bottom: var(--s-12);
}
.tl__firm img.is-tile { width: 36px; }
.tl__firm img.is-word { width: 55px; }
.tl__firm b {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-body);
  font-weight: 600;
  letter-spacing: var(--track-headline);
  color: var(--sea-deep);
}
.tl__firm span {
  display: block;
  margin-top: 4px;
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--ink-soft);
}

/* --------------------------------------------------------------------------
   3. MANUFACTURING AND QUALITY
   The pale band. Heading, picture, and two points side by side.
   -------------------------------------------------------------------------- */
/* THE PHOTOGRAPH IS THE GROUND, NOT A COLUMN. It was a picture in the middle
   of the row; it is the band itself now.

   AND IT STAYS PALE. The obvious move is a dark wash and cream type, but the
   closing section three screens down is already a dark photograph with cream
   type on it, and two of those in one page makes the second one ordinary.
   The seaglass ground stays and the picture sits under it at low opacity, so
   the band still reads as the pale band the layout wants while the lab is
   legible behind the words. Opacity rather than a filter: the seaglass shows
   through evenly and nothing darkens under the copy.

   0.16 AND A DARKER INK, both measured. The lab is a bright room, so the risk
   is not its highlights but the few near-black objects in it — a worker’s hair,
   the shadow under the bench — pulling the ground down towards the type on it.
   At 0.2 with --ink-soft the two points measured 3.94 and 4.08:1, which is a
   fail. Dropping the picture far enough on its own would have taken it to 0.10
   and left barely anything to see, so the copy in this band takes --ink
   instead: 8.3:1 over the darkest pixel under a glyph, and the photograph
   stays visible. It is the only section where the body copy is not
   --ink-soft, and the reason is the photograph. */
.mq {
  position: relative;
  isolation: isolate;
  overflow: clip;
  background: var(--seaglass);
  padding-block: clamp(64px, 10vh, 128px);
}
.mq__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 42%;
  opacity: 0.16;
  pointer-events: none;
}
.mq__grid {
  position: relative;
  display: grid;
  /* Two columns, not three. The picture left the row when it became the
     ground, and the two points became one account. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  gap: clamp(28px, 4vw, 64px);
  align-items: start;
}
.mq__title {
  margin-top: var(--s-16);
  font-family: var(--font-display);
  /* 32, not 38. It used to be three words; it is a sentence now, and at 38 it
     ran to five lines in the column that heads the band. */
  font-size: clamp(23px, 2.3vw, 32px);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: var(--track-headline);
  color: var(--sea-deep);
  max-width: 18ch;
}
.mq__body > * + * { margin-top: var(--s-20); }
.mq__body p {
  font-size: var(--text-body);
  line-height: 1.7;
  /* --ink, as everywhere else in this band: the copy sits on the photograph
     rather than on flat seaglass, and --ink-soft measured under 4.5:1 over the
     darkest of it. */
  color: var(--ink);
  max-width: 60ch;
}

/* --------------------------------------------------------------------------
   4. THE CEO'S MESSAGE, AND THE COMPANY TABLE
   -------------------------------------------------------------------------- */
.msg { background: var(--cream); }
.msg__grid {
  display: grid;
  /* TWO COLUMNS, NOT THREE. Sharing the row with the company table left the
     portrait 168px wide, which is a thumbnail of a man rather than a
     photograph of one. The table has its own section below now, and the
     picture has twice the width it had. */
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.5fr);
  gap: clamp(28px, 4vw, 64px);
  align-items: start;
}

/* THE PORTRAIT. The frame keeps the reference’s 4:5 against a source that is
   0.70:1 — taller than the frame rather than wider — so cover crops top and
   bottom instead of the sides, 191px of 1501. object-position decides where
   that goes: at 34% it took 65px off the top and left only 36px of headroom
   above his hair. 20% takes 38px and the crop stays well clear. */
.msg__portrait {
  margin: 0;
  aspect-ratio: 4 / 5;
  border: 1px solid var(--border);
  border-radius: 20px;
  overflow: hidden;
}
.msg__portrait img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 20%;
}
.msg__quote {
  margin-top: var(--s-16);
  max-width: 30ch;
  font-family: var(--font-display);
  font-size: clamp(21px, 2vw, 27px);
  font-weight: 600;
  line-height: 1.24;
  letter-spacing: var(--track-headline);
  color: var(--sea-deep);
  /* Hanging punctuation, so the opening mark does not push the first word out
     of line with everything below it. */
  text-indent: -0.44em;
}
.msg__body { margin-top: clamp(18px, 2.2vw, 26px); }
.msg__body > * + * { margin-top: var(--s-12); }
.msg__body p {
  /* 14px and a measure, not 12px across the full column. With the table
     gone the copy has 720px to run in, which at caption size is a hundred
     and five characters a line — about twice a comfortable measure. */
  font-size: var(--text-body);
  line-height: 1.7;
  color: var(--ink-soft);
  max-width: 62ch;
}
.msg__sign {
  margin-top: clamp(20px, 2.4vw, 30px);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px var(--s-12);
  font-family: var(--font-body);
  /* A name and a title, not a caption. */
  font-size: var(--text-body);
}
.msg__sign b { font-weight: 600; color: var(--sea-deep); }
.msg__sign span { color: var(--ink-meta); }
.msg__sign i { font-style: normal; color: var(--border-dark); }

/* --------------------------------------------------------------------------
   5. COMPANY AT A GLANCE
   Heading left, the facts right — the same shape the manufacturing band uses,
   so the page has one way of setting a titled block and not two.
   -------------------------------------------------------------------------- */
.glance { background: var(--ivory); }
.glance__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.62fr) minmax(0, 2fr);
  gap: clamp(24px, 3.4vw, 56px);
  align-items: start;
}
.glance__title {
  font-family: var(--font-display);
  /* 27, not 30. At 30 the line broke after “at a” and left “glance” on its
     own; 27 fits the whole title inside the column it heads. */
  font-size: clamp(21px, 2vw, 27px);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: var(--track-headline);
  color: var(--sea-deep);
}

/* EIGHT FACTS IN TWO COLUMNS, READ DOWNWARDS. grid-auto-flow: column with a
   fixed four rows, so the first four run down the left and the rest down the
   right — a plain two-column grid would flow them across, which is how you
   read a table and not how you read a list. */
.glance__list {
  margin: 0;
  display: grid;
  grid-template-rows: repeat(4, auto);
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  column-gap: clamp(24px, 3.4vw, 48px);
  border-top: 1px solid var(--border);
}
.glance__list > div {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: var(--s-16);
  padding-block: var(--s-16);
  border-bottom: 1px solid var(--border);
}
.glance__list dt,
.glance__list dd {
  margin: 0;
  font-size: var(--text-body);
  line-height: 1.6;
}
.glance__list dt { color: var(--ink-soft); }
.glance__list dd { color: var(--sea-deep); }
.glance__list dd span { display: block; color: var(--ink-soft); }

/* --------------------------------------------------------------------------
   5. THE CLOSE
   The port at dusk, with the ask on it.
   -------------------------------------------------------------------------- */
/* THE PICTURE ON THE LEFT, THE ASK ON THE RIGHT, AND THE JOIN IS A FADE.
   The photograph is masked out towards the right rather than covered over
   there: a scrim heavy enough to carry cream type would have sat on the
   picture as a grey panel, where a mask simply ends it. What the words are on
   by the time they start is the section’s own ground.

   The ground is --ink-deep and the type is cream, as it was. The band is the
   last thing on the page and the only dark one; making it light to suit a
   bright supermarket photograph would have left the page with no ending. */
.close-band {
  position: relative;
  isolation: isolate;
  overflow: clip;
  background: var(--ink-deep);
  padding-block: clamp(72px, 11vh, 150px);
  /* The picture is the taller half of this band. Given only the height the
     copy needs, a portrait crop in a wide strip has to be scaled up hard to
     cover it, and almost nothing of the photograph survives. */
  min-height: 600px;
  display: grid;
  align-items: center;
}
/* THE PICTURE IS NOT STRETCHED ACROSS THE WHOLE BAND. Covering 1440px of band
   with the photograph scales it to 0.8 and throws away well over half the
   frame. Held to the copy column and given a taller band it scales to 0.7 and
   keeps two thirds — less zoom, more picture. The column edge is also where
   the picture now stops, so it no longer passes behind the words. */
.close-band__bg {
  position: absolute;
  inset: 0 auto 0 0;
  z-index: -2;
  width: 50%;
  height: 100%;
  object-fit: cover;
  object-position: 46% 42%;
  /* Percentages re-based on the narrower box, so the fade still lands at the
     same place across the band as it did before. */
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 58%, transparent 100%);
          mask-image: linear-gradient(90deg, #000 0%, #000 58%, transparent 100%);
}
/* Lighter than it was. Nothing is read over the photograph any more, so the
   scrim only has to sit a bright aisle in the band’s key — and it is solid by
   the time the copy column starts. */
.close-band::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(90deg,
    rgba(9, 28, 37, 0.34) 0%,
    rgba(9, 28, 37, 0.30) 28%,
    rgba(9, 28, 37, 0.60) 42%,
    var(--ink-deep) 52%);
}
.close-band__grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(24px, 4vw, 64px);
  align-items: center;
}
.close-band__copy { grid-column: 2; }
.close-band .ab-eyebrow { color: var(--dawn); }
.close-band__title {
  margin-top: var(--s-16);
  font-family: var(--font-display);
  font-size: clamp(28px, 3vw, 42px);
  font-weight: 600;
  line-height: 1.06;
  letter-spacing: var(--track-headline);
  color: var(--cream);
  max-width: 16ch;
}
.close-band__body {
  margin-top: var(--s-20);
  font-size: var(--text-body);
  line-height: 1.7;
  color: rgba(245, 242, 236, 0.86);
  max-width: 46ch;
}
.close-band__cta {
  display: inline-flex;
  align-items: center;
  gap: var(--s-12);
  margin-top: clamp(24px, 3vw, 34px);
  font-family: var(--font-body);
  font-size: var(--text-small);
  font-weight: 500;
  color: var(--cream);
  padding-bottom: 6px;
  border-bottom: 1px solid rgba(245, 242, 236, 0.4);
  transition: border-color 220ms var(--ease-out);
}
.close-band__cta .btn__arrow { transition: transform 260ms var(--ease-out); }
.close-band__cta:hover { border-color: var(--cream); }
.close-band__cta:hover .btn__arrow { transform: translateX(4px); }
.close-band__cta:focus-visible { outline: 2px solid var(--cream); outline-offset: 4px; }

/* --------------------------------------------------------------------------
   NARROWER
   -------------------------------------------------------------------------- */
@media (max-width: 1080px) {
  .mq__grid { grid-template-columns: minmax(0, 1fr); gap: clamp(24px, 4vw, 40px); }
  .glance__grid { grid-template-columns: minmax(0, 1fr); }
  .glance__title { max-width: none; }
}

@media (max-width: 860px) {
  /* Stacked, and the separators go with the columns — a rule down the left of
     a stack points at nothing. */
  .facts__grid { grid-template-columns: minmax(0, 1fr); gap: clamp(20px, 5vw, 30px); }
  .facts__item + .facts__item { padding-left: 0; border-left: 0; }
  .facts__label { max-width: none; }

  /* The scrim turns to run down the page rather than across it, because the
     copy is now above the picture rather than beside it. */
  /* SOLID UNDER THE WORDS, CLEARING BELOW THEM. The desktop scrim runs across
     the frame because the copy is on the left; stacked, it has to run down it.
     At 0.74 by 78% the lede measured 4.14:1 and the scroll cue 3.10 — the copy
     had drifted onto the picture. Solid to 58% now, which is past the last
     line, and the fish has the bottom third to itself. */
  .ah::after {
    background: linear-gradient(180deg,
      var(--ivory) 0%,
      var(--ivory) 58%,
      rgba(244, 240, 231, 0.88) 74%,
      rgba(244, 240, 231, 0.74) 100%);
  }
  .ah__grid { min-height: clamp(520px, 76vh, 680px); align-items: flex-start; }
  .ah__copy { max-width: none; }
  .ah__title { max-width: 18ch; }

  /* THE SPINE STAYS, AND MOVES TO THE EDGE. Dropping it on a phone would lose
     the one device saying these three blocks are a sequence, which is the
     whole reason this section is a timeline and not three cards. The period
     moves up beside its node and the picture spans the copy. */
  .tl__row {
    grid-template-columns: 22px minmax(0, 1fr);
    gap: var(--s-16) var(--s-20);
  }
  .tl__spine { left: calc(var(--shell-pad) + 11px); }
  .tl__node  { grid-row: 1; grid-column: 1; }
  .tl__when  { grid-row: 1; grid-column: 2; text-align: left; padding-top: 3px; }
  .tl__figure { grid-column: 2; }
  .tl__copy   { grid-column: 2; }
  .tl__title  { max-width: none; }

  .mq__grid { grid-template-columns: minmax(0, 1fr); }
  .mq__title { max-width: 24ch; }
  .mq__body p { max-width: none; }
  .msg__grid { grid-template-columns: minmax(0, 1fr); }
  .msg__portrait { max-width: 300px; }
  .glance__list { grid-auto-flow: row; grid-template-rows: none; }
  /* Stacked, the picture takes the top and the words sit under it, so both
     the mask and the scrim turn to run down the band rather than across it. */
  .close-band__grid { grid-template-columns: minmax(0, 1fr); }
  .close-band__copy { grid-column: 1; }
  .close-band { padding-top: clamp(214px, 56vw, 330px); min-height: 0; display: block; }
  /* Stacked, the picture gets a band of its own rather than covering the
     whole section. Covering it meant an 1200x1300 crop scaled to fill 586px of
     height, which showed the tops of two heads and nothing else; sized to the
     strip it actually occupies it scales to 0.31 and the scene reads. */
  .close-band__bg {
    inset: 0 0 auto 0;
    width: 100%;
    height: 42%;
    object-position: 50% 34%;
    -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 56%, transparent 100%);
            mask-image: linear-gradient(180deg, #000 0%, #000 56%, transparent 100%);
  }
  /* The band gained top padding so the photograph has room to be seen, and
     the scrim closes earlier to match: solid before the eyebrow, so nothing is
     read over the picture here either. */
  .close-band::after {
    background: linear-gradient(180deg,
      rgba(9, 28, 37, 0.34) 0%,
      rgba(9, 28, 37, 0.30) 15%,
      rgba(9, 28, 37, 0.62) 27%,
      var(--ink-deep) 38%);
  }
  .close-band__title { max-width: 20ch; }
}

@media (max-width: 560px) {
  .tl__firms { grid-template-columns: minmax(0, 1fr); }
  .tl__firm + .tl__firm {
    padding-left: 0;
    border-left: 0;
    padding-top: var(--s-16);
    border-top: 1px solid var(--border);
  }
  .glance__list > div { grid-template-columns: minmax(0, 1fr); gap: 4px; }
}

@media (prefers-reduced-motion: reduce) {
  .tl__node::before,
  .close-band__cta,
  .close-band__cta .btn__arrow { transition: none; }
  .close-band__cta:hover .btn__arrow { transform: none; }
}
