/* ==========================================================================
   FAKIEH LOGISTICS — "OUT FOR DELIVERY"
   The launch presented as a shipment you can track. The parcel is the website;
   the destination is deployment. Says "almost there" without promising a date.
   ========================================================================== */

@font-face {
  font-family: 'Neue Montreal';
  src: url('../assets/fonts/NeueMontreal-Light.otf') format('opentype');
  font-weight: 300; font-display: swap;
}
@font-face {
  font-family: 'Neue Montreal';
  src: url('../assets/fonts/NeueMontreal-Regular.otf') format('opentype');
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: 'Neue Montreal';
  src: url('../assets/fonts/NeueMontreal-Medium.otf') format('opentype');
  font-weight: 500; font-display: swap;
}
/* No Bold face is declared: nothing here goes above weight 500, and shipping a
   42KB OTF the page never renders is pure cost on a launch page. */

:root {
  --navy:   #090911;
  --teal:   #0E7174;
  --teal-d: #0a5b5e;
  --sand:   #E8D7BE;
  --cream:  #F4EFE8;
  --paper:  #FBF9F5;
  --silver: #A0A0A0;
  --ink-2:  #5F5A52;          /* 6.1:1 on --cream — the only muted text colour */
  --line:   rgba(9, 9, 17, .10);
  --ease:   cubic-bezier(.22, 1, .36, 1);
}

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  min-height: 100dvh;
  background: var(--cream);
  color: var(--navy);
  font-family: 'Neue Montreal', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

.page {
  min-height: 100dvh;
  max-width: 1120px;
  margin-inline: auto;
  padding: clamp(18px, 2.6vh, 30px) clamp(20px, 5vw, 56px) clamp(16px, 2.2vh, 26px);
  display: flex;
  flex-direction: column;
  gap: clamp(14px, 2vh, 24px);
}

/* ---------- Header ---------- */

.top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
}

.logo { width: clamp(132px, 13vw, 176px); }
.logo img { width: 100%; height: auto; display: block; }
/* Needs the .logo prefix to outrank `.logo img { display: block }` above,
   otherwise both variants render stacked in the default theme. */
.logo .lg-teal { display: none; }

.waybill {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 7px 15px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  font-size: 11px; font-weight: 400; letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-2);
  white-space: nowrap;
}
.waybill strong { font-weight: 500; color: var(--navy); letter-spacing: .09em; }
.waybill .dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--teal); flex: none;
}

/* ---------- Lede ---------- */

.lede { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; }

.status-pill {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 7px 16px 7px 12px;
  border-radius: 999px;
  background: rgba(14, 113, 116, .10);
  color: var(--teal-d);
  font-size: 11px; font-weight: 500; letter-spacing: .17em; text-transform: uppercase;
}

/* A live-tracking heartbeat. The ::after is the expanding halo. */
.pulse { position: relative; width: 8px; height: 8px; flex: none; }
.pulse::before, .pulse::after {
  content: ''; position: absolute; inset: 0;
  border-radius: 50%; background: var(--teal);
}
.pulse::after { animation: ping 2s var(--ease) infinite; }

@keyframes ping {
  0%   { transform: scale(1);   opacity: .55; }
  70%  { transform: scale(3.2); opacity: 0; }
  100% { transform: scale(3.2); opacity: 0; }
}

h1 {
  font-size: clamp(32px, 4.6vw, 54px);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -.025em;
}
h1 em { font-style: normal; color: var(--teal); }

.sub {
  font-size: clamp(15px, 1.5vw, 18px);
  font-weight: 300; line-height: 1.5;
  color: var(--ink-2);
  max-width: 46ch;
}

/* ---------- Map ---------- */

.map-wrap {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: clamp(10px, 1.4vw, 18px);
  box-shadow: 0 1px 2px rgba(9, 9, 17, .04), 0 14px 40px -26px rgba(9, 9, 17, .30);
}

.map-stage { position: relative; border-radius: 12px; overflow: hidden; }
.map { display: block; width: 100%; height: auto; }

