/* ==========================================================================
   Starfish Group — reach.css
   Export markets.

   TWO COLUMNS, NOT ONE COMPOSITION. The previous version set the copy over the
   map and masked the map out beneath the words. It read well, but headline and
   graphic were competing for the same ground. Now the copy owns the left two
   fifths and the map the right three, and the dot field runs under both —
   invisible where the copy is, resolving as it crosses to where the routes are.

   The dot map is a static SVG generated offline with dotted-map; the library is
   a build-time tool here, not something the site ships. It is drawn twice, one
   world width apart, so the Pacific falls between the two copies. A single copy
   sends the Thailand-to-US arc west across Europe, which is the wrong ocean.

   Dots and routes share one SVG and one viewBox on purpose. Split into two
   elements the pins stop sitting on the countries they name, and a map whose
   points are not where the places are is a decoration pretending to be a map.
   ========================================================================== */

.reach {
  position: relative;
  overflow: clip;
  /* More room than the sections either side. The brief for this one was air,
     and the map needs the height as much as the copy does. */
  padding-block: clamp(80px, 11vh, 132px);
  /* THE LIGHTEST GROUND ON THE PAGE, and warm rather than blue. Cream would
     have been a hair off the ivory of the section above and the boundary
     would have disappeared; this is a clear step up in lightness from it, and
     everything on the map gains contrast against it rather than losing any. */
  background: var(--surface-card);
}

/* --------------------------------------------------------------------------
   THE GROUND
   Full bleed, behind everything, and untouchable except at the pins.
   -------------------------------------------------------------------------- */
.reach__figure {
  position: absolute;
  inset: 0;
  z-index: 0;
  margin: 0;
  display: grid;
  align-content: center;
  /* The map covers the copy's half of the section too, so left to itself it
     would swallow every click and text selection over there. Only the pins'
     hit discs take the pointer back. */
  pointer-events: none;
}

.reach__map {
  display: block;
  width: 100%;
  height: clamp(420px, 46vw, 620px);
}

/* Faint to start with — the mask in the markup takes it to nothing on the left
   and full on the right, and this is what "full" means. */
.reach__dots {
  opacity: 0.34;
  filter: saturate(0.5);
}

/* --------------------------------------------------------------------------
   THE COPY
   Two fifths of the width, and the only thing on this side of the section.
   -------------------------------------------------------------------------- */
.reach__inner {
  position: relative;
  z-index: 1;
  /* THE EMPTY COLUMN MUST NOT SWALLOW THE MAP. This grid spans the whole shell
     and sits above the figure, so column two — which has nothing in it and
     exists only to hold the map's space — was taking every pointer event
     before it reached a pin. The copy takes the pointer back. */
  pointer-events: none;
  display: grid;
  grid-template-columns: minmax(0, 43fr) minmax(0, 57fr);
  align-items: center;
}

.reach__copy {
  grid-column: 1;
  /* Nothing in column two: the map shows through it. */
  pointer-events: auto;
}

/* A short rule under the eyebrow, which is the one place the accent appears in
   the copy. It replaces nothing — the old version had the eyebrow alone and it
   floated. */
.reach__tag { position: relative; padding-bottom: var(--s-16); }
.reach__tag::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 34px;
  height: 2px;
  background: var(--coral);
}

/* THE DOMINANT ELEMENT. Two lines, set larger than the section headings either
   side of it, because the hierarchy this section was asked for starts here. */
.reach__heading {
  margin-top: var(--s-16);
  font-size: clamp(29px, 3.3vw, 47px);
  line-height: 1.1;
  /* TWO LINES, as briefed, and the <br> is what sets the break. 15ch was
     narrower than 'Ready for your market.' and forced a third. */
  max-width: 24ch;
  text-wrap: balance;
}

.reach__lede {
  margin-top: clamp(20px, 2.4vw, 28px);
  font-size: clamp(15px, 1.15vw, 17px);
  line-height: 1.72;
  color: var(--ink-soft);
  /* Narrower than the headline. It is fourth in the hierarchy and should not
     be the widest thing in the column. */
  max-width: 36ch;
}

/* --------------------------------------------------------------------------
   THE PROOF ROW
   One row, three groups, weighted: the year is the proof, the market count
   supports it, the certifications are a footnote a buyer checks rather than a
   thing to announce. Divided by hairlines, not boxes.
   -------------------------------------------------------------------------- */
