/* ---------------------------------------------------------------------------
   The landing page, and only the landing page.

   Kept out of styles.css because it is the one surface in this app that is
   selling something rather than doing something. Everything else a parent
   opens is a tool held one-handed in a driveway and is styled for legibility
   at arm's length; this page is read once, on a phone or a laptop, by someone
   deciding whether the link a school sent them is trustworthy. It gets a hero,
   photographs and motion, and none of that belongs in the stylesheet the live
   tracker loads.

   The hero is dark in both colour schemes. It sits on a photograph, so its
   contrast comes from the scrim over that photograph rather than from the
   theme tokens, and letting it flip to light would mean two sets of scrims to
   keep legible instead of one.
   --------------------------------------------------------------------------- */

.landing {
  /* The page's own tokens. Deliberately not the app's --accent: the hero is
     photographic and needs a yellow that belongs to a school bus. */
  --bus: #ffc932;
  --ink: #0d1117;
  --on-dark: #f4f6f8;
  --on-dark-muted: #b9c2cd;
}

/* --- Hero ----------------------------------------------------------------- */

.hero {
  position: relative;
  isolation: isolate;
  min-height: min(46rem, 100svh);
  display: grid;
  align-content: center;
  padding: 4.5rem 1.25rem 3.5rem;
  overflow: hidden;
  background: var(--ink);
  color: var(--on-dark);
  text-align: center;
}

/* The photograph, as an element rather than a background image, so it can be
   an <img> with srcset and be lazily decoded like any other picture. */
.hero__photo {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 80%;
}

/* Two scrims, not one: a vertical gradient so the headline has depth of
   contrast wherever the sky is bright, and a flat wash so the darkest reading
   of the photograph still passes contrast against white text. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(110% 62% at 50% 30%, rgba(8, 11, 15, 0.6) 0%, rgba(8, 11, 15, 0) 100%),
    linear-gradient(to bottom, rgba(8, 11, 15, 0.8) 0%, rgba(8, 11, 15, 0.34) 42%, rgba(8, 11, 15, 0.88) 100%),
    rgba(8, 11, 15, 0.14);
}

.hero__inner {
  /* The photograph is a bright yellow bus, and no scrim dark enough to make
     grey text safe over its windscreen leaves the bus looking like a bus. The
     shadow does that job locally instead, on the text that needs it. */
  text-shadow: 0 1px 14px rgba(8, 11, 15, 0.85), 0 1px 3px rgba(8, 11, 15, 0.7);
  max-width: 46rem;
  margin: 0 auto;
  display: grid;
  gap: 1.25rem;
  justify-items: center;
}

.hero__eyebrow {
  margin: 0;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bus);
}

.hero h1 {
  margin: 0;
  font-size: clamp(2.5rem, 9vw, 4.75rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  font-weight: 800;
  text-wrap: balance;
}

.hero__tagline {
  margin: 0;
  max-width: 34rem;
  font-size: clamp(1.15rem, 3.4vw, 1.6rem);
  line-height: 1.3;
  color: var(--on-dark);
  text-wrap: balance;
}

.hero__tagline em {
  font-style: normal;
  color: var(--bus);
}

.hero__sub {
  margin: 0;
  max-width: 32rem;
  color: #dde3ea;
}

.hero__cta {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 0.25rem;
}

/* The hero's buttons override the app's, which are quiet by design because
   they usually sit on a form. Here one of them is the whole point of the page. */
.hero a.button {
  padding: 0.8rem 1.4rem;
  border-radius: 999px;
  font-size: 1.05rem;
}

.hero a.button.primary {
  background: var(--bus);
  border-color: var(--bus);
  color: #241a00;
  box-shadow: 0 8px 30px rgba(255, 201, 50, 0.28);
}

.hero a.button:not(.primary) {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.35);
  color: var(--on-dark);
  backdrop-filter: blur(6px);
}

/* --- The route line ------------------------------------------------------ */

