/**
 * Home map tower — label animation + runtime positioning.
 *
 * Positioning: the classes label-left / label-bottom are assigned at runtime by
 * assets/scripts/map-tower.js, which measures real bounding boxes and resolves
 * collisions (tower sets and label widths differ per WPML language, so static
 * per-country CSS cannot cover every case).
 *
 * Label animation (desktop): hovering a tower plays one continuous sequence —
 * backspace the short name, light the tower, draw a connector, then type the
 * full name while the underline stretches and the flag trails the last typed
 * character. The stock home.css markup (.img-icon label + .title popup) is
 * replaced by a single .map-label block in front-page.php, so none of those
 * stock rules have a target any more.
 *
 * Two things the animation deliberately does NOT own:
 *   - the tower's grayscale -> cyan change: Tower_00000.png is already the grey
 *     tower and the 150-frame canvas sequence is already cyan + glow, so this
 *     is just the crossfade that home.css/`--map-swap` below already drive;
 *   - the frame playback: template/assets/js/module/CanvasModule.js starts and
 *     stops it off the `is-active` class via a MutationObserver, which is why
 *     map-tower.js toggles that class on hover.
 *
 * Desktop only: below 1025px the map switches to the pin/stacked layout.
 */
@media screen and (min-width: 1025px) {
  .map-tower {
    /* One shared beat for the tower crossfade. home.css delays the fire
       (.gif-tower/.gif2) by a hard 2s — pulled back here so it blooms with the
       rest of the sequence instead of arriving long after it. */
    --map-swap: 0.38s;
    /* Width easing for the underline/flag. Short enough to stay glued to the
       typing, long enough to read as elastic rather than stepped. */
    --map-grow: 108ms cubic-bezier(0.22, 1, 0.36, 1);
    /* Gap between the last typed character and the flag. */
    --map-flag-gap: 0.8rem;
    /* Travel of the group rise. The label does not return to where it started:
       it leaves the tower's middle row and settles above its head, which is
       where the design reference ends up. 4rem clears the 100px tower box from
       its centre line to just past the spire. */
    --label-lift: 4rem;
    /* Dropped-below labels have the tower directly above them, so they lift
       just enough to read as motion without climbing into the artwork. */
    --label-lift-bottom: 1.4rem;
    --map-rise: 354ms cubic-bezier(0.33, 1, 0.68, 1);
    /* Lean of the connector's vertical leg. The corner (top) stays glued to the
       horizontal run; the tower end swings out, so the line reads as a slight
       diagonal down to the spire rather than a hard right angle (client
       reference). Mirrored automatically for label-left via its scaleX(-1). */
    --hook-slant: -22deg;
  }

  /* ---------- Stacking ---------- */
  /* The visitor's own country sits above idle neighbours; the tower currently
     playing sits above everything, so its expanded label is never covered. */
  .map-tower .map-item.is-active .map-img {
    z-index: 20;
  }
  .map-tower .map-item.is-lit:not(.is-pinned) .map-img {
    z-index: 40;
  }

  /* ---------- Tower crossfade ---------- */
  /* `is-lit` mirrors what :hover used to do. It has to, because once the label
     expands the pointer can sit on the label — outside .map-img — and :hover
     would drop out mid-sequence. */
  .map-tower .map-item.is-lit .map-img canvas,
  .map-tower .map-item.is-active .map-img canvas {
    opacity: 1;
  }
  /* The grey tower clears out faster than the cyan one arrives. While both are
     part-way visible they are vertically offset by the rise, which reads as a
     doubled tower — a short fade keeps that window brief. */
  .map-tower .map-item.is-lit .map-img .gif-tower,
  .map-tower .map-item.is-active .map-img .gif-tower {
    opacity: 0;
    transition-duration: 0.19s;
    transition-delay: 0s;
  }

  /* ---------- Icon lift ---------- */
  /* The rise belongs to the cyan tower only — it is the layer arriving, and it
     starts from below while invisible, so the motion is revealed rather than
     performed on something already on screen. The grey tower must NOT move: it
     is already sitting at its coordinates, so displacing it (even to fly it
     back) reads as a jolt downwards before the animation proper begins.
     Applied to .gif rather than .map-img, which carries translateX(-50%) as
     positioning and would drag the tower off its coordinates. */
  .map-tower .map-item .map-img .gif {
    transform: translateY(1rem) scale(0.97);
    transform-origin: 50% 100%;
    transition:
      opacity var(--map-swap) ease,
      transform 370ms cubic-bezier(0.33, 1, 0.68, 1);
  }
  .map-tower .map-item.is-lit .map-img .gif,
  .map-tower .map-item.is-active .map-img .gif {
    opacity: 1;
    transform: translateY(0) scale(1);
  }

  /* ---------- Label ---------- */
  /* Anchored by its left edge and never re-centred, so the text grows to the
     right while the start of the label stays put. */
  .map-tower .map-item .map-label {
    position: absolute;
    top: 50%;
    left: calc(100% - 2rem);
    width: var(--label-w, max-content);
    /* Text row plus the underline. The underline is inside the measured box on
       purpose: the solver collides labels by this rect, and leaving the rule
       outside it would under-report the label's real footprint. */
    height: 1.7rem;
    line-height: 1.4rem;
    white-space: nowrap;
    pointer-events: none;
    /* --label-dy is the solver's vertical nudge when neither side nor the
       bottom placement clears a neighbour (map-tower.js). */
    transform: translateY(calc(-50% + var(--label-dy, 0px)));
    transition: width var(--map-grow), transform var(--map-rise);
  }
  /* Collapsing back on mouseleave is a touch slower than the per-character
     growth so it reads as a settle rather than a snap. */
  .map-tower .map-item:not(.is-lit) .map-label {
    transition-duration: 215ms;
  }
  /* The solver probes placements by writing --label-dy and reading the box
     straight back (map-tower.js). Both the width and the transform are
     transitioned, so a probe would be answered with the label's *previous*
     geometry — every candidate would look clear and the pass would settle on
     nonsense. Transitions are suppressed for the length of the pass; it runs
     inside one frame, so nothing is visible mid-solve anyway. */
  .map-tower.is-solving .map-item .map-label,
  .map-tower.is-solving .map-item .map-label_flag,
  .map-tower.is-solving .map-item .map-label_hook,
  .map-tower.is-solving .map-item .map-label_hook::before,
  .map-tower.is-solving .map-item .map-label_hook::after {
    transition: none;
  }

  .map-tower .map-item .map-label_text {
    display: inline-block;
    font-size: 1.2rem;
    font-weight: 600;
    line-height: 1.4rem;
    letter-spacing: -0.024rem;
    color: var(--Color-text, #001221);
  }

  /* Absolute rather than a flex sibling: a flex sibling jumps a whole glyph
     per character, this one eases along with the underline. */
  .map-tower .map-item .map-label_flag {
    position: absolute;
    top: 0.2rem;
    left: calc(var(--text-w, 0px) + var(--map-flag-gap));
    width: 1.7rem;
    height: 1rem;
    object-fit: contain;
    transition: left var(--map-grow);
  }
  .map-tower .map-item:not(.is-lit) .map-label_flag {
    transition-duration: 215ms;
  }

  /* The underline and the horizontal run of the connector are the same
     element — one source of truth, and CSS gives the easing for free. */
  .map-tower .map-item .map-label_rule {
    position: absolute;
    top: 1.4rem;
    left: 0;
    width: 100%;
    height: 0.3rem;
    background: var(--color-pri);
  }

  /* L-shaped lead-in, built from two solid bars rather than a stretched SVG.
     A stretched SVG path fought itself two ways: preserveAspectRatio="none"
     rendered the horizontal run ~1.5x fatter than the vertical one, and the fix
     for that (vector-effect: non-scaling-stroke) makes Chrome ignore pathLength,
     which broke the stroke-dashoffset draw so the line stopped partway and read
     as stuck. Two thin bars (0.2rem — deliberately lighter than the 0.3rem
     underline, per the client reference) meet cleanly at the corner, and each
     draws by scaling, which is smooth and trivial to sequence.
     The box only positions the L; its top sits at the text's mid-height (not
     the underline) so the horizontal joins the middle of the word, and its
     height (set by is-rising) is the gap down to the tower. */
  .map-tower .map-item .map-label_hook {
    position: absolute;
    top: 0.7rem;
    right: 100%;
    /* Horizontal run of the L. Sized so the corner sits just right of the spire
       (the tower centre is ~3rem left of the label): the leaning vertical then
       travels down-left and lands ON the spire. Widening this pushes the corner
       left of the spire and the slant overshoots; narrowing shortens the run. */
    width: 2.4rem;
    height: 2.6rem;
    /* Eased while the label is still climbing (bars are scaled to 0, so
       invisible), so the box is already at its final size by the time the L
       draws — the draw does not have to chase a moving target. */
    transition: height var(--map-rise);
  }
  .map-tower .map-item .map-label_hook::before,
  .map-tower .map-item .map-label_hook::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    background: var(--color-pri);
  }
  /* Vertical leg: from the corner (text mid-height) down to the tower, leaned by
     --hook-slant so it reads as a diagonal. transform-origin at the top keeps
     the corner fixed on the horizontal run while the tower end swings out; it
     also means the leg draws downward from the corner. */
  .map-tower .map-item .map-label_hook::before {
    width: 0.2rem;
    height: 100%;
    transform: scaleY(0) skewX(var(--hook-slant, 0deg));
    transform-origin: 0 0;
  }
  /* Horizontal run: along the top, from the corner into the middle of the word. */
  .map-tower .map-item .map-label_hook::after {
    width: 100%;
    height: 0.2rem;
    transform: scaleX(0);
    transform-origin: 0 50%;
  }
  /* The connector is held back until the content has arrived: it draws itself in
     only on is-drawn, which map-tower.js schedules AFTER the group rise and the
     typing have both settled (before this it hung in mid-air while the text was
     still flying up — client note on the storyboard frames). The vertical draws
     first, then the horizontal, so the line reads as reaching out from the tower
     up to the label. */
  .map-tower .map-item.is-drawn .map-label_hook::before {
    transform: scaleY(1) skewX(var(--hook-slant, 0deg));
    transition: transform 185ms ease-out;
  }
  .map-tower .map-item.is-drawn .map-label_hook::after {
    transform: scaleX(1);
    transition: transform 185ms ease-out 170ms;
  }

  /* Portal link fades in only once the name has finished typing. */
  .map-tower .map-item .map-label_portal {
    position: absolute;
    top: calc(100% + 0.7rem);
    left: 0;
    font-size: 1.2rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--color-pri);
    text-decoration: underline;
    text-underline-offset: 0.2rem;
    opacity: 0;
    visibility: hidden;
    transition: opacity 154ms ease, visibility 0s linear 154ms;
  }
  .map-tower .map-item.is-open .map-label_portal {
    opacity: 1;
    visibility: visible;
    transition: opacity 154ms ease, visibility 0s;
  }

  /* The expanded label becomes part of the tower's own hover region so moving
     the pointer onto the portal link does not end the sequence. Idle labels
     stay inert — otherwise their boxes steal hover from neighbouring towers.
     The pinned tower is excluded for the same reason: its label rests expanded
     for the whole visit, and a permanently hit-testable box that wide would
     shadow every tower behind it. Its link stays clickable on its own. */
  .map-tower .map-item.is-lit:not(.is-pinned) .map-label {
    pointer-events: auto;
  }
  .map-tower .map-item.is-open .map-label_portal {
    pointer-events: auto;
  }

  /* Group rise, overlapping the typing rather than running before it.
     A transition, not a keyframe: keyframes returned the label to the row it
     started on, so the whole climb cancelled itself out and the label read as
     standing still. Here the lifted position IS the end state — it holds for as
     long as the tower is lit and eases back down on leave. The hook rides along
     (it is positioned against the label) and lands on the tower's upper body,
     which is the join the reference shows. */
  .map-tower .map-item.is-rising .map-label {
    /* Where the label lands is measured from the TOWER, not from wherever the
       solver parked the label at rest. Adding the lift on top of --label-dy
       stacked two offsets: a label already nudged up 40px to clear a neighbour
       flew a full 80px, ending above the tower box entirely with the connector
       left dangling in open space.
       The floor is what keeps the motion visible: a label resting above the
       landing spot would otherwise have nowhere to travel, so it climbs at
       least 1.6rem past where it started. min() picks the higher of the two
       because up is negative. */
    --label-y: min(
      calc(-1 * var(--label-lift)),
      calc(var(--label-dy, 0px) - 1.6rem)
    );
    transform: translateY(calc(-50% + var(--label-y)));
  }
  /* The connector box is stretched to whatever gap --label-y opens up, so its
     vertical run ends at the same point relative to the tower every time. The
     spire tip sits ~23px below the tower-box top (measured: topmost opaque pixel
     at 23% down the 100px box). With the box top now at the text mid-height
     rather than the underline, 2.6rem lands the vertical's end ~1px above the
     tip — the L points at the spire without running down over it, and the higher
     start gives ~14px of visible vertical (vs ~8px when it joined the underline). */
  .map-tower .map-item.is-rising .map-label_hook {
    height: calc(-1 * var(--label-y) - 2.6rem);
  }

  /* ---------- Label flipped to the left of the tower ---------- */
  /* Mirror of the anchor rule: here the right edge is what stays put, so the
     label grows leftwards instead of overrunning the map edge. */
  .map-tower .map-item.label-left .map-label {
    left: auto;
    right: calc(100% - 2rem);
  }
  .map-tower .map-item.label-left .map-label_hook {
    right: auto;
    /* Push the hook out from the text's right edge so the horizontal's free end
       does not butt against the last letters (client note on UAE — needed a
       small gap). The corner (which lands on the spire) sits at the far/tower
       end after the scaleX(-1) mirror, so the run is shortened by the same
       amount the box is shifted out: the corner stays put, only the text-side
       end retreats — spire alignment is preserved. */
    left: calc(100% + 0.35rem);
    width: 2.05rem;
    transform: scaleX(-1);
  }
  .map-tower .map-item.label-left .map-label_portal {
    left: auto;
    right: 0;
    text-align: right;
  }
  /* Mirror the inner order as well: with the tower on the right, the text sits
     on the tower side (right-anchored, so the connector meets it and the right
     edge stays put while it types leftwards) and the flag trails on the far
     left — the mirror image of the right-hand label, not text-then-flag facing
     the tower. */
  .map-tower .map-item.label-left .map-label_text {
    position: absolute;
    top: 0;
    right: 0;
  }
  .map-tower .map-item.label-left .map-label_flag {
    left: 0;
  }

  /* ---------- Label dropped below the tower (both sides collide) ---------- */
  /* Still visually centred under the tower at rest — that is what lets twenty
     of these coexist — but pinned by a measured half-width rather than by
     translateX(-50%), which would recentre the label on every typed character
     and drag its left edge along. --rest-half is the resting half-width, set
     once per layout pass in map-tower.js, so the left edge holds while the
     text grows rightwards. The connector is dropped here: the label already
     sits directly under the tower, so a hook would double back on itself. */
  .map-tower .map-item.label-bottom .map-label {
    top: calc(100% - 0.6rem);
    left: 50%;
    transform: translate(calc(-1 * var(--rest-half, 0px)), var(--label-dy, 0px));
  }
  .map-tower .map-item.label-bottom .map-label_hook {
    display: none;
  }
  .map-tower .map-item.label-bottom.is-rising .map-label {
    transform: translate(
      calc(-1 * var(--rest-half, 0px)),
      calc(var(--label-dy, 0px) - var(--label-lift-bottom))
    );
  }

  /* Country cards are a mobile/tablet affordance only. */
  .map-countries {
    display: none;
  }

  /* ---------- Reduced motion ---------- */
  /* No typing, no drawing, no lift — the end state, immediately. map-tower.js
     skips the timeline as well, so the text is swapped in one step. */
  @media (prefers-reduced-motion: reduce) {
    .map-tower .map-item .map-label,
    .map-tower .map-item .map-label_flag {
      transition: none;
    }
    /* The lifted position is still the end state — it is just reached in one
       step rather than climbed. */
    .map-tower .map-item.is-rising .map-label {
      transition: none;
    }
    .map-tower .map-item .map-img .gif {
      transform: none;
      transition: opacity var(--map-swap) ease;
    }
    .map-tower .map-item.is-drawn .map-label_hook::before,
    .map-tower .map-item.is-drawn .map-label_hook::after {
      transition: none;
    }
  }
}