/* ---------- Hover: the map as a live display under glass ----------
   Four things move together — the panel tilts, the three depth layers drift by
   different amounts, a specular sheen tracks the cursor, and a telemetry ping
   runs the completed leg. JS writes only --rx/--ry/--sx/--sy; everything else
   is CSS, and the whole block is gated to fine pointers below. */

.map-wrap {
  transform: perspective(1200px)
             rotateX(var(--rx, 0deg))
             rotateY(var(--ry, 0deg));
  transform-origin: 50% 50%;
  transition: box-shadow 400ms var(--ease);
}

/* The specular highlight. Screen-blended and capped low so it can only ever
   brighten the map, never wash the labels. */
.sheen {
  position: absolute; inset: 0; pointer-events: none;
  opacity: 0; transition: opacity 420ms var(--ease);
  mix-blend-mode: screen;
  background: radial-gradient(340px circle at var(--sx, 50%) var(--sy, 50%),
    rgba(255, 253, 248, .14) 0%,
    rgba(255, 253, 248, .06) 38%,
    rgba(255, 253, 248, 0)   72%);
}

/* The ping. stroke-dasharray works in literal percentages because JS sets
   pathLength="100" on every route path. */
.route-pulse {
  fill: none; stroke-linecap: round;
  stroke-dasharray: 4 96;
  stroke-dashoffset: 0;
  opacity: 0;
}
.route-pulse.core { stroke: #FFFDF8; stroke-width: 5; }
.route-pulse.glow { stroke: #FFFDF8; stroke-width: 13; opacity: 0; }

@keyframes ping-run {
  0%   { stroke-dashoffset: 0;   opacity: 0; }
  14%  { opacity: 1; }
  86%  { opacity: 1; }
  100% { stroke-dashoffset: -88; opacity: 0; }
}
@keyframes ping-run-glow {
  0%   { stroke-dashoffset: 0;   opacity: 0; }
  14%  { opacity: .22; }
  86%  { opacity: .22; }
  100% { stroke-dashoffset: -88; opacity: 0; }
}

.dest-in { transition: transform 460ms var(--ease); }

@media (hover: hover) and (pointer: fine) {
  .map-wrap:hover {
    box-shadow: 0 1px 2px rgba(9, 9, 17, .05), 0 26px 60px -30px rgba(9, 9, 17, .38);
  }
  .map-wrap:hover .sheen { opacity: 1; }

  .map-wrap:hover .route-pulse.core { animation: ping-run 2.6s linear infinite; }
  .map-wrap:hover .route-pulse.glow { animation: ping-run-glow 2.6s linear infinite; }

  /* the shipment reports in a little faster while you are watching it */
  .map-wrap:hover .marker .m-pulse { animation-duration: 1.5s; }

  /* the destination lifts as if acknowledging */
  .map-wrap:hover .dest-in { transform: translateY(-5px); }
}

/* Placed after the hover block on purpose: it ties on specificity with
   `.map-wrap:hover .route-pulse.core`, so source order decides, and the
   delivery sweep must win even if the cursor is over the map. */
.map-wrap.receiving .route-pulse.core { animation: ping-deliver 620ms cubic-bezier(.4, 0, .2, 1) 1 both; }
.map-wrap.receiving .route-pulse.glow { animation: ping-deliver-glow 620ms cubic-bezier(.4, 0, .2, 1) 1 both; }

.water  { fill: rgba(14, 113, 116, .09); }
.blocks rect { fill: var(--sand); opacity: .42; }
.blocks-t { display: none; }   /* the portrait block set, switched in below */

/* The casing is what makes this read as a road rather than a line drawn over
   the map: it clears the blocks out from under the route the way a street
   does. pathLength="100" is set in JS so dash values are literal percentages. */
.route-casing {
  fill: none; stroke: var(--paper);
  stroke-width: 15; stroke-linecap: round; stroke-linejoin: round;
}
.route-base {
  fill: none; stroke: rgba(9, 9, 17, .20);
  stroke-width: 4.5; stroke-linecap: round; stroke-dasharray: .7 4.2;
}
.route-done {
  fill: none; stroke: var(--teal);
  stroke-width: 5; stroke-linecap: round;
}

.o-halo { fill: rgba(14, 113, 116, .16); }
.o-dot  { fill: var(--teal); }

.pin      { fill: var(--navy); }
.pin-dot  { fill: var(--sand); }
.pin-base { fill: rgba(9, 9, 17, .16); }

.chip rect { fill: var(--navy); }
.chip text {
  fill: var(--cream); font-size: 15px; font-weight: 500;
  letter-spacing: .04em; text-anchor: middle;
  font-family: 'Neue Montreal', Helvetica, Arial, sans-serif;
}
.chip-origin rect { fill: rgba(9, 9, 17, .82); }
.chip-origin text { font-size: 13px; font-weight: 400; }

.marker .m-pulse { fill: rgba(14, 113, 116, .20); animation: ping 2.4s var(--ease) infinite; }
.marker .m-ring  { fill: var(--paper); stroke: var(--teal); stroke-width: 2.5; }
.marker .m-core  { fill: var(--teal); }

.map-foot {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding: 12px 8px 2px;
  font-size: 12px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-2);
}
.map-foot strong {
  font-size: 20px; font-weight: 500; letter-spacing: -.01em;
  color: var(--teal); font-variant-numeric: tabular-nums;
}
.pct { display: inline-flex; align-items: baseline; gap: 7px; }

/* ---------- Tracking steps ---------- */

.track ol {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(10px, 1.4vw, 20px);
}

.track li {
  position: relative;
  padding-top: 22px;
  border-top: 2px solid var(--line);
}
.track li.done { border-top-color: var(--teal); }
.track li.now  { border-top-color: var(--teal); }

.tick {
  position: absolute; top: -7px; left: 0;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--cream); border: 2px solid var(--line);
}
.track li.done .tick { background: var(--teal); border-color: var(--teal); }
.track li.now  .tick { background: var(--cream); border-color: var(--teal); box-shadow: 0 0 0 4px rgba(14,113,116,.14); }