/*
   The one piece of theatre on the page, and it earns its place by being the
   product's actual promise drawn rather than described: a dotted route, and a
   marker that starts far away and arrives. Everything about it is decorative,
   so it is aria-hidden, and it stops entirely under prefers-reduced-motion --
   where the marker is simply parked partway along the route, which still reads
   as "the bus is on its way".
*/
.route {
  width: min(30rem, 100%);
  margin-top: 0.5rem;
}

.route svg { display: block; width: 100%; height: auto; overflow: visible; }

.route__road {
  fill: none;
  stroke: rgba(255, 255, 255, 0.22);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 1 11;
}

.route__done {
  fill: none;
  stroke: var(--bus);
  stroke-width: 3;
  stroke-linecap: round;
  /* Set from the path's own length in the markup's viewBox units. */
  stroke-dasharray: 320;
  stroke-dashoffset: 320;
  animation: route-draw 7s cubic-bezier(0.4, 0, 0.5, 1) infinite;
}

.route__stop { fill: var(--on-dark); }
.route__stop-ring { fill: none; stroke: rgba(255, 255, 255, 0.4); stroke-width: 2; }

/* The marker is positioned entirely by the motion path, so a browser without
   offset-path would draw it at the corner of the SVG rather than on the road.
   Hidden unless the path is understood; the drawn route still tells the story. */
.route__bus { visibility: hidden; }

@supports (offset-path: path('M 0 0 L 1 1')) {
  .route__bus {
    visibility: visible;
    offset-path: path('M 4 34 C 60 34, 74 8, 132 8 S 210 34, 262 20 S 306 6, 316 6');
    offset-rotate: 0deg;
    animation: route-run 7s cubic-bezier(0.4, 0, 0.5, 1) infinite;
  }
}

.route__bus-glow {
  fill: var(--bus);
  opacity: 0.35;
  animation: route-pulse 2s ease-in-out infinite;
}

.route__bus-body { fill: var(--bus); }

@keyframes route-draw {
  0% { stroke-dashoffset: 320; }
  85%, 100% { stroke-dashoffset: 0; }
}

@keyframes route-run {
  0% { offset-distance: 0%; }
  85%, 100% { offset-distance: 100%; }
}

@keyframes route-pulse {
  0%, 100% { opacity: 0.15; transform: scale(1); }
  50% { opacity: 0.4; transform: scale(1.35); }
}

/* --- The example notification -------------------------------------------- */

/*
   A mock-up of the thing the app sends, captioned as an example so that nobody
   reads it as a live bus. Placed in the hero because it is the clearest
   possible answer to "what do I actually get out of this".
*/
.alert-demo {
  position: relative;
  text-shadow: none;
  width: min(27rem, 100%);
  margin-top: 0.75rem;
  padding: 0.85rem 1rem;
  display: flex;
  gap: 0.8rem;
  align-items: center;
  text-align: left;
  border-radius: 14px;
  padding-right: 4.5rem;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.22);
  backdrop-filter: blur(10px);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.35);
  animation: alert-in 900ms 600ms ease-out both;
}

.alert-demo__icon {
  flex: none;
  width: 2.4rem;
  height: 2.4rem;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: var(--bus);
  color: #241a00;
  font-size: 1.3rem;
}

.alert-demo__title { font-weight: 700; font-size: 0.95rem; }
.alert-demo__body { font-size: 0.9rem; color: var(--on-dark-muted); }
.alert-demo__eta { color: var(--bus); font-variant-numeric: tabular-nums; font-weight: 700; }

.alert-demo__tag {
  /* Out of the flex flow: in it, the caption stole enough width from a phone
     to wrap the notification's own headline, which is the one line here that
     has to read like the real thing. */
  position: absolute;
  top: 0.45rem;
  right: 0.6rem;
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--on-dark-muted);
}

@keyframes alert-in {
  from { opacity: 0; transform: translateY(14px) scale(0.97); }
  to { opacity: 1; transform: none; }
}

/* The closing call to action repeats the hero's, so it repeats its colour
   too: on this page the yellow is the button that matters, and the app's blue
   showing up once at the bottom reads as a different, lesser offer. */