.reach__proof {
  margin-top: clamp(32px, 4vw, 52px);
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: clamp(14px, 1.8vw, 24px);
  /* IT MAY RUN WIDER THAN THE PROSE. Three groups need about 520px and the
     copy column is 481, so inside it the certifications wrapped to a second
     line and the brief asked for one row. Column two is empty — the map shows
     through it — so the row is allowed to reach into it. It ends around 680px
     and Thailand sits at 745, so it never reaches the graphic. */
  width: max-content;
  /* 560, not 600. At 600 the certifications ran to 720px and the Singapore
     label began at 719 — the two were touching. */
  max-width: min(560px, 100vw - 2 * var(--shell-pad));
}
.reach__stat + .reach__stat {
  padding-left: clamp(14px, 1.8vw, 24px);
  border-left: 1px solid var(--border);
}

.reach__stat dd {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(26px, 2.5vw, 36px);
  line-height: 1;
  letter-spacing: var(--track-display);
  color: var(--coral-ink);
}
.reach__stat dt {
  margin-top: var(--s-8);
  font-family: var(--font-body);
  font-size: var(--text-micro);
  font-weight: 600;
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
  color: var(--ink-meta);
}

/* QUIETER, AND DELIBERATELY SO. Three stamps rather than a third big figure —
   three equal numbers would be three claims of equal weight, and only two of
   them are claims. */
.reach__certs {
  display: flex;
  flex-wrap: nowrap;
  gap: 6px;
  /* Sits down on the figures' baseline rather than floating above them. */
  padding-top: clamp(6px, 1vw, 12px);
}
.reach__cert {
  display: inline-flex;
  align-items: center;
  padding: 5px 10px;
  border: 1px solid var(--border-dark);
  /* A pill, which is a radius the system already has. */
  border-radius: 9999px;
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.11em;
  line-height: 1;
  white-space: nowrap;
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   ROUTES
   Drawn with stroke-dashoffset. reveal.js sets --len per path from its own
   measured length, so the draw works whatever the geometry is.
   -------------------------------------------------------------------------- */
.reach__arc {
  fill: none;
  stroke: var(--teal);
  /* Thin, and thinner than before. Five lines at the old weight read as a
     logistics diagram; at this weight they read as journeys. */
  stroke-width: 0.14;
  stroke-opacity: 0.5;
  stroke-linecap: round;
  stroke-dasharray: var(--len, 200);
  stroke-dashoffset: var(--len, 200);
}

/* The Pacific crossing. SAME WEIGHT AS THE REST — it was 0.26 against 0.14 and
   read as a different class of line rather than a longer one. What still sets
   it apart is opacity and the distance it travels, which is prominence enough
   without a second stroke width on the map. */
.reach__arc--far {
  stroke-opacity: 0.88;
}

.is-drawn .reach__arc {
  animation: reach-draw 1500ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 160ms);
}
@keyframes reach-draw { to { stroke-dashoffset: 0; } }

/* --------------------------------------------------------------------------
   PINS
   -------------------------------------------------------------------------- */
/* A four-pixel circle is not a hover target. Each pin carries an invisible
   disc several times its size, and that disc is the only part of the map that
   takes the pointer at all. */
.reach__hit {
  fill: transparent;
  pointer-events: auto;
  cursor: default;
}

.reach__dot {
  fill: var(--teal);
  opacity: 0.8;
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 280ms var(--ease-out), opacity 280ms var(--ease-out);
}
.reach__dot--far { opacity: 1; }

/* The ring that goes once when you find a city. Drawn at the dot's own radius
   so it starts exactly on its edge, and it only exists on hover — a map with
   five things pulsing at rest is an airport departure board. */
.reach__ping {
  fill: none;
  stroke: var(--teal);
  stroke-width: 0.12;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}
.reach__pin:hover .reach__dot,
.reach__pin:focus-within .reach__dot { transform: scale(1.75); opacity: 1; }
.reach__pin:hover .reach__ping,
.reach__pin:focus-within .reach__ping { animation: reach-ping 900ms var(--ease-out); }

@keyframes reach-ping {
  0%   { opacity: 0.55; transform: scale(1); }
  100% { opacity: 0;    transform: scale(4.2); }
}

/* The label comes up with its own dot, so hovering says which name belongs to
   which point without anything changing position. Matched on data-i rather
   than on order: every pin is drawn before every label, so the sibling
   selector this started as never matched anything. */