.t-name {
  display: block;
  font-size: clamp(13px, 1.3vw, 15px); font-weight: 500; letter-spacing: .01em;
}
.t-note {
  display: block; margin-top: 3px;
  font-size: clamp(11px, 1.1vw, 13px); font-weight: 300; line-height: 1.35;
  color: var(--ink-2);
}
.track li.next .t-name { color: var(--ink-2); }

/* ---------- Footer ---------- */

.foot {
  margin-top: auto;
  padding-top: clamp(14px, 2vh, 22px);
  border-top: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}

.tagline {
  font-size: 12px; font-weight: 300; letter-spacing: .06em; color: var(--ink-2);
}

/* ---------- Signup ----------
   One pill: the field and the button share a border so it reads as a single
   control rather than two stuck together. */

.signup { display: flex; flex-direction: column; align-items: flex-end; gap: 7px; }

.notify {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 4px 4px 6px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  transition: border-color 240ms var(--ease), box-shadow 240ms var(--ease);
}
.notify:focus-within {
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(14, 113, 116, .14);
}

.notify-input {
  width: clamp(160px, 20vw, 210px);
  padding: 9px 10px;
  border: 0; background: none; outline: none;
  font-family: inherit; font-size: 13px; letter-spacing: .01em;
  color: var(--navy);
}
.notify-input::placeholder { color: var(--ink-2); opacity: 1; }

.notify-btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 10px 18px;
  border: 0; border-radius: 999px; cursor: pointer;
  background: var(--teal); color: var(--cream);
  font-family: inherit; font-size: 13px; font-weight: 500; letter-spacing: .04em;
  white-space: nowrap;
  transition: background 240ms var(--ease), transform 240ms var(--ease);
}
.notify-btn .arrow { width: 12px; height: 12px; fill: currentColor; transition: transform 240ms var(--ease); }
.notify-btn:hover { background: var(--teal-d); }
.notify-btn:hover .arrow { transform: translateX(3px); }
.notify-btn:disabled { cursor: default; opacity: .62; }
.notify-btn:disabled .arrow { transform: none; }

/* The honeypot must be reachable by a scripted bot but invisible and
   unfocusable for a person — so it is moved off-screen, not display:none. */
.hp {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; pointer-events: none;
}

