/* ============================================================================
   REACH — between sections 4 and 5, on white. The section head, then two
   columns from the same line. Left: the panel, a tour of the engagements
   with photographs until a country on the map is picked, then that
   country's engagement, faded in (render/reach.js, behaviour/reach.js).
   Right: the world map, reaching into the right-hand margin, each country
   with engagements filled, as on the alumni portal's map. Picking one
   fades the rest and shows its points, one per place; a place with
   several engagements shows their number on a larger point, and the
   panel's arrows step through them. Until then only the tour's point
   shows. Points of one country that would overlap on screen are nudged
   apart (behaviour/reach.js). Above the map, a row of filter pills
   narrows the map, the tour and the steps to one experience.
   The conduit runs down the left margin beside this section on its way to
   the alumni band, so the text column starts clear of it (--reach-left),
   as the figure sections' does.

   designv2.1 §0: Class A · light · no analytical claim (a record of where
   engagements took place), so §3.3 does not bind: the points carry no
   signal colour, only the action colour.

   Recorded exceptions, to raise with the client:
   - §21 lists map styling as a known gap (no tokens for land, borders or
     markers). The tier-3 tokens below are drawn from the purple ramp and
     the page's own violet, as on the alumni portal's map: land in the
     hub's pill tone, borders in the canvas, countries with engagements in
     the action colour, the picked or pointed-at country in purple-900
     ringed in the orbit rings' violet. The points are canvas white, with
     an ink count and hairline, to stand out on any of those fills; the
     picked point is ringed in the violet.
   - §13.2 asks for 44px touch targets. The countries are the first target;
     the points shown on a picked country are 24px, the WCAG 2.2 AA
     minimum. Every country and engagement can also be reached by
     keyboard.
   ========================================================================= */

.reach {
  /* tier-3, scoped */
  --reach-left:  max(var(--conduit-lane), calc((100% - var(--layout-container-max)) / 2 + var(--space-6)));
  --reach-right: max(var(--space-6), calc((100% - var(--layout-container-max)) / 2 + var(--space-6)));
  --reach-text:  min(380px, 32vw);
  --reach-land:   color-mix(in srgb, var(--purple-100) 50%, var(--purple-050));
  --reach-match:  var(--color-action-primary);
  --reach-picked: var(--purple-900);
  --reach-ring:   color-mix(in srgb, var(--graphic-violet) 45%, var(--purple-300));
  /* With a country picked, the rest of the map, faded towards the canvas */
  --reach-land-faded:  color-mix(in srgb, var(--reach-land) 45%, var(--color-canvas));
  --reach-match-faded: color-mix(in srgb, var(--reach-match) 35%, var(--reach-land));
  --reach-count:    0.5625rem;   /* 9px, the number in a group dot */
  --reach-count-sm: 0.5rem;      /* 8px, the same below 720px */
  padding: var(--space-section) var(--reach-right) var(--space-section) var(--reach-left);
  background: var(--color-canvas);
}

.reach__frame {
  display: grid;
  grid-template-columns: var(--reach-text) minmax(0, 1fr);
  grid-template-areas:
    "head  head"
    "panel map";
  column-gap: var(--space-12);
  row-gap: var(--space-12);
}

/* --- the head ------------------------------------------------------------ */
.reach__head { grid-area: head; max-width: var(--layout-container-narrow); }
.reach__lead {
  margin: var(--space-4) 0 0;
  font-size: var(--type-lead);
  line-height: 1.65;
  color: var(--color-body);
}

/* --- the map ------------------------------------------------------------- */
.reach__map {
  grid-area: map;
  align-self: start;
  margin-right: calc(var(--reach-right) * -1 + var(--space-6));
}

/* The experience filter, in one line above the map (wrapping only where
   the column is too narrow): §10.2 filter pills, {radius.pill}, 1px
   hairline, at the 44px of the §13.2 floor. The chosen one is pressed, in
   the action colour; none pressed shows all. None is ever disabled. */
.reach__filters {
  display: flex; flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
}
.reach__filter {
  min-height: 44px;
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--color-hairline);
  color: var(--color-ink);
  font-family: inherit;
  font-size: var(--type-label);
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition: background-color var(--motion-fast), color var(--motion-fast), box-shadow var(--motion-fast);
}
.reach__filter:hover  { background: var(--color-canvas-tinted); }
.reach__filter:active { background: var(--color-canvas-pressed); }
.reach__filter[aria-pressed="true"] {
  background: var(--color-action-primary);
  box-shadow: none;
  color: var(--color-on-action);
}
.reach__filter[aria-pressed="true"]:hover  { background: var(--color-action-primary-hover); }
.reach__filter[aria-pressed="true"]:active { background: var(--color-action-primary-active); }
.reach__filter:focus-visible { outline: 3px solid var(--color-focus-ring); outline-offset: 2px; }