.reach__map:has(.reach__pin[data-i="0"]:hover) .reach__label[data-i="0"],
.reach__map:has(.reach__pin[data-i="1"]:hover) .reach__label[data-i="1"],
.reach__map:has(.reach__pin[data-i="2"]:hover) .reach__label[data-i="2"],
.reach__map:has(.reach__pin[data-i="3"]:hover) .reach__label[data-i="3"],
.reach__map:has(.reach__pin[data-i="4"]:hover) .reach__label[data-i="4"] {
  fill: var(--ink);
  font-weight: 600;
}

/* The origin. Coral, larger than every destination, ringed — so Thailand reads
   as the source at a glance rather than as the busiest node in a network. */
.reach__hub  { fill: var(--coral); }
.reach__ring { stroke: var(--coral); stroke-width: 0.11; stroke-opacity: 0.4; }
.reach__halo {
  fill: var(--coral);
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

.is-drawn .reach__pin--hub .reach__halo {
  animation: reach-pulse 3600ms var(--ease-out) infinite;
  animation-delay: 400ms;
}
@keyframes reach-pulse {
  0%   { opacity: 0.28; transform: scale(1); }
  70%  { opacity: 0;    transform: scale(2.6); }
  100% { opacity: 0;    transform: scale(2.6); }
}

/* --------------------------------------------------------------------------
   LABELS
   Anchored away from their own pin and off each other's rows: China above its
   dot, Taiwan and Japan to the right on different lines, Singapore below,
   the United States reading back into the composition from the right edge.
   -------------------------------------------------------------------------- */
.reach__label {
  font-family: var(--font-body);
  /* VIEWBOX UNITS, NOT PIXELS. The window is 97 units across roughly 1120px,
     so the scale is about 11.5 and a value near 1 is a 12px label. */
  font-size: 0.96px;
  font-weight: 500;
  letter-spacing: 0.02px;
  fill: var(--ink-soft);
  opacity: 0;
  pointer-events: none;
  transition: fill 220ms var(--ease-out);
}

.is-drawn .reach__label {
  animation: reach-fade 700ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 160ms + 720ms);
}
@keyframes reach-fade { to { opacity: 1; } }

.reach__label--far { fill: var(--ink); font-weight: 600; }

.reach__label--hub {
  font-size: 1.22px;
  font-weight: 600;
  fill: var(--ink);
  animation-delay: 240ms !important;
}

/* --------------------------------------------------------------------------
   NARROWER
   The map stops being a second column and becomes a band under the copy. Below
   that it goes entirely: five routes across a phone is a smear, and the copy
   already names every market.
   -------------------------------------------------------------------------- */
@media (max-width: 1060px) {
  /* THE SECTION BECOMES A COLUMN so the map can be ordered below the copy.
     The figure is written before the shell in the markup — it has to be, it is
     the ground — so taken out of absolute positioning it landed above the
     headline until this put it back. */
  .reach { display: flex; flex-direction: column; }
  .reach__inner { grid-template-columns: minmax(0, 1fr); order: 1; }
  .reach__copy { max-width: 46ch; }
  .reach__figure {
    position: static;
    order: 2;
    margin-top: clamp(28px, 4vw, 44px);
  }
  .reach__map { height: clamp(320px, 42vw, 420px); }
  .reach__dots { opacity: 0.26; }
}

@media (max-width: 620px) {
  /* THE MAP GOES. Five routes and six labels across 375px is a smear — the
     labels were landing on each other and on their own dots — and the copy
     already names every market it would have shown. The dot field goes with
     it rather than being left behind as texture with nothing on it. */
  .reach__figure { display: none; }

  /* On a phone there is no empty column to lean into, so the row wraps after
     all and the certifications take their own line under a rule. */
  .reach__proof { flex-wrap: wrap; width: auto; gap: var(--s-24); }
  .reach__stat + .reach__stat { padding-left: var(--s-24); }
  .reach__stat--cert {
    flex-basis: 100%;
    padding-left: 0 !important;
    border-left: 0 !important;
    padding-top: var(--s-20);
    border-top: 1px solid var(--border);
  }
  .reach__stat--cert dd { padding-top: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .is-drawn .reach__arc,
  .is-drawn .reach__label,
  .is-drawn .reach__pin--hub .reach__halo { animation: none; }
  .reach__arc { stroke-dashoffset: 0; }
  .reach__label { opacity: 1; }
  .reach__dot, .reach__label { transition: none; }
  .reach__pin:hover .reach__dot,
  .reach__pin:focus-within .reach__dot { transform: none; }
  .reach__pin:hover .reach__ping,
  .reach__pin:focus-within .reach__ping { animation: none; }
}