.notify-msg {
  min-height: 15px; padding-right: 4px;
  font-size: 12px; letter-spacing: .02em; color: var(--ink-2);
  opacity: 0; transform: translateY(-3px);
  transition: opacity 300ms var(--ease), transform 300ms var(--ease);
}
.notify-msg.show { opacity: 1; transform: none; }
.notify-msg.ok   { color: var(--teal); }

/* Done: the field is retired and the confirmation takes its place. */
.signup[data-state="done"] .notify { display: none; }
.signup[data-state="done"] .notify-msg { font-size: 13px; font-weight: 500; }

/* The form recedes as the parcel leaves it, so the launch reads as the button
   handing something off rather than two unrelated things happening. */
.signup[data-state="sending"] .notify {
  opacity: 0; transform: scale(.94);
  transition: opacity 260ms var(--ease), transform 260ms var(--ease);
  pointer-events: none;
}

/* ---------- Delivery celebration ----------
   The signup is not "submitted", it is DELIVERED: a parcel flies from the
   button to the destination pin, the pin catches it, the route lights up and
   the brand's pennants burst out of the pin. All of it is viewport-fixed and
   driven by the Web Animations API, so nothing here can reflow the page. */

/* Deliberately unmarked: a plain sand square. A logo on something 34px across
   that is only on screen for 600ms is noise — the silhouette is the whole
   point, and it reads faster clean. */
.parcel {
  position: fixed; left: 0; top: 0; z-index: 60;
  width: 32px; height: 32px; margin: -16px 0 0 -16px;
  border-radius: 8px;
  background: var(--sand);
  box-shadow: 0 10px 26px -8px rgba(0, 0, 0, .5);
  pointer-events: none;
}

.burst-bit {
  position: fixed; left: 0; top: 0; z-index: 59;
  width: 13px; height: 13px; margin: -6px 0 0 -6px;
  pointer-events: none;
  -webkit-mask: var(--pennant) no-repeat center / contain;
          mask: var(--pennant) no-repeat center / contain;
}

:root {
  --pennant: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 28'%3E%3Cpath d='M0 0h14l14 14v14l-14-14H0z' fill='%23000'/%3E%3C/svg%3E");
}

/* The depot takes the parcel in. Animating `r` rather than a transform: the
   .origin group carries a translate ATTRIBUTE, and a CSS transform on it would
   override that and fling the dot to the SVG's origin. */
@keyframes halo-accept {
  0%   { r: 12; opacity: .55; }
  40%  { r: 23; opacity: 1; }
  100% { r: 12; opacity: .55; }
}
.origin.accept .o-halo { animation: halo-accept 540ms cubic-bezier(.34, 1.56, .64, 1) 1; }

/* The pin takes the impact. */
@keyframes pin-land {
  0%   { transform: translateY(-15px) scale(1.2); }
  55%  { transform: translateY(3px)   scale(.93); }
  100% { transform: translateY(0)     scale(1); }
}
.dest-in.land { animation: pin-land 640ms cubic-bezier(.34, 1.56, .64, 1) 1 both; }

/* The whole panel acknowledges the arrival. */
@keyframes card-receive {
  0%   { box-shadow: 0 0 0 0 rgba(232, 215, 190, 0); }
  28%  { box-shadow: 0 0 0 2px rgba(232, 215, 190, .55), 0 0 48px rgba(232, 215, 190, .28); }
  100% { box-shadow: 0 0 0 0 rgba(232, 215, 190, 0); }
}
.map-wrap.receiving { animation: card-receive 1150ms var(--ease) 1; }

/* A full-length sweep, unlike the hover ping which stops at the shipment. */
@keyframes ping-deliver {
  0%   { stroke-dashoffset: 0;    opacity: 0; }
  10%  { opacity: 1; }
  100% { stroke-dashoffset: -100; opacity: 1; }
}
@keyframes ping-deliver-glow {
  0%   { stroke-dashoffset: 0;    opacity: 0; }
  10%  { opacity: .3; }
  100% { stroke-dashoffset: -100; opacity: .3; }
}

:focus-visible { outline: 2px solid var(--teal); outline-offset: 3px; border-radius: 4px; }

/* ---------- Entrance ---------- */