.reach__canvas { position: relative; aspect-ratio: 950 / 620; }   /* the drawing's own proportions */
.reach__land {
  position: absolute; inset: 0;
  display: block;
  width: 100%; height: 100%;
}
.reach__land path {
  fill: var(--reach-land);
  stroke: var(--color-canvas);
  stroke-width: 0.5;
  transition: fill var(--motion-medium);
}

/* A country with engagements: a button. Its focus ring, like the picked
   and pointed-at states, is drawn on a copy in the lift (below). */
.reach__country { cursor: pointer; outline: none; }
.reach__country path { fill: var(--reach-match); }
.reach__country:active path { fill: var(--color-action-primary-hover); }
.reach.has-country .reach__land > path { fill: var(--reach-land-faded); }
.reach.has-country .reach__country path { fill: var(--reach-match-faded); }
/* A country with none of the chosen experience's engagements: plain land,
   and no longer a button (behaviour/reach.js). */
.reach .reach__country.is-out { pointer-events: none; }
.reach .reach__country.is-out path { fill: var(--reach-land); }
.reach.has-country .reach__country.is-out path { fill: var(--reach-land-faded); }

/* The lift: copies of the picked country and of the one under the pointer
   or keyboard focus, drawn over their neighbours (behaviour/reach.js). */
.reach__lift { pointer-events: none; }
.reach__land .reach__lift path { fill: var(--reach-picked); stroke: var(--reach-ring); stroke-width: 1.5; transition: none; }
.reach__land .reach__lift .is-focus path { stroke: var(--color-focus-ring); stroke-width: 3; }

.reach__markers {
  position: absolute; inset: 0;
  margin: 0; padding: 0;
  list-style: none;
  pointer-events: none;   /* the countries under it take the pointer; the points take it back */
}

/* A point: a 24px button round a 12px dot; a place with several
   engagements, a 24px button round a 16px dot with their number. The
   number is set below {type.diagram-label}, at the page owner's request,
   so a group dot stays close to the size of a single one. The dots
   are nudged clear of each other, but the buttons can still overlap a
   little: the single points sit above the groups, so neither loses its
   centre. A point shows only on the picked country, or while the tour
   shows it (.is-shown, behaviour/reach.js); hidden, it cannot be
   focused either. */
.reach__marker {
  position: absolute; z-index: 2;
  left: var(--x); top: var(--y);
  width: var(--space-6); height: var(--space-6);
  display: grid; place-items: center;
  padding: 0; border: 0;
  border-radius: var(--radius-full);
  background: none;
  cursor: pointer;
  pointer-events: auto;
  transform: translate(-50%, -50%);
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--motion-medium), visibility 0s var(--motion-medium);
}
.reach__marker.is-shown { visibility: visible; opacity: 1; transition: opacity var(--motion-medium); }
.reach__marker--group { z-index: 1; }

.reach__dot {
  display: grid; place-items: center;
  width: var(--space-3); height: var(--space-3);
  border-radius: var(--radius-full);
  background: var(--color-canvas);
  box-shadow: 0 0 0 1px var(--color-ink);   /* keeps it clear of a light fill under it */
  color: var(--color-ink);
  font-family: var(--font-accent);
  font-size: var(--type-data-label);
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  transition: transform var(--motion-fast), background-color var(--motion-fast), box-shadow var(--motion-fast);
}
.reach__marker--group .reach__dot { width: var(--space-4); height: var(--space-4); font-size: var(--reach-count); }

/* The five states. Picked is the pressed state: ringed in the orbits'
   violet; the panel says which place it is. The tour's point (.is-toured)
   wears the same ring without being pressed. No point is ever disabled.
   Hovering a point only marks it; the panel changes on a click. */
.reach__marker:hover { z-index: 3; }
.reach__marker:hover .reach__dot { transform: scale(1.25); background: var(--color-canvas-tinted); }
.reach__marker:active .reach__dot { transform: scale(1.1); background: var(--color-canvas-pressed); }
.reach__marker[aria-pressed="true"],
.reach__marker.is-toured { z-index: 3; }
.reach__marker[aria-pressed="true"] .reach__dot,
.reach__marker.is-toured .reach__dot {
  transform: scale(1.1);
  box-shadow: 0 0 0 1px var(--color-ink), 0 0 0 calc(1px + var(--space-1)) var(--reach-ring);
}
.reach__marker:focus-visible { z-index: 3; outline: 3px solid var(--color-focus-ring); outline-offset: 2px; }

/* --- the panel ----------------------------------------------------------- */
.reach__panel { grid-area: panel; position: relative; }

