/* NX shipment tracking page. Same stylesheet as the dashboard's tracking app
   (backend/dashboard_core/tracking/templates/tracking/base.html), moved to a
   file, plus the states a client-side page has and a server-rendered one does
   not: loading and service error. */
:root {
  /* NX brand: navy #1A005D, white, fresh green #8EC300, in the ratio 40/40/20.
     Navy and white are the surfaces and the text; green is the accent only
     (the button, the current step, the dot), never a surface or small text. */
  --navy: #1A005D; --navy-90: #250D65; --navy-80: #443178; --navy-60: #716297; --navy-40: #A096B9; --navy-20: #CFCADD; --navy-10: #ECEAF3;
  --green: #8EC300; --green-60: #BBDB66; --green-20: #E5EFCA; --green-text: #5C8000;
  --bg: #F4F4F6; --surface: #FFFFFF; --ink: #282828; --text-2: #4A4A55; --muted: #727272;
  --line: #E0E0E0; --line-2: #ECECEF; --grey: #D0D0D0;
  --amber: #B45309; --amber-soft: #FBEFD9; --amber-ring: #F6E3C3;
  --mono: 'IBM Plex Mono', ui-monospace, Menlo, Consolas, monospace;
  --sans: 'DM Sans', 'Helvetica Neue', Arial, sans-serif;
  --ease: cubic-bezier(.22, 1, .36, 1);
}
* { box-sizing: border-box; }
html, body { margin: 0; }
body { background: var(--bg); color: var(--ink); font-family: var(--sans); -webkit-font-smoothing: antialiased; line-height: 1.4; }
a { color: var(--navy); } a:hover { color: var(--navy-80); }
input::placeholder { color: #9A9AA6; }
.wrap { max-width: 1200px; margin: 0 auto; }
.site { display: flex; flex-direction: column; min-height: 100vh; }

/* header */
.site-header { background: var(--surface); border-bottom: 1px solid var(--line); }
.site-header .wrap { padding: 14px 24px; display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.logo { display: flex; align-items: center; gap: 14px; text-decoration: none; color: var(--ink); }
.logo img { height: 48px; width: auto; display: block; }
.logo span { font-size: 12px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); border-left: 1px solid var(--line); padding-left: 14px; }
.langs { display: none; gap: 2px; border: 1px solid var(--line); border-radius: 999px; padding: 3px; }
.js .langs { display: flex; }
.langs button { font: inherit; font-size: 12px; font-weight: 700; padding: 6px 10px; border-radius: 999px; border: 0; background: transparent; color: var(--ink); cursor: pointer; transition: background .2s, color .2s; }
.langs button:hover { background: var(--navy-10); }
.langs button[aria-pressed="true"] { background: var(--navy); color: #fff; }

/* hero */
.hero { background: var(--navy); color: #fff; padding: 72px 24px 150px; position: relative; overflow: hidden; }
/* The NX chevrons: two bands, green and white, bending once. The drawing
   covers the whole hero at every size: the SVG is scaled to cover (never
   stretched), kept to the right, and the bands start above the top edge and
   end below the bottom edge, so no band ever shows an end. The stroke is in
   screen pixels (non-scaling), so a wide screen gets a wider view of the
   drawing, not fatter bands. */
.hero-art { position: absolute; inset: 0; pointer-events: none; }
.hero-art svg { width: 100%; height: 100%; display: block; }
.hero-art .band { fill: none; stroke-linejoin: miter; stroke-miterlimit: 20; vector-effect: non-scaling-stroke; stroke-width: clamp(26px, 3.2vw, 58px); }
.hero-art .band { stroke-dasharray: 1; stroke-dashoffset: 0; }
.hero .wrap { display: flex; flex-direction: column; gap: 28px; position: relative; z-index: 1; }
.hero h1, .search label { text-shadow: 0 2px 24px rgba(26, 0, 93, .6); }
.hero h1 { margin: 0; width: fit-content; font-size: clamp(40px, 6vw, 76px); font-weight: 500; line-height: 1; letter-spacing: -.035em; padding-bottom: 14px; border-bottom: 6px solid var(--green); }
.search { display: flex; gap: 12px; flex-wrap: wrap; align-items: stretch; max-width: 720px; margin-top: 8px; }
.search .field { flex: 1 1 320px; display: flex; flex-direction: column; gap: 8px; }
.search label { font-size: 13px; font-weight: 600; color: var(--navy-20); }
.search input { height: 60px; border: 0; border-radius: 999px; padding: 0 26px; font-family: var(--mono); font-size: 22px; font-weight: 600; letter-spacing: .06em; color: var(--ink); background: #fff; min-width: 0; text-transform: uppercase; box-shadow: 0 10px 30px rgba(14, 3, 48, .35); transition: box-shadow .2s; }
.search input:focus { outline: 0; box-shadow: 0 0 0 4px var(--green), 0 10px 30px rgba(14, 3, 48, .35); }
.search .go { display: flex; flex-direction: column; justify-content: flex-end; }
.search button { height: 60px; padding: 0 34px; border: 0; border-radius: 999px; background: var(--green); color: var(--navy); font-family: var(--sans); font-size: 17px; font-weight: 700; letter-spacing: .02em; cursor: pointer; display: flex; align-items: center; gap: 10px; box-shadow: 0 10px 30px rgba(14, 3, 48, .35); transition: transform .2s var(--ease), background .2s; }
.search button:hover { background: var(--green-60); transform: translateY(-1px); }
.search button[disabled] { opacity: .7; cursor: progress; transform: none; }
.search button svg { transition: transform .25s var(--ease); }
.search button:hover svg { transform: translateX(4px); }

/* result */
.result { padding: 0 24px 96px; margin-top: -100px; position: relative; }
.card { background: var(--surface); border-radius: 24px; box-shadow: 0 18px 50px rgba(26, 0, 93, .14); overflow: hidden; }
.card-head { padding: 36px 40px 32px; display: flex; flex-direction: column; gap: 18px; border-bottom: 1px solid var(--line-2); }
.head-row { display: flex; justify-content: space-between; align-items: center; gap: 16px 32px; flex-wrap: wrap; }
.pill { display: inline-flex; align-items: center; gap: 8px; background: var(--green-20); color: var(--navy); font-size: 13px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; padding: 8px 14px; border-radius: 999px; }
.pill .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--green); }
.pill.delivered { background: var(--navy); color: #fff; } .pill.delivered .dot { background: var(--green); }
.pill.exception { background: var(--amber-soft); color: var(--amber); } .pill.exception .dot { background: var(--amber); }
.pill.processing { background: var(--navy-10); color: var(--navy); } .pill.processing .dot { background: var(--navy-40); }
.meta { display: flex; gap: 6px 24px; flex-wrap: wrap; font-size: 14px; color: var(--text-2); }
.meta b { color: var(--ink); font-weight: 700; }
dl.facts { margin: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); gap: 24px 40px; }
dl.facts > div { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
dl.facts dt { font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
dl.facts dd { margin: 0; overflow-wrap: anywhere; }
dd.code { font-family: var(--mono); font-size: 32px; font-weight: 600; letter-spacing: .04em; color: var(--navy); }
dd.big { font-size: 32px; font-weight: 700; letter-spacing: -.02em; line-height: 1.1; color: var(--navy); }
dd.big small { display: block; font-size: 18px; font-weight: 500; color: var(--text-2); margin-top: 2px; }

/* timeline */
.card-body { padding: 36px 40px 40px; }
.steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr)); gap: 0; }
.step { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.rail { display: flex; align-items: center; }
/* Above the bars, so the halo and the pulse of the current node are whole
   circles the bars stop at, not rings with a line through them. */
.node { width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0; position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; background: #fff; border: 3px solid var(--grey); }
.is-done .node { background: var(--navy); border-color: var(--navy); color: #fff; }
.is-current .node { border: 4px solid var(--green); box-shadow: 0 0 0 6px var(--green-20); }
.is-current.stage-exception .node { border-color: var(--amber); box-shadow: 0 0 0 6px var(--amber-ring); }
.is-current.stage-exception .node { --pulse: 180, 83, 9; }
.is-current .node { --pulse: 142, 196, 0; }
.bar { flex: 1; height: 4px; background: var(--line); position: relative; overflow: hidden; }
.bar i { position: absolute; inset: 0; background: var(--navy); transform-origin: left center; transform: scaleX(0); }
.bar:not(.on) i { display: none; }
.text { display: flex; flex-direction: column; gap: 4px; padding-right: 16px; }
.step-label { font-size: 15px; font-weight: 700; color: var(--navy); }
.is-current .step-label { color: var(--green-text); }
.is-current.stage-exception .step-label { color: var(--amber); }
.is-pending .step-label, .is-pending .step-when, .is-pending .step-where { color: var(--muted); }
.step-when, .step-where { font-size: 14px; color: var(--text-2); }
.step-when { font-variant-numeric: tabular-nums; }
.empty { color: var(--text-2); font-size: 15px; margin: 0; }

/* hint / not found / error / loading */
.notice { padding: 40px; display: flex; gap: 22px; align-items: flex-start; }
.notice .icon { width: 52px; height: 52px; border-radius: 50%; background: var(--navy-10); color: var(--navy); display: grid; place-items: center; flex-shrink: 0; }
.notice.warn .icon { background: var(--amber-soft); color: var(--amber); }
.notice h2 { margin: 0 0 8px; font-size: 26px; font-weight: 600; letter-spacing: -.02em; line-height: 1.1; color: var(--navy); }
.notice p { margin: 0; color: var(--text-2); font-size: 16px; line-height: 1.55; max-width: 60ch; }
.notice code { font-family: var(--mono); font-weight: 600; color: var(--ink); background: var(--bg); padding: 2px 8px; border-radius: 6px; }
.notice.loading .icon { position: relative; }
.notice.loading .icon::after { content: ""; position: absolute; inset: 6px; border-radius: 50%; border: 3px solid var(--navy-20); border-top-color: var(--green); animation: spin .9s linear infinite; }
.notice .retry { margin-top: 14px; font: inherit; font-weight: 700; color: var(--navy); background: var(--navy-10); border: 0; border-radius: 999px; padding: 10px 18px; cursor: pointer; }
.notice .retry:hover { background: var(--navy-20); }

/* footer */
.site-footer { background: var(--navy); color: #fff; padding: 44px 24px 28px; margin-top: auto; }
.site-footer .wrap { display: flex; flex-direction: column; gap: 28px; }
.foot-main { display: flex; justify-content: space-between; align-items: flex-start; gap: 32px; flex-wrap: wrap; }
.foot-brand { display: flex; flex-direction: column; gap: 14px; }
/* The logo is navy and green on transparent, so it sits in a white tile. */
.foot-logo { display: inline-block; width: fit-content; background: #fff; border-radius: 12px; padding: 10px 14px; }
.foot-logo img { height: 36px; width: auto; display: block; }
address { font-style: normal; font-size: 14px; line-height: 1.6; color: var(--navy-20); display: flex; flex-direction: column; }
address b { color: #fff; }
address a { color: #fff; font-weight: 600; text-decoration: none; border-bottom: 2px solid var(--green); }
.foot-nav { display: flex; flex-direction: column; gap: 10px; }
.foot-nav a { font-size: 14px; font-weight: 600; text-decoration: none; color: #fff; }
.foot-nav a:hover { color: var(--green); }
.foot-bottom { border-top: 1px solid var(--navy-80); padding-top: 18px; display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; font-size: 13px; color: var(--navy-40); }

/* motion: only transform and opacity, so every animation runs on the compositor */
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes rise { from { opacity: 0; transform: translate3d(0, 22px, 0); } to { opacity: 1; transform: translate3d(0, 0, 0); } }
@keyframes pop { from { opacity: 0; transform: scale(.6); } 70% { opacity: 1; transform: scale(1.06); } to { opacity: 1; transform: scale(1); } }
@keyframes grow-x { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes grow-y { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes spin { to { transform: rotate(360deg); } }
/* The pulse is a shadow of the node itself, so it is centred by construction. */
@keyframes pulse { from { box-shadow: 0 0 0 6px var(--green-20), 0 0 0 6px rgba(var(--pulse), .5); } to { box-shadow: 0 0 0 6px var(--green-20), 0 0 0 22px rgba(var(--pulse), 0); } }
@keyframes pulse-exception { from { box-shadow: 0 0 0 6px var(--amber-ring), 0 0 0 6px rgba(var(--pulse), .4); } to { box-shadow: 0 0 0 6px var(--amber-ring), 0 0 0 22px rgba(var(--pulse), 0); } }
.site-header { animation: fade-in .2s both; }
/* The bands draw themselves from the top down when the page opens. --d0 is how
   much of the line is already "drawn" at the first frame, tuned so the pen is
   just above the top edge of the hero at every width. */
@keyframes draw { from { stroke-dashoffset: var(--d0); animation-timing-function: cubic-bezier(.3, 0, .2, 1); } 85% { stroke-dashoffset: .38; animation-timing-function: linear; } to { stroke-dashoffset: 0; } }
.hero-art .band { --d0: .61; animation: draw .7s .05s both; }
.hero-art .band + .band { --d0: .66; animation-delay: .18s; }
.hero h1 { animation: rise .22s var(--ease) .03s both; }
.hero .search { animation: rise .2s var(--ease) .07s both; }
.card { animation: rise .25s var(--ease) .11s both; }
.pill { animation: pop .18s var(--ease) .2s both; }
dl.facts > div, .meta, .notice > * { animation: rise .18s var(--ease) both; animation-delay: calc(.22s + var(--i, 0) * .025s); }
/* The timeline is a chain: node i pops, its bar draws to the right, and only
   when the bar has arrived does node i+1 pop. One step every --period. */
.steps { --t0: .28s; --period: .25s; }
.step .node { animation: pop .1s var(--ease) both; animation-delay: calc(var(--t0) + var(--i, 0) * var(--period)); }
.step .text { animation: rise .18s var(--ease) both; animation-delay: calc(var(--t0) + var(--i, 0) * var(--period) + .05s); }
.bar.on i { will-change: transform; animation: grow-x .15s cubic-bezier(.4, 0, .2, 1) both; animation-delay: calc(var(--t0) + var(--i, 0) * var(--period) + .1s); }
.is-current .node { animation: pop .1s var(--ease) both, pulse 1.8s ease-out infinite; animation-delay: calc(var(--t0) + var(--i, 0) * var(--period)), calc(var(--t0) + var(--i, 0) * var(--period) + .12s); }
.is-current.stage-exception .node { animation-name: pop, pulse-exception; }
.site-footer { animation: fade-in .2s .32s both; }
.card.swap { animation: fade-in .15s both; }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; } .bar i { transform: none; } }

/* Below ~900px the drawing is cropped so much that the white band runs
   behind the title and the label: it goes, the green one on the right edge
   stays. */
@media (max-width: 900px) {
  .hero-art .band + .band { display: none; }
}

/* narrow screens: the timeline stands up */
@media (max-width: 640px) {
  .site-header .wrap { padding: 12px 16px; }
  .logo img { height: 40px; }
  .hero { padding: 48px 16px 120px; }
  .search input { font-size: 19px; height: 56px; }
  .search button { height: 56px; width: 100%; justify-content: center; }
  .search .go { flex: 1 1 100%; }
  .result { padding: 0 16px 56px; margin-top: -84px; }
  .card-head { padding: 26px 20px 24px; }
  .card-body { padding: 26px 20px 8px; }
  .notice { padding: 26px 20px; flex-direction: column; }
  dd.code { font-size: 24px; } dd.big { font-size: 26px; }
  .steps { grid-template-columns: 1fr; }
  .step { display: grid; grid-template-columns: 28px 1fr; column-gap: 16px; gap: 0 16px; }
  .rail { flex-direction: column; align-self: stretch; }
  .bar { width: 4px; height: auto; flex: 1; min-height: 34px; margin: 6px 0; }
  .bar i { transform-origin: center top; transform: scaleY(0); animation-name: grow-y; }
  .text { padding: 2px 0 26px; }
  .site-footer { padding: 32px 16px 22px; }
}