.closer a.button.primary {
  background: var(--bus);
  border-color: var(--bus);
  color: #241a00;
}

/* --- Sections ------------------------------------------------------------- */

.band {
  padding: 3.5rem 1.25rem;
}

.band--dark {
  background: var(--ink);
  color: var(--on-dark);
}

.band--dark .muted,
.band--dark .band__lede { color: var(--on-dark-muted); }

.band--dark a { color: var(--bus); }

.band__inner {
  max-width: 58rem;
  margin: 0 auto;
}

.band h2 {
  font-size: clamp(1.5rem, 4vw, 2.1rem);
  line-height: 1.15;
  letter-spacing: -0.02em;
  margin: 0 0 0.6rem;
  text-wrap: balance;
}

.band__lede {
  margin: 0 0 2rem;
  font-size: 1.05rem;
  color: var(--muted);
  max-width: 40rem;
}

/* --- Feature cards -------------------------------------------------------- */

.features {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}

.feature {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.25rem;
  box-shadow: var(--shadow);
}

.feature__icon {
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent);
  margin-bottom: 0.8rem;
}

.feature__icon svg { width: 1.4rem; height: 1.4rem; }

.feature h3 { margin: 0 0 0.35rem; font-size: 1.05rem; }
.feature p { margin: 0; color: var(--muted); font-size: 0.95rem; }

/* --- Steps, beside a photograph ------------------------------------------- */

.split {
  display: grid;
  gap: 2rem;
  align-items: center;
  grid-template-columns: 1fr;
}

@media (min-width: 52rem) {
  .split { grid-template-columns: 1.1fr 0.9fr; }
  .split--flip > :first-child { order: 2; }
}

.split__photo {
  width: 100%;
  max-height: 26rem;
  object-fit: cover;
  border-radius: 16px;
  border: 1px solid var(--border);
}

/* Numbered rather than a bare <ol>: three steps are the spine of the page and
   want to be scannable without reading them. */
.bigsteps { list-style: none; margin: 0; padding: 0; counter-reset: step; }

.bigsteps > li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 2.25rem 1fr;
  gap: 0.9rem;
  margin-bottom: 1.25rem;
}

.bigsteps > li:last-child { margin-bottom: 0; }

.bigsteps > li::before {
  content: counter(step);
  width: 2.25rem;
  height: 2.25rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  font-weight: 800;
  background: var(--bus);
  color: #241a00;
}

.bigsteps h3 { margin: 0 0 0.2rem; font-size: 1.02rem; }
.bigsteps p { margin: 0; color: var(--muted); font-size: 0.95rem; }
.band--dark .bigsteps p { color: var(--on-dark-muted); }

/* --- Promises ------------------------------------------------------------- */

.promises {
  display: grid;
  gap: 1.25rem 2rem;
  /* Wide enough that four promises settle into two columns rather than three
     and a conspicuous hole. */
  grid-template-columns: repeat(auto-fit, minmax(21rem, 1fr));
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
}

.promises > li {
  display: grid;
  grid-template-columns: 1.4rem 1fr;
  gap: 0.7rem;
  font-size: 0.98rem;
  color: var(--on-dark-muted);
}

.promises svg { width: 1.4rem; height: 1.4rem; color: var(--bus); margin-top: 0.1rem; }
.promises strong { display: block; color: var(--on-dark); font-size: 1rem; margin-bottom: 0.15rem; }

/* --- Closing call to action ---------------------------------------------- */

.closer {
  text-align: center;
  border: 1px solid var(--border);
  border-radius: 18px;
  background: var(--surface);
  padding: 2.25rem 1.5rem;
  box-shadow: var(--shadow);
}

.closer h2 { margin-bottom: 0.5rem; }
.closer .row { justify-content: center; }

/* --- Motion --------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .route__done,
  .route__bus,
  .route__bus-glow,
  .alert-demo { animation: none; }

  /* Parked partway along, which is the same story told without movement. */
  .route__done { stroke-dashoffset: 130; }
  .route__bus { offset-distance: 58%; }
}