/* ---------- Mobile / tablet (<=1024px) ---------- */
/* Pins stay tappable like desktop, but the per-pin label (which covered the
   map) is replaced: tapping a pin pops it with a halo and swaps the single
   detail card under the map (selection handled in map-tower.js). */
@media screen and (max-width: 1024px) {
  /* Per-pin label is off; the card below carries the info. */
  .map .map-list .map-item .map-label {
    display: none;
  }

  /* De-clump offsets computed by map-tower.js (pins pushed apart just enough
     to stop overlapping while staying near their true coordinates). */
  .map .map-list .map-item .map-img {
    transform: translateX(calc(-50% + var(--pin-dx, 0px))) translateY(var(--pin-dy, 0px));
  }

  /* Bigger pins = comfortable tap targets. */
  .map .map-list .map-item .map-img .icon-pin {
    width: 2.8rem;
    height: 2.8rem;
    transition: transform 0.3s ease, filter 0.3s ease;
  }
  .map .map-list .map-item.is-selected .map-img {
    z-index: 10;
  }
  .map .map-list .map-item.is-selected .map-img .icon-pin {
    transform: scale(1.25);
    filter: drop-shadow(0 0.3rem 0.5rem rgba(29, 144, 201, 0.55));
    animation: map-pin-pop 0.35s ease;
  }

  /* One detail card under the map, swapped per selected pin. */
  .map-countries {
    width: 100%;
    min-height: 6.8rem;
  }
  .map-countries .map-country {
    display: none;
  }
  .map-countries .map-country.is-selected {
    display: flex;
    align-items: center;
    gap: 1.2rem;
    width: fit-content;
    min-width: 24rem;
    margin: 0 auto;
    padding: 1.2rem 1.6rem;
    background: #fff;
    border-radius: 1.2rem;
    border: 0.1rem solid rgba(29, 144, 201, 0.35);
    box-shadow: 0 0.2rem 0.8rem rgba(0, 18, 33, 0.08);
    animation: map-card-in 0.3s ease;
  }
  .map-country_flag img {
    display: block;
    width: 3.6rem;
    height: 2.4rem;
    object-fit: cover;
    border-radius: 0.2rem;
  }
  .map-country_name {
    font-size: 1.5rem;
    font-weight: 600;
    color: #012240;
    white-space: nowrap;
  }
  .map-country_link {
    font-size: 1.3rem;
    color: var(--color-pri);
    margin-left: auto;
    white-space: nowrap;
    text-decoration: underline;
    text-underline-offset: 0.2rem;
  }
}

@keyframes map-pin-pop {
  0% { transform: scale(1); }
  55% { transform: scale(1.45); }
  100% { transform: scale(1.25); }
}
@keyframes map-card-in {
  from { opacity: 0; transform: translateY(0.6rem); }
  to { opacity: 1; transform: translateY(0); }
}