.top, .lede, .map-wrap, .track, .foot {
  animation: rise 800ms var(--ease) both;
}
.lede     { animation-delay: 70ms; }
.map-wrap { animation-delay: 150ms; }
.track    { animation-delay: 240ms; }
.foot     { animation-delay: 320ms; }

/* An animation with fill:both keeps asserting `transform: none` from the
   animation cascade, which outranks even inline styles — so the entrance would
   permanently block the hover tilt. JS drops this class in once the entrance
   is done; every element's natural state already equals the animation's end
   state, so nothing shifts. */
.page.settled > * { animation: none; }

@keyframes rise {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   TEAL THEME — html[data-theme="teal"]

   The map panel is DARKER than the page, not lighter. A lighter panel looked
   better but put the small caps in .map-foot at 3.8:1 against it; recessing it
   to #084A4D takes the same text to 6.3:1 and reads like an inset display.
   Contrast against the page field #0A5B5E: cream 6.78:1, sand 5.50:1,
   cream at 82% 5.11:1, cream at 78% 4.78:1 — all AA for body text.
   ========================================================================== */

html[data-theme="teal"] {
  --field:  #0A5B5E;
  --card:   #084A4D;
  --line:   rgba(244, 239, 232, .18);
  --ink-2:  rgba(244, 239, 232, .82);
}

html[data-theme="teal"] body { background: var(--field); color: var(--cream); }

html[data-theme="teal"] .lg-light { display: none; }
html[data-theme="teal"] .lg-teal  { display: block; }

/* --- header --- */
html[data-theme="teal"] .waybill {
  background: rgba(244, 239, 232, .07);
  border-color: rgba(244, 239, 232, .20);
  color: var(--ink-2);
}
html[data-theme="teal"] .waybill strong { color: var(--cream); }
html[data-theme="teal"] .waybill .dot   { background: var(--sand); }

/* --- lede --- */
html[data-theme="teal"] .status-pill {
  background: rgba(232, 215, 190, .14);
  color: var(--sand);
}
html[data-theme="teal"] .pulse::before,
html[data-theme="teal"] .pulse::after { background: var(--sand); }

html[data-theme="teal"] h1     { color: var(--cream); }
html[data-theme="teal"] h1 em  { color: var(--sand); }
html[data-theme="teal"] .sub   { color: var(--ink-2); }

/* --- map --- */
html[data-theme="teal"] .map-wrap {
  background: var(--card);
  border-color: rgba(244, 239, 232, .12);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .18), 0 18px 44px -28px rgba(0, 0, 0, .55);
}
html[data-theme="teal"] .water        { fill: rgba(9, 9, 17, .16); }
html[data-theme="teal"] .blocks rect  { fill: var(--sand); opacity: .19; }

html[data-theme="teal"] .route-casing { stroke: var(--card); }
html[data-theme="teal"] .route-base   { stroke: rgba(244, 239, 232, .30); }
html[data-theme="teal"] .route-done   { stroke: var(--sand); }

html[data-theme="teal"] .o-halo { fill: rgba(232, 215, 190, .22); }
html[data-theme="teal"] .o-dot  { fill: var(--sand); }

html[data-theme="teal"] .pin       { fill: var(--navy); }
html[data-theme="teal"] .pin-dot   { fill: var(--sand); }
html[data-theme="teal"] .pin-base  { fill: rgba(0, 0, 0, .26); }

html[data-theme="teal"] .chip rect        { fill: var(--navy); }
html[data-theme="teal"] .chip text        { fill: var(--cream); }
html[data-theme="teal"] .chip-origin rect { fill: rgba(9, 9, 17, .78); }

html[data-theme="teal"] .marker .m-pulse { fill: rgba(232, 215, 190, .24); }
html[data-theme="teal"] .marker .m-ring  { fill: var(--card); stroke: var(--sand); }
html[data-theme="teal"] .marker .m-core  { fill: var(--sand); }

html[data-theme="teal"] .map-foot        { color: var(--ink-2); }
html[data-theme="teal"] .map-foot strong { color: var(--sand); }

