/* Homepage v2 — "a shipment's journey".
   Layered on top of home.css. Each section borrows the mode of transport that
   matches its story: a ship crossing the ocean in the hero, a train running
   through the four-step workflow, a ship moving along the shipment lifecycle,
   and a truck making the final delivery in the CTA.

   Progressive enhancement: every rule here describes the FINISHED frame of an
   animation. home-v2.js adds `.v2-anim` to <html> only when it is going to
   animate, and that class is what rewinds each scene to its start. No JS, or
   prefers-reduced-motion, therefore shows the completed scene — never a train
   stuck off-screen. */

:root {
  --sea-back: #efe8de;
  --sea-front: #f5f1ea;
  --sea-line: #ddd3c6;
  --steel: #2b2724;
}

/* ----------------------------------------------------------------- hero sea
   The connected-systems strip becomes the water line: the front wave is the
   strip's own colour, so the ship sails into the band rather than above it. */
.hero-rail {
  border-top: 0;
  background: var(--sea-front);
}
.hero-sea {
  position: relative;
  flex: 0 0 auto;
  height: 56px;
  margin-top: -12px;          /* let the swell rise into the hero a touch */
  overflow: hidden;
  pointer-events: none;
}
.hero-sea .wave {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 200%;
  height: 100%;
  animation: wave-drift 26s linear infinite;
}
.hero-sea .wave-back  { bottom: 6px; opacity: 1; animation-duration: 38s; animation-direction: reverse; }
.hero-sea .wave-front { z-index: 2; }
@keyframes wave-drift { to { transform: translateX(-50%); } }

.hero-sea .ship {
  position: absolute;
  z-index: 1;
  left: 0;
  bottom: 3px;                /* hull sits a few px below the front crest */
  width: 190px;
  animation: sail 70s linear infinite;
  animation-delay: -30s;      /* already mid-crossing on first paint */
}
.hero-sea .ship svg { display: block; width: 100%; height: auto; animation: bob 5.5s ease-in-out infinite; transform-origin: 50% 90%; }
.hero-sea .ship-far {
  width: 92px;
  bottom: 16px;
  opacity: .42;
  animation-duration: 140s;
  animation-direction: reverse;
  animation-delay: -95s;
}
@keyframes sail {
  from { transform: translateX(-220px); }
  to   { transform: translateX(calc(calc(100 * var(--vw)) + 20px)); }
}
@keyframes bob {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(1.5px) rotate(-.6deg); }
}

/* ------------------------------------------------------------ the conveyor
   A belt above the four cards carries the work through them (drawn on a canvas
   by home-v2.js): email -> read -> decided -> done, with flagged items lifted
   off to a person at 04. It lives in the headroom the cards already had. */