/* The panels share one grid cell, so the cell keeps the tallest height and
   the section never moves; the picked one fades in. */
.reach__entries { display: grid; }
/* Beside the map, the panel keeps the room the longer engagement texts
   used to take (and the photos will), so the alumni band stays clear. The
   room includes the step buttons, so showing them moves nothing below. */
@media (min-width: 980px) { .reach__panel { min-height: 38rem; } }
.reach__entries > * { grid-area: 1 / 1; margin: 0; visibility: hidden; }
.reach__entries > .is-on { visibility: visible; animation: reach-fade-in var(--motion-slow); }
@keyframes reach-fade-in { from { opacity: 0; transform: translateY(var(--space-2)); } }

.reach__hint {
  margin: var(--space-6) 0 0;
  font-size: var(--type-body-sm);
  line-height: 1.5;
  color: var(--color-muted);
}

/* One engagement: the institution, then its facts, one per line
   ("Location: Ottawa, Canada"), between two hairlines. */
.reach__where {
  margin: 0;
  font-size: var(--type-h3);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--color-ink);
}
.reach__facts {
  margin: var(--space-4) 0 0;
  padding: var(--space-4) 0;
  border-top: 1px solid var(--color-hairline-soft);
  border-bottom: 1px solid var(--color-hairline-soft);
}
.reach__facts > div + div { margin-top: var(--space-2); }
.reach__facts dt,
.reach__facts dd {
  display: inline;
  margin: 0;
  font-size: var(--type-body-sm);
  line-height: 1.5;
}
.reach__facts dt { font-weight: 600; color: var(--color-ink); }
.reach__facts dt::after { content: ':'; }
.reach__facts dd { color: var(--color-body); }
/* The photo of the experience, under the facts, the panel's full width.
   Every photo is cropped to one 3:2 frame, held before it loads, so a
   late or a squarer photo never moves the page below. */
.reach__photo {
  display: block;
  width: 100%; height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  margin-top: var(--space-4);
  border-radius: var(--radius-sm);
}

/* The steps through a place with several engagements, above it at the
   left. Shown only when the picked place has more than one. */
.reach__step {
  display: none; align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.reach__step.is-on { display: flex; }
.reach__step-count {
  margin: 0;
  min-width: 7ch;
  text-align: center;
  font-family: var(--font-accent);
  font-size: var(--type-data-label);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--color-muted);
}
/* §10.1 button-icon: 44px, round, hairline. It wraps round, so it is never
   disabled. */
.reach__step-btn {
  display: grid; place-items: center;
  width: 44px; height: 44px;
  padding: 0; border: 0;
  border-radius: var(--radius-full);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--color-hairline);
  color: var(--color-ink);
  cursor: pointer;
  transition: background-color var(--motion-fast);
}
.reach__step-btn svg {
  width: var(--space-4); height: var(--space-4);
  fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
}
.reach__step-btn:hover  { background: var(--color-canvas-tinted); }
.reach__step-btn:active { background: var(--color-canvas-pressed); }
.reach__step-btn:focus-visible { outline: 3px solid var(--color-focus-ring); outline-offset: 2px; }

/* ---- responsive (§13.1) — review at 1440, 1180, 980, 720, 480, 390 ------ */
/* Below 980px there is no conduit: the ordinary gutter, and one column,
   the map between the head and the panel. */
@media (max-width: 979px) {
  .reach { --reach-left: var(--space-6); }
  .reach__frame {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "head" "map" "panel";
    row-gap: var(--space-8);
  }
  .reach__map { margin-right: 0; }
  /* No experience filter on smaller screens, at the page owner's request:
     the map shows every engagement (behaviour/reach.js clears the filter). */
  .reach__filters { display: none; }
  .reach__panel { max-width: var(--layout-container-narrow); }
  /* Under the map the panel takes the picked entry's own height, so a
     short entry leaves no room for the longest one. */
  .reach__entries > * { display: none; }
  .reach__entries > .is-on { display: block; }
}

/* Below 720px the map fits the screen, edge to edge, at the page owner's
   request. Its dots shrink so Europe's stay apart (behaviour/reach.js
   pushes apart any that still touch); the buttons round them shrink too,
   below the 24px of the exception above. */
@media (max-width: 719px) {
  .reach { --reach-left: var(--space-4); --reach-right: var(--space-4); }
  .reach__map { margin-inline: calc(var(--space-4) * -1); }
  .reach__marker { width: var(--space-4); height: var(--space-4); }
  .reach__marker--group { width: var(--space-4); height: var(--space-4); }
  .reach__dot { width: var(--space-2); height: var(--space-2); }
  .reach__marker--group .reach__dot { width: var(--space-3); height: var(--space-3); font-size: var(--reach-count-sm); }
}