/* --- tracker --- */
html[data-theme="teal"] .track li         { border-top-color: rgba(244, 239, 232, .20); }
html[data-theme="teal"] .track li.done,
html[data-theme="teal"] .track li.now     { border-top-color: var(--sand); }

html[data-theme="teal"] .tick             { background: var(--field); border-color: rgba(244, 239, 232, .28); }
html[data-theme="teal"] .track li.done .tick { background: var(--sand); border-color: var(--sand); }
html[data-theme="teal"] .track li.now  .tick {
  background: var(--field); border-color: var(--sand);
  box-shadow: 0 0 0 4px rgba(232, 215, 190, .18);
}
html[data-theme="teal"] .t-name              { color: var(--cream); }
html[data-theme="teal"] .t-note              { color: rgba(244, 239, 232, .78); }
html[data-theme="teal"] .track li.next .t-name { color: rgba(244, 239, 232, .78); }

/* --- footer --- */
html[data-theme="teal"] .foot    { border-top-color: rgba(244, 239, 232, .16); }
html[data-theme="teal"] .tagline { color: rgba(244, 239, 232, .78); }

html[data-theme="teal"] .notify {
  background: rgba(244, 239, 232, .08);
  border-color: rgba(244, 239, 232, .22);
}
html[data-theme="teal"] .notify:focus-within {
  border-color: var(--sand);
  box-shadow: 0 0 0 3px rgba(232, 215, 190, .16);
}
html[data-theme="teal"] .notify-input { color: var(--cream); }
html[data-theme="teal"] .notify-input::placeholder { color: rgba(244, 239, 232, .62); }

/* Sand on teal, navy on sand: 14.1:1, and the warmest thing on the page. */
html[data-theme="teal"] .notify-btn { background: var(--sand); color: var(--navy); }
html[data-theme="teal"] .notify-btn:hover { background: var(--cream); }
html[data-theme="teal"] .notify-msg.ok { color: var(--sand); }

html[data-theme="teal"] :focus-visible { outline-color: var(--sand); }

/* ---------- Short viewports ----------
   Laptops in a half-height window still deserve the whole shipment on screen,
   so the type and the map give ground before the layout starts scrolling. */

@media (max-height: 780px) {
  h1   { font-size: clamp(28px, 3.8vw, 42px); }
  .sub { font-size: 15px; }
  .lede { gap: 11px; }
  .map-wrap { padding: 10px; border-radius: 16px; }
  .map-foot { padding: 9px 6px 0; }
  .map-foot strong { font-size: 17px; }
  .track li { padding-top: 17px; }
}

/* ---------- Responsive ---------- */

@media (max-width: 780px) {
  .track ol { grid-template-columns: repeat(2, 1fr); row-gap: 22px; }
  .foot { flex-direction: column; align-items: stretch; gap: 14px; }
  .tagline { max-width: 34ch; }
  .signup { align-items: stretch; }
  .notify { width: 100%; }
  .notify-input { width: auto; flex: 1; min-width: 0; }
  .notify-msg { padding-right: 0; }
}

@media (max-width: 400px) {
  /* Below this the field and the button cannot both hold their minimum
     comfortable width on one line. */
  .notify { flex-wrap: wrap; border-radius: 22px; padding: 6px; }
  .notify-input { width: 100%; flex: none; }
  .notify-btn { width: 100%; justify-content: center; }
}

/* ==========================================================================
   MOBILE (<= 620px) — a different layout, not a squeezed one.

   Phones get the portrait map (JS swaps the viewBox and the route), a vertical
   timeline instead of four stacked rules, and — since there is no hover to
   trigger anything — the motion runs on its own: the timeline builds itself as
   the shipment travels, and a telemetry ping loops the route afterwards.
   ========================================================================== */