.logic-flow { margin-top: clamp(74px, calc(9.2 * var(--vh)), 96px); }
.logic-track { display: none; }
.pipeline {
  position: absolute;
  left: 0;
  top: -58px;
  width: 100%;
  height: 46px;
  pointer-events: none;
}
/* Rewound frame: each card lights as the first piece of work reaches it. */
.v2-anim .logic-card:not(.is-lit) { opacity: .55; }
.logic-card { transition: opacity .45s ease, border-color .45s ease, transform .25s, box-shadow .25s; }
.logic-card.is-lit { border-color: #ff570073; }
.logic-card.is-lit:last-child .operator-mark { animation: human-pulse 1.6s ease-out 2; }
@keyframes human-pulse {
  0%   { box-shadow: 0 0 0 0 #ff570066; }
  100% { box-shadow: 0 0 0 10px #ff570000; }
}

/* ------------------------------------------------------ lifecycle timeline
   The shipment's tag travels a dashed planned route that turns solid behind
   it; at each milestone it docks (node fills, rings out, badge plays, status
   types in). Then .is-monitoring: a pulse sweeps the finished line on a loop and
   each milestone glows as it passes. */
.journey-line { transition: none; background: repeating-linear-gradient(90deg, #ffffff30 0 6px, transparent 6px 12px); }
.journey-line span { transform-origin: left center; }
.journey-line::after {                  /* the monitoring pulse */
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  width: 12%;
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, #fff 70%, transparent);
  box-shadow: 0 0 12px #ffad82;
  opacity: 0;
  will-change: transform, opacity;
}
.is-monitoring .journey-line::after { animation: jl-sweep 5s linear infinite; }
/* transform/opacity only, so the loop is composited, not repainted. 100% of the
   line = 100/12 of the pulse's own width. */
@keyframes jl-sweep {
  0% { transform: translateX(-100%); opacity: 0; }
  6% { opacity: .9; }
  56% { opacity: .9; }
  60%, 100% { transform: translateX(833%); opacity: 0; }
}
.journey-comet {                        /* the shipment tag */
  display: none;
  position: absolute;
  z-index: 3;
  left: 0;
  translate: -50% -50%;
  height: 18px;
  padding: 0 8px;
  border-radius: 9px;
  background: #ff5700;
  color: #fff;
  font: 800 8px/18px var(--font-geist-mono), monospace;
  letter-spacing: .08em;
  white-space: nowrap;
  box-shadow: 0 0 0 3px #ff570033, 0 0 16px 2px #ff570055;
  opacity: 0;
  transition: opacity .15s;
  pointer-events: none;
  will-change: transform;
}
.journey-comet::before {               /* its trail */
  content: "";
  position: absolute;
  right: 100%;
  top: 8px;
  width: 42px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, #ffad82);
}
.v2-js .journey-comet { display: block; }
.journey-comet.is-live { opacity: 1; }

.journey-node { position: relative; isolation: isolate; overflow: hidden; }
.journey-node::before {                 /* the fill that sweeps in on docking */
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--orange);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .45s cubic-bezier(.6, 0, .2, 1);
}
.journey-step.is-done .journey-node::before { transform: none; }
.v2-anim .journey-step.is-done .journey-node { animation: jn-dock .9s ease-out; }
.journey-step::before {                 /* the glow behind a node as the pulse passes */
  content: "";
  position: absolute;
  z-index: -1;
  left: 13px;
  top: 0;
  width: 94px;
  height: 50px;
  border-radius: 4px;
  box-shadow: 0 0 24px 9px #ff57008c;
  opacity: 0;
}
.v2-anim .is-monitoring .journey-step::before { animation: jn-glow 5s linear infinite; animation-delay: var(--glow-delay, 0s); }
@keyframes jn-dock {
  0% { box-shadow: 0 0 0 7px #222, 0 0 0 7px #ff5700aa; }
  100% { box-shadow: 0 0 0 7px #222, 0 0 0 24px #ff570000; }
}
@keyframes jn-glow { 0% { opacity: 1; } 14%, 100% { opacity: 0; } }
.board-status span { animation: bs-ping 2s ease-out infinite; }
@keyframes bs-ping { 0% { box-shadow: 0 0 0 0 #55c88799; } 100% { box-shadow: 0 0 0 9px #55c88700; } }
.is-offscreen .board-status span, .is-offscreen .journey-line::after, .is-offscreen .journey-step::before, .is-offscreen .journey-node { animation-play-state: paused !important; }

.ms-icon {
  position: absolute;
  z-index: 2;
  top: -15px;
  left: 45px;                          /* centred on the 94px node, which sits 13px in */
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 1px solid #ff570066;
  border-radius: 50%;
  background: #222;
  color: #fd9360;
  box-shadow: 0 0 0 5px #222;
  transition: opacity .35s, transform .45s cubic-bezier(.34, 1.56, .64, 1), border-color .35s;
}
.ms-icon svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; overflow: visible; }
.ms-icon .ms-fill { fill: #222; }
.v2-anim .journey-step:not(.is-done) .ms-icon { opacity: .35; transform: scale(.8); }
.journey-step.is-done .ms-icon { border-color: #ff5700; }
/* 1 pre-alert: the document rises out of the envelope */
.ms-doc { transition: transform .6s ease .15s; }
.v2-anim .journey-step:not(.is-done) .ms-doc { transform: translateY(5px); }
/* 2 shipment created: the check draws in */
.ms-check { stroke-dasharray: 16; stroke-dashoffset: 0; transition: stroke-dashoffset .5s ease .2s; }
.v2-anim .journey-step:not(.is-done) .ms-check { stroke-dashoffset: 16; }
/* 3 FMS sync, 4 monitoring: keep turning once reached */
.ms-spin, .ms-sweep { transform-box: view-box; transform-origin: 16px 16px; }
.journey-step.is-done .ms-spin { animation: ms-rotate 2.6s linear infinite; }
.journey-step.is-done .ms-sweep { animation: ms-rotate 2.2s linear infinite; }
.ms-wedge { fill: #ff570040; stroke: none; }
.ms-ping { fill: #fd9360; stroke: none; opacity: 0; }
.journey-step.is-done .ms-ping { animation: ms-ping 2.2s ease-out infinite; }
/* 5 communications sent: the plane takes off, again and again */
.journey-step.is-done .ms-plane { animation: ms-fly 2.8s ease-in-out infinite; }
@keyframes ms-rotate { to { transform: rotate(360deg); } }
@keyframes ms-ping { 0%, 40% { opacity: 0; } 48% { opacity: 1; } 100% { opacity: 0; } }
@keyframes ms-fly {
  0%, 30% { transform: translate(0, 0); opacity: 1; }
  60%     { transform: translate(7px, -7px); opacity: 0; }
  61%     { transform: translate(-6px, 6px); opacity: 0; }
  85%, 100% { transform: translate(0, 0); opacity: 1; }
}
.is-offscreen .ms-icon * { animation-play-state: paused !important; }
.journey-node { transition: color .3s .15s; }
.journey-step.is-done .journey-node { color: #fff; }
.v2-anim .journey-status { clip-path: inset(0 100% 0 0); transition: clip-path .6s steps(14) .35s; }
.v2-anim .journey-step.is-done .journey-status { clip-path: inset(0 0 0 0); }
.journey-step h3, .journey-step p { transition: opacity .5s .45s, transform .5s .45s; }
.journey-step p { transition-delay: .55s; }
.v2-anim .journey-step:not(.is-done) h3,
.v2-anim .journey-step:not(.is-done) p { opacity: .22; transform: translateY(8px); transition-delay: 0s; }

.shipment-summary strong.is-typing::after {   /* typing caret */
  content: "";
  display: inline-block;
  width: 2px;
  height: .85em;
  margin-left: 3px;
  vertical-align: -1px;
  background: #fd9360;
  animation: caret .5s steps(1) infinite;
}
@keyframes caret { 50% { opacity: 0; } }
.summary-check { transition: transform .5s cubic-bezier(.34, 1.56, .64, 1) .9s; }
.v2-anim .shipment-board:not(.is-summed) .summary-check { transform: scale(0); transition-delay: 0s; }

/* ---------------------------------------------------------------- odometer
   Each digit is a strip of numerals behind a one-numeral window; the strip
   rolls up to the figure (see ODOMETER in home-v2.js). The real figure is kept
   as visually hidden text for screen readers. */
.proof-value { display: flex; align-items: flex-end; }
.roll, .roll-sym { display: inline-block; height: 1.1em; line-height: 1.1em; }
.roll { overflow: hidden; font-variant-numeric: tabular-nums; }
.roll-strip { display: block; will-change: transform; }
.roll-strip > span { display: block; height: 1.1em; text-align: center; }
.is-rolling .roll-strip { transition: transform 1.9s cubic-bezier(.16, .8, .24, 1) var(--roll-delay, 0s); }
.is-rolling .roll { -webkit-mask-image: linear-gradient(transparent, #000 12%, #000 88%, transparent); mask-image: linear-gradient(transparent, #000 12%, #000 88%, transparent); }
.is-reset .roll-strip { transition: none !important; }
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* The yard follows the paragraph, so home.css's `p:last-child` rule no longer
   reaches it; restate it for the paragraph itself. */
.forwarders-title > p:not(.kicker) {
  max-width: 470px;
  margin: 28px 0 0;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.75;
}

/* -------------------------------------------------------------------- yard
   Under "By forwarders. For forwarders.": a container yard from above. */
.yard {
  display: block;
  width: 100%;
  max-width: 420px;
  height: auto;
  margin-top: clamp(18px, calc(3.5 * var(--vh)), 34px);
}

/* -------------------------------------------------------------------- quay
   The final CTA's foot: a working ship-to-shore crane loading a truck. The
   scene is sized to the space under the copy so it never sits behind text. */
.cta-section { position: relative; }
.cta-scene {
  position: absolute;
  z-index: 0;
  left: 0;
  right: 0;
  bottom: 0;
  height: clamp(130px, calc(26 * var(--vh)), 240px);
  pointer-events: none;
  overflow: hidden;
}
.cta-scene .quay { display: block; }
.cta-section .cta-inner { padding-bottom: 36px; }

/* Short laptop screens: the conveyor's headroom is what pushes #how past one
   screen, so it shrinks into the space the section already had. */
@media (min-width: 1021px) and (max-height: 780px) {
  .logic-flow { margin-top: 36px; }
  .pipeline { top: -36px; height: 32px; }
  .yard { max-width: 340px; }
}

/* ------------------------------------------------------------ small screens */
@media (max-width: 1020px) {
  /* Cards wrap to 2x2 and then a column, so a straight belt no longer maps
     onto them; the cards keep their normal look. */
  .pipeline { display: none; }
  .logic-flow { margin-top: clamp(30px, calc(4 * var(--vh)), 56px); }
  .v2-anim .logic-card:not(.is-lit) { opacity: 1; }
  .ms-icon { display: none; }
}
@media (max-width: 760px) {
  .hero-sea { height: 46px; }
  .hero-sea .ship { width: 150px; }
  .hero-sea .ship-far { display: none; }
  .cta-scene { height: 120px; }
}

/* Motion off: everything holds its finished frame (see header note). */
@media (prefers-reduced-motion: reduce) {
  .hero-sea .wave,
  .hero-sea .ship,
  .hero-sea .ship svg,
  .ms-icon *, .board-status span { animation: none !important; }
  .hero-sea .ship { transform: translateX(calc(58 * var(--vw))); }
  .hero-sea .ship-far { transform: translateX(calc(18 * var(--vw))); }
}


/* ----------------------------------------------------------- hero globe
   A large, fixed globe centred on the US, sized and placed like the original
   hero globe: it bleeds off the right edge and under the sea band, so it reads
   as part of the scene rather than an illustration in a box. It is out of the
   hero's flow (absolute), so it never affects the hero's height — which is
   what keeps the hero at exactly one screen for snapping. */
.hero-grid { grid-template-columns: minmax(0, 1fr); }
.hero-globe2d {
  --d: clamp(760px, min(calc(118 * var(--vh)), calc(84 * var(--vw))), 1180px);
  position: absolute;
  z-index: 0;
  width: var(--d);
  height: var(--d);
  left: calc(81% - var(--d) / 2);   /* the US (globe centre) sits at ~81% */
  /* The globe's western edge runs under the copy; fade it out there so the
     paragraph never has lanes and ships crossing behind its lines. */
  -webkit-mask-image: linear-gradient(90deg, transparent 3%, #000 19%);
          mask-image: linear-gradient(90deg, transparent 3%, #000 19%);
  top: calc(50% - var(--d) / 2);
  opacity: 0;
  transition: opacity .9s ease;
  pointer-events: none;
}
.hero-globe2d.is-ready { opacity: 1; }
.hero-globe2d canvas { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
/* The copy sits over the globe's western limb; give it the stacking order. */
.hero .hero-grid { z-index: 1; }

/* Map key: bottom-right, just above the sea band, on a soft pill so it stays
   legible over the globe. */
.globe-key {
  position: absolute;
  z-index: 2;
  right: clamp(22px, calc(4 * var(--vw)), 48px);
  bottom: 138px;                     /* sea band 56 + systems strip 64 + gap */
  padding: 8px 14px;
  border: 1px solid #e7e0d6;
  border-radius: 999px;
  background: #fffdf9e6;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.globe-legend {
  display: flex;
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
  white-space: nowrap;
  color: #5e5b57;
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: .04em;
}
.globe-legend li { display: inline-flex; align-items: center; gap: 6px; }
.globe-legend i { display: inline-block; flex: none; }
.lg-port { width: 8px; height: 8px; border-radius: 50%; background: #ff5700; box-shadow: 0 0 0 1.5px #fff; }
.lg-ramp { width: 7px; height: 7px; background: #1d1d1d; }
.lg-lane { width: 16px; height: 0; border-top: 1.5px dashed #ff5700; }
.lg-rail { width: 16px; height: 3px; border-radius: 2px; background: #3a3632; }
.lg-xb { width: 16px; height: 3px; border-radius: 2px; background: #ff5700; }

/* Below 1021px the copy spans the width, so a globe behind it would put map
   labels under the text. Instead it joins the hero's flow directly below the
   copy (the hero is a flex column; `order` moves it without touching the
   markup), full strength and still centred on the US. Snapping is off at these
   widths, so the extra height is fine. */
@media (max-width: 1020px) {
  .hero-grid { order: 1; }
  .hero-globe2d {
    --d: min(640px, 112vw);
    order: 2;
    position: relative;
    left: auto;
    top: auto;
    align-self: center;
    margin: -8px 0 -18px;
    -webkit-mask-image: none;
            mask-image: none;
  }
  .hero-sea { order: 3; }
  .hero-rail { order: 4; }
  .globe-key { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-globe2d { transition: none; }
}

/* Paused while scrolled out of view (class set by home-v2.js). */
.is-offscreen .hero-sea *,
.is-offscreen .hero-sea .ship svg,
.is-offscreen .journey-ship svg { animation-play-state: paused !important; }


/* The shared header is exempt from the large-screen page zoom, so it is the
   same size here as on every other page (which are not scaled). Zooming the
   nav by 1/z cancels the page's z. */
.nav { zoom: var(--z-inv, 1); }