@media (max-width: 620px) {

  /* --- portrait map --- */
  .blocks-w, .water { display: none; }
  .blocks-t { display: block; }
  /* Labels are legible again at portrait scale, so the chips stay on. */
  .chip { display: block; }

  /* --- vertical timeline ---
     Four full-width rules stacked read as dividers. One continuous spine with
     nodes down the left reads as a journey, and takes less room doing it. */
  .track ol { grid-template-columns: 1fr; gap: 0; }

  .track li {
    border-top: 0;
    padding: 0 0 17px 30px;
  }
  .track li:last-child { padding-bottom: 0; }

  .tick { top: 3px; left: 0; }

  .track li:not(:last-child)::after {
    content: ''; position: absolute;
    left: 5px; top: 16px; bottom: 2px; width: 2px;
    background: var(--line);
    transform-origin: top;
  }
  .track li.done::after { background: var(--teal); }
  html[data-theme="teal"] .track li.done::after { background: var(--sand); }

  .track li.now .t-name { color: var(--teal); }
  html[data-theme="teal"] .track li.now .t-name { color: var(--sand); }

  .t-name { font-size: 15px; }
  .t-note { font-size: 13px; margin-top: 2px; }

  /* --- the timeline builds itself while the shipment travels --- */
  .track li .tick { animation: node-pop 460ms cubic-bezier(.34, 1.56, .64, 1) both; }
  .track li::after { animation: spine-grow 520ms var(--ease) both; }
  .track li .t-name, .track li .t-note { animation: step-in 460ms var(--ease) both; }

  .track li:nth-child(1) .tick, .track li:nth-child(1)::after,
  .track li:nth-child(1) .t-name, .track li:nth-child(1) .t-note { animation-delay: 520ms; }
  .track li:nth-child(2) .tick, .track li:nth-child(2)::after,
  .track li:nth-child(2) .t-name, .track li:nth-child(2) .t-note { animation-delay: 980ms; }
  .track li:nth-child(3) .tick, .track li:nth-child(3)::after,
  .track li:nth-child(3) .t-name, .track li:nth-child(3) .t-note { animation-delay: 1440ms; }
  .track li:nth-child(4) .tick, .track li:nth-child(4)::after,
  .track li:nth-child(4) .t-name, .track li:nth-child(4) .t-note { animation-delay: 1860ms; }

  /* --- ambient motion, standing in for the hover effect --- */
  .route-pulse.core { animation: ping-idle 5.4s linear 2.9s infinite; }
  .route-pulse.glow { animation: ping-idle-glow 5.4s linear 2.9s infinite; }
  .dest-in { animation: bob 3.6s ease-in-out 3.2s infinite; }

  .map-foot { padding-top: 10px; }
}

@keyframes node-pop {
  0%   { transform: scale(.3);  opacity: 0; }
  60%  { transform: scale(1.16); opacity: 1; }
  100% { transform: scale(1);   opacity: 1; }
}
@keyframes spine-grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes step-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}

/* Travel, then rest. A ping that takes the whole cycle to cross reads as slow;
   this one crosses in ~2.5s and then leaves the map quiet for ~2.9s. */
@keyframes ping-idle {
  0%   { stroke-dashoffset: 0;   opacity: 0; }
  4%   { opacity: 1; }
  40%  { opacity: 1; }
  46%  { stroke-dashoffset: -88; opacity: 0; }
  100% { stroke-dashoffset: -88; opacity: 0; }
}
@keyframes ping-idle-glow {
  0%   { stroke-dashoffset: 0;   opacity: 0; }
  4%   { opacity: .22; }
  40%  { opacity: .22; }
  46%  { stroke-dashoffset: -88; opacity: 0; }
  100% { stroke-dashoffset: -88; opacity: 0; }
}

@media (max-width: 620px) {
  .page { gap: 14px; padding-bottom: 20px; }
  .lede { gap: 9px; }
  .sub { font-size: 14px; }
}

@media (max-width: 480px) {
  .top { gap: 12px; }
  .waybill { font-size: 10px; padding: 6px 12px; }
  .map-foot { font-size: 11px; }
  .mail { width: 100%; justify-content: center; }
}

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .top, .lede, .track, .foot { opacity: 1; transform: none; }
  /* No tilt, no parallax, no ping. JS also skips the loop entirely. */
  .map-wrap { opacity: 1; transform: none !important; }
  .sheen { display: none; }
  .route-pulse { display: none; }
}

/* ---------- Print ---------- */

@media print {
  body { background: #fff; }
  .map-wrap { box-shadow: none; }
  .mail { background: none; color: var(--teal); padding: 0; }
}
