@font-face {
  font-family: "Playwrite BE VLG";
  src: url("assets/playwrite_bevlg.ttf") format("truetype");
  font-weight: 100 400; /* a variable font that stops at 400 */
  font-display: swap;
}

:root {
  /* Ploop's palette (app/src/main/res/values/colors.xml). */
  --black: #000000;
  --white: #FFFFFF;
  --paper: #F2F0EF;      /* light_gray / offwhite */
  --beige: #E8E5DF;
  --band: #E6E4E3;       /* summary_band */
  --ink-soft: #353535;   /* light_black */
  --orange: #FD6A1E;     /* brand_orange */
  --spark: #F4B400;      /* favorite_active */
  --wave-green: #83C295;
  --wave-amber: #F2C45B;
  --wave-red: #E87568;
  --neutral: #1A1A1A;    /* NEUTRAL_1000 */

  --sans: "Instrument Sans", system-ui, sans-serif;
  --serif: "Instrument Serif", Georgia, serif;
  --hand: "Playwrite BE VLG", "Segoe Print", cursive;
  /* Labels inside the drawings: a marker handwriting that stays legible at small sizes. */
  --doodle: "Shantell Sans", "Segoe Print", cursive;

  --measure: 34rem;
  --gutter: clamp(20px, 5vw, 72px);
}

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

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

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 1.125rem;
  line-height: 1.55;
  color: var(--black);
  background: var(--black);
  -webkit-font-smoothing: antialiased;
}

h1, h2, p { margin: 0; }
img, svg { display: block; }

a { color: inherit; }

:focus-visible {
  outline: 3px solid var(--orange);
  outline-offset: 3px;
  border-radius: 8px;
}

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

/* The hero and the tracks share one sky. Layers, bottom up: tracks, clouds, hero text. */
.sky-wrap {
  position: relative;
  background: var(--beige);
  overflow: hidden;
  touch-action: pan-y;
}

.hero {
  position: relative;
  z-index: 2;
  min-height: max(640px, min(100svh, 860px));
  display: grid;
  grid-template-rows: auto 1fr;
}

.hero-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 48px;
  max-width: 1320px;
  width: 100%;
  margin: 0 auto;
  padding: 8px var(--gutter) 14vh;
}

.sky {
  position: absolute;
  z-index: 1;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.nav {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: 1320px;
  width: 100%;
  margin: 0 auto;
  padding: 20px var(--gutter);
  pointer-events: none;
}
.nav a { pointer-events: auto; }
.nav-links {
  display: flex;
  align-items: center;
  gap: 8px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}

/* The launcher art fills only pixels 107-329 x 114-301 of its 432px square. Scale it so that
   area is 50px tall and crop to it, with 3px to spare all round. */
.brand-mark {
  --s: 0.2674;
  flex: none;
  width: calc(222px * var(--s) + 6px);
  height: calc(187px * var(--s) + 6px);
  overflow: hidden;
  position: relative;
}
.brand-mark img {
  position: absolute;
  width: calc(432px * var(--s));
  height: calc(432px * var(--s));
  left: calc(3px - 107px * var(--s));
  top: calc(3px - 114px * var(--s));
}

.brand-name {
  font-family: var(--hand);
  /* The font's heaviest real weight. Asking for bold made the browser smear it into a fake one. */
  font-weight: 400;
  font-synthesis: none;
  font-size: 1.75rem;
  line-height: 1.4;
  /* Playwrite sits high in its line box; nudge it to line up with the logo. */
  padding-top: 0.15em;
}
.brand-name.small { font-size: 1.25rem; }

.nav-link {
  font-weight: 500;
  text-decoration: none;
  padding: 9px 16px;
  border-radius: 999px;
}
.nav-link:hover { background: rgba(0, 0, 0, 0.06); }

.hero-copy {
  max-width: 44rem;
  pointer-events: none;
}
.hero-copy a { pointer-events: auto; }

h1 {
  font-family: var(--serif);
  font-weight: 400;
  font-synthesis: none;
  font-size: clamp(4.2rem, 8.8vw, 8.6rem);
  white-space: nowrap;
  line-height: 0.92;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

/* The italic accent in each heading, in the brand orange. */
h1 em, h2 em {
  font-style: italic;
  color: var(--orange);
  /* Italics lean out past their box; leave them room so nothing gets clipped. */
  padding-right: 0.06em;
}

.lede {
  margin-top: 28px;
  max-width: 30rem;
  font-size: clamp(1.125rem, 1.6vw, 1.3rem);
  color: var(--ink-soft);
}

.actions {
  margin-top: 36px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 24px;
}

.btn {
  display: inline-flex;
  align-items: center;
  min-height: 52px;
  padding: 0 26px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 1.05rem;
  text-decoration: none;
  transition: transform 160ms ease;
}
.btn-small { min-height: 40px; padding: 0 18px; font-size: 0.95rem; }
.btn-solid { background: var(--black); color: var(--white); }
.btn-solid:hover { background: var(--orange); color: var(--black); }
.btn:active { transform: scale(0.97); }

.soon {
  font-family: var(--hand);
  font-size: 0.95rem;
  color: var(--ink-soft);
}

/* ---------- Sketches ---------- */

/* The illustrations are drawn, not screenshots: ink outlines with a hand wobble (the #ink filter),
   handwritten labels, and marker colour. */
.defs { position: absolute; width: 0; height: 0; overflow: hidden; }

.sketch { filter: url(#ink); }

/* Hand-drawn boxes are never quite even. */
.phone, .screen, .app-card, .app-track, .app-nav,
.map, .track-bar, .station-card, .planner-card, .dir, .ends p, .grid li {
  border: 2.5px solid var(--black);
}
.app-card, .app-track, .track-bar, .station-card, .planner-card, .grid li {
  border-radius: 22px 28px 20px 26px / 26px 20px 28px 22px;
}
.dir, .ends p { border-radius: 14px 18px 12px 16px / 16px 12px 18px 14px; }

/* A marker blob of the line's colour with its ink outline printed slightly off, like a sticker. */
.marker {
  position: relative;
  background: var(--line);
}
.marker::after {
  content: "";
  position: absolute;
  inset: -1px;
  border: 2.5px solid var(--black);
  border-radius: inherit;
  transform: translate(-3px, -2px);
}

.route-pill {
  background: var(--white);
  color: var(--black);
  border: 2px solid var(--black);
  font-family: var(--doodle);
  font-size: 0.8rem;
  padding: 1px 10px 3px;
  border-radius: 999px;
}

/* ---------- Phone ---------- */

.phone {
  position: relative;
  width: 300px;
  padding: 9px;
  border-width: 3px;
  border-radius: 50px 54px 46px 52px;
  background: var(--white);
  box-shadow: 12px 14px 0 -2px rgba(0, 0, 0, 0.1);
  transform: rotate(2deg);
  pointer-events: none;
}
.screen {
  position: relative;
  height: 600px;
  border-radius: 40px 44px 38px 42px;
  background: var(--paper);
  color: var(--black);
  overflow: hidden;
  padding: 14px 14px 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-family: var(--doodle);
  font-size: 0.8rem;
}
.app-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 2px 12px 0;
  font-size: 0.75rem;
}
.app-icons { display: flex; gap: 4px; }
.app-icons i { width: 14px; height: 9px; border: 2px solid var(--black); border-radius: 3px; }
.app-icons i:first-child { width: 9px; border-radius: 50%; }
.app-head {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 8px 2px 4px;
}
.app-head .brand-name { font-size: 1.45rem; }
.app-mark { --s: 0.17; }

.app-card,
.app-track {
  background: var(--white);
  padding: 12px;
}
.app-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.app-chip {
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  color: var(--white);
  font-size: 0.72rem;
}
.app-col { display: grid; min-width: 0; line-height: 1.5; }
.app-col strong { font-weight: 600; font-size: 0.85rem; }
.app-col span { font-size: 0.66rem; color: #6D6965; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.app-eta { font-weight: 600; margin-left: auto; font-size: 1rem; white-space: nowrap; }
.app-status {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding-top: 6px;
  border-top: 2px dashed #B9B5B1;
  font-size: 0.7rem;
}
.app-status svg {
  width: 36px;
  height: 10px;
  fill: none;
  stroke: var(--wave-green);
  stroke-width: 3;
  stroke-linecap: round;
}
.app-status-amber svg { stroke: var(--wave-amber); }
.app-track .app-row { gap: 8px; }
.app-track .route-pill { font-size: 0.68rem; padding: 0 7px 2px; }
.app-track-title { font-size: 0.7rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.app-track .track-eta { font-size: 0.7rem; }
.app-track .progress { margin-top: 10px; height: 9px; }

.app-grid { padding: 2px 4px 0; }
.app-grid-title { font-size: 0.75rem; }
.app-grid-tiles {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 7px;
  margin-top: 6px;
}
.app-grid-tiles i {
  aspect-ratio: 1;
  border-radius: 9px 11px 8px 10px;
}
/* A status dot on each tile, as on The Grid. */
.app-grid-tiles i::before {
  content: "";
  position: absolute;
  z-index: 1;
  right: -4px;
  bottom: -4px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--wave-green);
  border: 2px solid var(--black);
}
.app-grid-tiles i.amber::before { background: var(--wave-amber); }
.app-grid-tiles i.red::before { background: var(--wave-red); }

.app-nav {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  display: flex;
  gap: 2px;
  padding: 4px;
  border-radius: 999px;
  background: var(--white);
  font-size: 0.75rem;
}
.app-nav span { padding: 6px 14px 8px; border-radius: 999px; }
.app-nav .on { background: var(--spark); }

.hint {
  margin-left: 12px;
  display: flex;
  align-items: flex-start;
  gap: 2px;
  font-family: var(--hand);
  font-size: 0.95rem;
  line-height: 1.7;
  color: var(--ink-soft);
  pointer-events: none;
  transform: rotate(-3deg);
}
.hint svg {
  margin-top: 14px;
  transform: rotate(25deg);
  fill: none;
  stroke: var(--ink-soft);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.hint.gone { opacity: 0; transition: opacity 600ms ease; }

/* ---------- Tracks ---------- */

.tracks {
  position: relative;
  height: clamp(170px, 20vw, 260px);
  margin-top: -1px;
}
.tracks svg {
  width: 100%;
  height: 100%;
}
.tracks .ribbon {
  fill: none;
  stroke-linecap: butt;
  transition: stroke-width 200ms ease;
}
.tracks .hit {
  fill: none;
  stroke: transparent;
  pointer-events: stroke;
  cursor: help;
}
/* Trains are HTML on top of the SVG so their movement is composited at sub-pixel precision. */
.train {
  position: absolute;
  left: 0;
  top: 0;
  border-radius: 999px;
  background: var(--white);
  pointer-events: none;
  will-change: transform;
}
.track-tip {
  position: absolute;
  pointer-events: none;
  padding: 6px 14px 8px;
  border-radius: 999px;
  background: var(--black);
  color: var(--white);
  font-family: var(--hand);
  font-size: 0.85rem;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, -150%);
  transition: opacity 120ms ease;
}
.track-tip.on { opacity: 1; }

/* ---------- Features ---------- */

.dark {
  background: var(--black);
  color: var(--paper);
  padding: clamp(56px, 8vw, 112px) var(--gutter) clamp(80px, 10vw, 140px);
  display: grid;
  gap: clamp(72px, 9vw, 128px);
  overflow-x: clip; /* the tilted pages must not cause sideways scrolling */
}

.feature {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(32px, 6vw, 88px);
  align-items: center;
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
}
.feature.flip { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
.feature.flip .feature-text { order: 2; }

.feature-text { max-width: var(--measure); }
.feature-text p { color: #B9B5B1; }
.feature-text p:first-of-type { color: var(--paper); font-size: 1.2rem; }
.feature-text p + p { margin-top: 1em; }

h2 {
  font-family: var(--serif);
  font-weight: 400;
  font-synthesis: none;
  font-size: clamp(2.6rem, 5.2vw, 4.2rem);
  line-height: 0.98;
  letter-spacing: -0.015em;
  margin-bottom: 24px;
  text-wrap: balance;
}

/* Each illustration is a sketchbook page taped onto the dark background, tilted a little. */
.stage {
  position: relative;
  margin: 0;
  min-height: 460px;
  padding: clamp(28px, 4vw, 52px);
  border-radius: 4px;
  background: var(--paper);
  color: var(--black);
  display: grid;
  place-items: center;
  transform: rotate(-1deg);
  box-shadow: 0 30px 60px -30px rgba(0, 0, 0, 0.7);
}
.feature.flip .stage { transform: rotate(1deg); }
.feature-grid .stage { transform: rotate(-0.5deg); }
.stage > * { width: 100%; }
/* Masking tape along the top. */
.stage::before {
  content: "";
  position: absolute;
  top: -15px;
  left: 50%;
  width: 128px;
  height: 32px;
  background: #EFCB5E;
  transform: translateX(-50%) rotate(-3deg);
  clip-path: polygon(0 8%, 4% 0, 8% 10%, 12% 0, 16% 8%, 100% 0, 96% 50%, 100% 100%, 0 92%, 4% 50%);
}
.stage > :not(.note) { filter: url(#ink); }

.note {
  position: absolute;
  z-index: 1;
  font-family: var(--hand);
  font-size: 0.95rem;
  line-height: 1.7;
  color: var(--orange);
  transform: rotate(-4deg);
  width: auto;
}

/* Live map */

.map-mock { display: block; padding-top: 76px; }
.map-mock .map {
  width: 100%;
  height: auto;
  background: var(--white);
}
.map text { font-family: var(--doodle); }

.track-bar {
  position: relative;
  margin: -58px 18px 0;
  padding: 12px 18px 16px;
  background: var(--white);
  font-family: var(--doodle);
}
.track-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.track-title { font-size: 0.95rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.track-eta {
  margin-left: auto;
  color: var(--orange);
  white-space: nowrap;
  font-size: 0.95rem;
}
/* A progress bar coloured in with pencil strokes. */
.progress {
  margin-top: 12px;
  height: 12px;
  border: 2px solid var(--black);
  border-radius: 999px;
  background: var(--white);
  overflow: hidden;
}
.progress span {
  display: block;
  height: 100%;
  width: 62%;
  background: repeating-linear-gradient(-55deg, var(--black) 0 2px, transparent 2px 5px);
  border-right: 2px solid var(--black);
}
.note-map { right: clamp(24px, 4vw, 52px); top: 14px; }

/* Station card */

.station-card,
.planner-card {
  background: var(--white);
  padding: 22px;
  max-width: 420px;
  font-family: var(--doodle);
}

.station-head {
  display: flex;
  align-items: center;
  gap: 14px;
}
.line-chip {
  flex: none;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  color: var(--white);
  font-size: 0.9rem;
}
.station-name { font-weight: 600; font-size: 1.15rem; line-height: 1.5; }
.station-sub { color: #6D6965; font-size: 0.78rem; }
.star {
  margin-left: auto;
  width: 30px;
  height: 30px;
  fill: var(--spark);
  stroke: var(--black);
  stroke-width: 1.6;
  stroke-linejoin: round;
}

.dir {
  margin-top: 14px;
  padding: 8px 14px 10px;
}
.towards { font-size: 0.78rem; color: #6D6965; }
.times { display: flex; gap: 18px; align-items: baseline; margin-top: 2px; }
.times strong { font-weight: 600; font-size: 1.25rem; }
.times span { font-size: 0.85rem; color: var(--ink-soft); }

.status {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
  font-size: 0.85rem;
}
.status svg {
  width: 72px;
  height: 12px;
  fill: none;
  stroke: var(--wave-green);
  stroke-width: 3.5;
  stroke-linecap: round;
}

.last {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 2px dashed #B9B5B1;
  font-size: 0.78rem;
  color: #6D6965;
}
.last span:first-child { margin-right: 4px; }
.pill {
  padding: 1px 12px 3px;
  border: 2px solid var(--black);
  border-radius: 999px;
  color: var(--black);
}

/* Planner */

.ends {
  display: grid;
  gap: 8px;
}
.ends p {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 14px 10px;
}
.dot {
  flex: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2.5px solid var(--black);
}
.dot-end { background: var(--orange); }

.timeline {
  list-style: none;
  margin: 18px 0 0;
  padding: 0 0 0 4px;
}
.timeline li {
  position: relative;
  padding: 0 0 16px 28px;
  display: grid;
}
/* Each leg of the trip is a stroke of that line's colour, outlined in ink. */
.timeline li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 4px;
  bottom: 2px;
  width: 11px;
  border-radius: 8px;
  background: var(--line);
  border: 2px solid var(--black);
}
.timeline li + li { margin-top: 4px; }
.timeline strong { font-weight: 600; font-size: 0.95rem; }
.timeline span { color: #6D6965; font-size: 0.75rem; }

.fare {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 8px 14px 10px;
  border: 2px dashed var(--black);
  border-radius: 14px;
  font-size: 0.85rem;
}
.fare strong { font-weight: 600; font-size: 1.2rem; }

.recent {
  display: inline-block;
  margin-top: 14px;
  padding: 2px 14px 4px;
  border-radius: 999px;
  border: 2px solid var(--black);
  font-size: 0.75rem;
}

/* The Grid */

.feature-grid {
  grid-template-columns: 1fr;
  gap: 48px;
}
.grid-mock { min-height: 0; }
.grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-flow: dense;
  gap: 14px;
}
/* Tiles coloured in with marker, the strokes showing. */
.grid li {
  position: relative;
  min-height: 132px;
  padding: 16px 18px;
  background:
    repeating-linear-gradient(-50deg, transparent 0 7px, rgba(255, 255, 255, 0.22) 7px 9px),
    var(--line);
  color: var(--ink);
  font-family: var(--doodle);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.grid li.wide { grid-column: span 2; }
.grid .name { font-weight: 600; font-size: 1rem; line-height: 1.5; }
.grid .state {
  display: flex;
  align-items: center;
  font-size: 0.8rem;
}
.grid .state .badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 1px 12px 3px 8px;
  border-radius: 999px;
  border: 2px solid var(--black);
  background: var(--white);
  color: var(--black);
}
.grid .badge i {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 2px solid var(--black);
  background: var(--wave);
}

.grid li { cursor: pointer; transition: transform 160ms ease; }
.grid li:hover { transform: rotate(-0.6deg) translateY(-2px); }
.grid li:active { transform: scale(0.97); }
.grid .sob {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 52px;
  height: 48px;
  overflow: visible;
  opacity: 0;
  transform: translateY(-8px) scale(0.7);
  transition: opacity 250ms ease, transform 350ms cubic-bezier(0.3, 1.6, 0.5, 1);
  pointer-events: none;
}
.grid li.bad .sob { opacity: 1; transform: none; }
.sob-cloud { fill: var(--paper); stroke: var(--black); stroke-width: 2.2; stroke-linejoin: round; }
.sob-face { fill: none; stroke: var(--black); stroke-width: 1.8; stroke-linecap: round; }
.sob .tear {
  fill: none;
  stroke: #3D8BD9;
  stroke-width: 2.6;
  stroke-linecap: round;
  animation: tear 900ms linear infinite;
}
.sob .tear:nth-of-type(4) { animation-delay: 300ms; }
.sob .tear:nth-of-type(5) { animation-delay: 600ms; }
@keyframes tear {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(12px); opacity: 0; }
}

.note-grid { right: clamp(24px, 4vw, 52px); top: -46px; }
.note-station { right: clamp(18px, 3vw, 40px); bottom: 10px; transform: rotate(3deg); }

/* Station card, live bits */
.star-btn {
  margin-left: auto;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.star-btn .star { margin: 0; transition: fill 150ms ease, transform 250ms cubic-bezier(0.3, 1.8, 0.5, 1); }
.star-btn[aria-pressed="false"] .star { fill: var(--white); transform: scale(0.85); }
.star-btn:active .star { transform: scale(1.3) rotate(15deg); }
.times .arriving { color: var(--orange); animation: blink 1s steps(2, start) infinite; }
@keyframes blink { to { visibility: hidden; } }

/* ---------- The Ploop line ---------- */

/* Each feature is a station, labelled the way KL labels its stations: a code chip and a name. */
.stop {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
  font-family: var(--doodle);
  font-size: 0.95rem;
  color: #B9B5B1;
}
.stn {
  position: relative;
  flex: none;
  display: inline-block;
  padding: 0 10px 2px;
  border-radius: 999px;
  background: var(--orange);
  color: var(--black);
  font-family: var(--doodle);
  font-weight: 600;
  font-size: 0.8rem;
  line-height: 1.6;
}
/* Ink outline printed slightly off, like the line chips in the drawings. */
.stn::after {
  content: "";
  position: absolute;
  inset: -1px;
  border: 2px solid var(--stn-ink, var(--black));
  border-radius: inherit;
  transform: translate(-3px, -2px);
}
.dark .stn { --stn-ink: var(--paper); }

/* The rail down the margin, with its train. */
.dark { position: relative; }
.rail {
  position: absolute;
  top: 0;
  left: 0;
  overflow: visible;
  pointer-events: none;
}
.rail-marker { fill: none; stroke: var(--orange); stroke-opacity: 0.5; stroke-width: 14; stroke-linecap: round; }
.rail-ink { fill: none; stroke: var(--paper); stroke-width: 2.5; stroke-linecap: round; }
.rail-buffer { fill: none; stroke: var(--paper); stroke-width: 3; stroke-linecap: round; }
.rail .dot {
  fill: var(--black);
  stroke: var(--paper);
  stroke-width: 3;
  cursor: pointer;
  pointer-events: all;
  transition: fill 250ms ease;
}
.rail .dot:hover { stroke: var(--orange); }
.rail .dot.passed { fill: var(--orange); }
.rail-train { cursor: pointer; pointer-events: all; }
.train-body { transform-box: fill-box; transform-origin: center; }
.train-body.toot { animation: toot 550ms ease; }
@keyframes toot {
  30% { transform: scale(1.3, 0.8); }
  60% { transform: scale(0.9, 1.1); }
}
.rail .car { fill: var(--paper); stroke: var(--black); stroke-width: 2; }
.rail .win, .rail .eye { fill: var(--black); }
.rail .coupler { stroke: var(--paper); stroke-width: 3; }
.rail .mouth { fill: none; stroke: var(--black); stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; }
.rail .cheek { fill: rgba(244, 143, 177, 0.9); }

/* The PA strip. */
.pa {
  position: fixed;
  z-index: 20;
  left: 50%;
  bottom: max(16px, env(safe-area-inset-bottom));
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: calc(100vw - 24px);
  padding: 7px 18px 8px 12px;
  border: 2.5px solid var(--black);
  border-radius: 999px;
  background: var(--paper);
  color: var(--black);
  font: 500 0.95rem/1.5 var(--doodle);
  cursor: pointer;
  box-shadow: 6px 7px 0 -1px rgba(0, 0, 0, 0.3);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 24px);
  transition: opacity 250ms ease, transform 250ms ease, visibility 0s 250ms;
}
.pa.on {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
  transition-delay: 0s;
}
.pa:hover { background: var(--white); }
.pa-icon {
  flex: none;
  width: 22px;
  height: 22px;
  fill: none;
  stroke: var(--black);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pa-icon .pa-cone { fill: var(--black); }
.pa-text { display: flex; align-items: center; gap: 10px; min-width: 0; }
.pa-text.swap { animation: pa-swap 400ms ease; }
@keyframes pa-swap { from { opacity: 0; transform: translateY(8px); } }
.pa-kind { color: #6D6965; white-space: nowrap; }
.pa-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---------- Outro ---------- */

.stop-end { color: var(--ink-soft); margin-bottom: 22px; }

.faregate {
  position: relative;
  width: min(400px, 100%);
  margin: 12px auto 0;
}
.gate-art { width: 100%; height: auto; overflow: visible; filter: url(#ink); }
.gate-art .floor { fill: none; stroke: var(--black); stroke-width: 3; stroke-linecap: round; }
.gate-art .pedestal { fill: var(--white); stroke: var(--black); stroke-width: 3; }
.gate-art .flap path { fill: var(--orange); stroke: var(--black); stroke-width: 3; }
.gate-art .flap {
  transform-box: fill-box;
  transition: transform 500ms cubic-bezier(0.3, 1.4, 0.5, 1);
}
.gate-art .flap-l { transform-origin: left center; }
.gate-art .flap-r { transform-origin: right center; }
.faregate.open .flap { transform: scaleX(0.1); }
.gate-art .reader { fill: var(--paper); stroke: var(--black); stroke-width: 3; transition: fill 200ms ease; }
.faregate.near .reader { fill: #FBD3BD; }
.faregate.open .reader { fill: var(--wave-green); }
.gate-art .waves { fill: none; stroke: var(--black); stroke-width: 2.5; stroke-linecap: round; }
.gate-art .panel { fill: var(--black); }
.gate-say {
  font-family: var(--doodle);
  font-size: 15px;
  font-weight: 700;
  text-anchor: middle;
  fill: var(--wave-amber);
}
.faregate.open .gate-say { fill: var(--wave-green); }

/* A blue token, like the ones the LRT gates take. */
.token {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 72%;
  width: 62px;
  height: 62px;
  padding: 0;
  border: 3px solid var(--black);
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #74A6F2, #2D6CD8 60%, #1F4FA8);
  box-shadow: inset 0 0 0 5px rgba(255, 255, 255, 0.28), 4px 5px 0 -1px rgba(0, 0, 0, 0.18);
  color: var(--white);
  font: 600 0.72rem/1 var(--doodle);
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  transition: transform 450ms cubic-bezier(0.5, 0, 0.3, 1), opacity 300ms ease;
}
.token:hover { box-shadow: inset 0 0 0 5px rgba(255, 255, 255, 0.28), 6px 8px 0 -1px rgba(0, 0, 0, 0.22); }
.token.held { cursor: grabbing; transition: none; }
.token.pop { animation: token-pop 450ms cubic-bezier(0.3, 1.6, 0.5, 1); }
@keyframes token-pop { from { transform: scale(0); } }
.note-gate { left: 30%; top: 4px; }

.gate-msg {
  min-height: 1.7em;
  margin-top: 14px;
  font-family: var(--hand);
  font-size: 0.95rem;
  color: var(--ink-soft);
}

.outro {
  background: var(--beige);
  padding: clamp(72px, 10vw, 140px) var(--gutter);
  display: grid;
  justify-items: center;
  text-align: center;
}
.outro-mark { --s: 0.5; margin-bottom: 28px; }
.outro h2 { max-width: 14ch; }
.outro .actions { justify-content: center; margin-top: 8px; }

.footer {
  background: var(--beige);
  color: var(--ink-soft);
  font-size: 0.9rem;
  padding: 24px var(--gutter) 36px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 24px;
  border-top: 1px solid #D5D1CA;
}
.footer-mark { --s: 0.14; }
.footer .brand { gap: 6px; }

/* ---------- Small screens ---------- */

@media (max-width: 860px) {
  .feature,
  .feature.flip { grid-template-columns: minmax(0, 1fr); }
  .feature.flip .feature-text { order: 0; }
  .stage { min-height: 0; }
  .hero { min-height: 0; }
  .hero-body { grid-template-columns: minmax(0, 1fr); padding-bottom: 260px; }
  .phone { display: none; }
  .nav-link { display: none; }
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .grid .state .badge { white-space: nowrap; font-size: 0.8rem; }
  .grid li { min-height: 116px; padding: 14px; }
  .grid .name { font-size: 1rem; }
  .grid .state { font-size: 0.85rem; }
  .grid .sob { width: 40px; height: 37px; top: 4px; right: 4px; }
  .note-grid { top: -42px; }
  .pa { font-size: 0.85rem; gap: 8px; padding: 6px 14px 7px 10px; }
  .pa-text { gap: 8px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* ---------- Paper grain ---------- */

/* A faint speckle over everything, like the page is printed on paper. It shuffles a few times a
   second so it reads as texture, not as a pattern. */
body::after {
  content: "";
  position: fixed;
  z-index: 101;
  inset: -120px;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.5 0 0 0 0 0.45 0 0 0 0 0.4 1.6 0 0 0 -0.55'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: 0.22;
  will-change: transform;
  animation: grain 0.9s steps(1) infinite;
}
@keyframes grain {
  0% { transform: translate(0, 0); }
  20% { transform: translate(-48px, 30px); }
  40% { transform: translate(36px, -54px); }
  60% { transform: translate(-22px, -30px); }
  80% { transform: translate(52px, 40px); }
}

/* ---------- Intro ---------- */

.preloader {
  display: none;
  position: fixed;
  z-index: 100;
  inset: 0;
  place-items: center;
  background: var(--beige);
}
.intro .preloader { display: grid; }
.intro { overflow: hidden; }
.pre-inner { display: grid; justify-items: center; gap: 2px; }
.pre-mark { --s: 0.55; opacity: 0; }
.pre-name { font-size: 3rem; clip-path: inset(-30% 100% -70% 0); }
.pre-line {
  width: 170px;
  height: 16px;
  fill: none;
  stroke: var(--orange);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
.preloader.play .pre-mark { animation: pre-pop 700ms cubic-bezier(0.3, 1.6, 0.5, 1) forwards; }
.preloader.play .pre-name { animation: write 1s cubic-bezier(0.45, 0, 0.3, 1) 350ms forwards; }
.preloader.play .pre-line { animation: draw 600ms ease-out 1.05s forwards; }
/* Out: the logo squashes like a cloud being tapped, and the page irises open around it. */
.preloader.out { animation: iris 800ms cubic-bezier(0.7, 0, 0.2, 1) forwards; }
.preloader.out .pre-mark { animation: squish 500ms ease forwards; opacity: 1; }
@keyframes pre-pop {
  from { opacity: 0; scale: 0.3; rotate: -14deg; }
  to { opacity: 1; scale: 1; rotate: 0deg; }
}
@keyframes squish {
  0% { scale: 1; }
  35% { scale: 1.25 0.72; }
  100% { scale: 0.5; opacity: 0; }
}
@keyframes iris {
  from { clip-path: circle(150% at 50% 46%); }
  to { clip-path: circle(0% at 50% 46%); }
}
@keyframes write {
  from { clip-path: inset(-30% 100% -70% 0); }
  to { clip-path: inset(-30% -10% -70% 0); }
}
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes rise { from { opacity: 0; translate: 0 28px; } }

/* ---------- Entrances ---------- */

/* Everything here is only hidden for people happy to see motion, and only once JavaScript is
   there to bring it back. */
@media (prefers-reduced-motion: no-preference) {
  /* Hero */
  .js:not(.go) :is(.nav, .lede, .hero-copy .actions, .phone) { opacity: 0; }
  .js:not(.go) .tracks { clip-path: inset(0 100% 0 0); }
  .js:not(.go) .screen > * { opacity: 0; }

  .go .nav { animation: rise 800ms cubic-bezier(0.22, 1, 0.36, 1) backwards; }
  .js:not(.go) .hint { opacity: 0; }
  .go .hint { animation: rise 900ms cubic-bezier(0.22, 1, 0.36, 1) 1.2s backwards; }
  .go .lede { animation: rise 900ms cubic-bezier(0.22, 1, 0.36, 1) 550ms backwards; }
  .go .hero-copy .actions { animation: rise 900ms cubic-bezier(0.22, 1, 0.36, 1) 700ms backwards; }
  .go .phone { animation: phone-in 1.2s cubic-bezier(0.22, 1, 0.36, 1) 250ms backwards; }
  .go .screen > * { animation: rise 700ms cubic-bezier(0.22, 1, 0.36, 1) backwards; animation-delay: calc(650ms + var(--i, 0) * 90ms); }
  .go .tracks { animation: lay 1.4s cubic-bezier(0.65, 0, 0.35, 1) 150ms backwards; }

  /* The headline sharpens out of a blur, one letter after another. */
  .hero h1 .char {
    display: inline-block;
    white-space: pre;
    opacity: 0;
    filter: blur(16px);
    translate: 0 0.12em;
    transition: filter 1.4s cubic-bezier(0.16, 1, 0.3, 1), opacity 900ms ease-out, translate 1.4s cubic-bezier(0.16, 1, 0.3, 1);
    transition-delay: calc(150ms + var(--i) * 60ms);
  }
  .go .hero h1 .char { opacity: 1; filter: blur(0); translate: 0 0; }

  /* Headings rise word by word from under an invisible edge. */
  .split .w {
    display: inline-block;
    overflow: hidden;
    vertical-align: top;
    padding: 0.06em 0 0.16em;
    margin: -0.06em 0 -0.16em;
  }
  .split .w > span {
    display: inline-block;
    translate: 0 110%;
    transition: translate 1s cubic-bezier(0.22, 1, 0.36, 1);
    transition-delay: calc(100ms + var(--i) * 70ms);
  }
  .in .split .w > span { translate: 0 0; }

  /* The words around each heading follow it in. */
  .js .feature-text:not(.in) > :not(h2),
  .js .outro:not(.in) > :not(h2) { opacity: 0; }
  .feature-text.in > :not(h2),
  .outro.in > :not(h2) {
    animation: rise 900ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
    animation-delay: calc(var(--i) * 110ms);
  }

  /* Each page is slapped down, then taped. */
  .js .stage:not(.in),
  .js .stage:not(.in)::before { opacity: 0; }
  .stage.in { animation: page-in 1.1s cubic-bezier(0.22, 1, 0.36, 1) backwards; }
  .stage.in::before { animation: tape-in 500ms cubic-bezier(0.3, 1.6, 0.5, 1) 650ms backwards; }

  /* Then the bits on it arrive. */
  .js .stage:not(.in) :is(.station-card, .planner-card) > *,
  .js .stage:not(.in) .grid li,
  .js .stage:not(.in) .track-bar { opacity: 0; }
  .stage.in :is(.station-card, .planner-card) > * {
    animation: rise 700ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
    animation-delay: calc(400ms + var(--i) * 90ms);
  }
  .stage.in .track-bar { animation: rise 800ms cubic-bezier(0.22, 1, 0.36, 1) 900ms backwards; }
  .stage.in .grid li {
    animation: tile-in 650ms cubic-bezier(0.3, 1.5, 0.5, 1) backwards;
    animation-delay: calc(350ms + var(--i) * 70ms);
  }
  .js .stage:not(.in) .timeline li::before { scale: 1 0; }
  .timeline li::before { transform-origin: top; }
  .timeline li:nth-child(2) { --n: 1; }
  .stage.in .timeline li::before {
    animation: leg 700ms cubic-bezier(0.45, 0, 0.25, 1) backwards;
    animation-delay: calc(800ms + var(--n, 0) * 400ms);
  }

  /* The handwritten notes write themselves, last. */
  .js .stage:not(.in) .note { clip-path: inset(-30% 100% -70% 0); }
  .stage.in .note { animation: write 1.1s cubic-bezier(0.45, 0, 0.3, 1) 1.3s backwards; }
}

@keyframes phone-in {
  from { opacity: 0; translate: 0 140px; rotate: 7deg; }
}
@keyframes lay {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 0 0 0); }
}
@keyframes page-in {
  from { opacity: 0; translate: 0 90px; rotate: -5deg; scale: 0.95; }
}
@keyframes tape-in {
  from { opacity: 0; scale: 1.6; rotate: -12deg; }
}
@keyframes tile-in {
  from { opacity: 0; scale: 0.7; rotate: -6deg; }
}
@keyframes leg {
  from { scale: 1 0; }
}

/* Italic words lean past their box; give them room inside the word-rise mask. */
.split em .w { padding-right: 0.1em; margin-right: -0.1em; }

/* ---------- Privacy policy ---------- */

.legal-page { background: var(--beige); }
.legal {
  max-width: 46rem;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 64px) var(--gutter) clamp(72px, 10vw, 120px);
  font-size: 1.05rem;
  color: var(--ink-soft);
}
.legal h1 { white-space: normal; font-size: clamp(3.4rem, 9vw, 6.4rem); color: var(--black); }
.legal h2 { font-size: clamp(2rem, 4.4vw, 2.8rem); margin: 0 0 16px; color: var(--black); }
.legal h3 { margin: 26px 0 8px; font-size: 1.1rem; font-weight: 600; color: var(--black); }
.legal p + p, .legal ul + p, .legal p + ul { margin-top: 0.9em; }
.legal ul { margin: 0; padding-left: 1.2em; }
.legal li + li { margin-top: 0.45em; }
.legal li::marker { color: var(--orange); }
.legal a { color: var(--black); text-decoration-color: var(--orange); text-decoration-thickness: 2px; text-underline-offset: 3px; }
.legal a:hover { color: var(--orange); }
.legal strong { color: var(--black); font-weight: 600; }
.legal section { margin-top: clamp(48px, 7vw, 72px); }

.legal-date { margin-top: 14px; font-family: var(--hand); font-size: 0.95rem; color: var(--orange); }
.legal-lede { margin-top: 20px; font-size: 1.25rem; color: var(--black); }

/* The short version: a page from the sketchbook, taped on. */
.tldr {
  position: relative;
  margin-top: 44px;
  padding: 34px clamp(22px, 4vw, 40px) 30px;
  background: var(--paper);
  border: 2.5px solid var(--black);
  border-radius: 22px 28px 20px 26px / 26px 20px 28px 22px;
  box-shadow: 10px 12px 0 -2px rgba(0, 0, 0, 0.1);
  transform: rotate(-0.8deg);
}
.tldr::before {
  content: "";
  position: absolute;
  top: -16px;
  left: 50%;
  width: 120px;
  height: 30px;
  background: #EFCB5E;
  transform: translateX(-50%) rotate(-3deg);
  clip-path: polygon(0 8%, 4% 0, 8% 10%, 12% 0, 16% 8%, 100% 0, 96% 50%, 100% 100%, 0 92%, 4% 50%);
}
.tldr ul { list-style: none; padding: 0; font-family: var(--doodle); font-size: 0.98rem; }
.tldr li { position: relative; padding-left: 30px; }
.tldr li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.45em;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid var(--black);
  background: var(--wave-green);
}

.legal-table-wrap { margin-top: 18px; overflow-x: auto; }
.legal-table {
  width: 100%;
  min-width: 34rem;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 0.95rem;
  background: var(--white);
  border: 2.5px solid var(--black);
  border-radius: 18px;
  overflow: hidden;
}
.legal-table th, .legal-table td { padding: 12px 14px; text-align: left; vertical-align: top; }
.legal-table th { font-family: var(--doodle); font-weight: 600; color: var(--black); background: var(--band); }
.legal-table tr + tr td, .legal-table tbody tr:first-child td { border-top: 2px dashed #D5D1CA; }
.legal-table td:first-child { color: var(--black); font-weight: 500; }
.legal-table + p, .legal-table-wrap + p { margin-top: 1em; }
.legal-note { font-size: 0.9rem; color: #6D6965; }

.footer a { color: inherit; text-decoration-color: var(--orange); text-underline-offset: 3px; }
.footer a.brand { text-decoration: none; }

/* ---------- Night ---------- */

/* The night sky fades in over the day one, so switching is a slow dusk, not a flash. */
.sky-wrap::before,
.sky-wrap::after {
  content: "";
  position: absolute;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 900ms ease, translate 900ms cubic-bezier(0.22, 1, 0.36, 1);
}
.sky-wrap::before {
  inset: 0;
  background: linear-gradient(180deg, #11162C 0%, #1D2142 45%, #3A2B52 78%, #5A3557 100%);
}
/* A crescent moon. */
.sky-wrap::after {
  top: 96px;
  left: 54%;
  width: 74px;
  height: 74px;
  border-radius: 50%;
  box-shadow: -16px 10px 0 0 #FFF4D6;
  filter: drop-shadow(0 0 18px rgba(255, 244, 214, 0.35));
  translate: 0 30px;
}
.night .sky-wrap::before { opacity: 1; }
.night .sky-wrap::after { opacity: 1; translate: 0 0; }

.night .hero h1,
.night .nav .brand-name,
.night .nav-link { color: var(--paper); transition: color 600ms ease; }
.night .lede, .night .hint { color: #CFCAD8; }
.night .hint svg { stroke: #CFCAD8; }
.night .nav-link:hover { background: rgba(255, 255, 255, 0.1); }
.night .hero .btn-solid { background: var(--paper); color: var(--black); }
.night .preloader { background: #161B33; }
.night .pre-name { color: var(--paper); }

.nav button { pointer-events: auto; }
.sky-toggle {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin-right: 4px;
  padding: 0;
  border: 2px solid currentColor;
  border-radius: 50%;
  background: none;
  color: var(--black);
  cursor: pointer;
  transition: rotate 500ms cubic-bezier(0.3, 1.5, 0.5, 1), background 200ms ease;
}
.sky-toggle:hover { background: rgba(0, 0, 0, 0.06); rotate: -20deg; }
.sky-toggle svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.sky-toggle .sky-moon { fill: currentColor; }
.sky-toggle .sky-sun { display: none; }
.night .sky-toggle { color: var(--paper); }
.night .sky-toggle:hover { background: rgba(255, 255, 255, 0.1); }
.night .sky-toggle .sky-moon { display: none; }
.night .sky-toggle .sky-sun { display: block; }

/* ---------- Departures board ---------- */

.board-wrap {
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
  display: grid;
  justify-items: center;
}
.board {
  --cell: clamp(9.5px, 2.25vw, 26px);
  --g: 2px;
  max-width: 100%;
  padding: clamp(12px, 2vw, 22px) clamp(10px, 2.2vw, 26px) clamp(14px, 2vw, 24px);
  background: #141414;
  border: 2.5px solid var(--paper);
  border-radius: 18px 22px 16px 20px / 20px 16px 22px 18px;
  box-shadow: inset 0 0 0 6px #0A0A0A, 0 30px 60px -30px rgba(0, 0, 0, 0.8);
  rotate: 0.6deg;
}
.board-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 10px;
}
.board-title { font: italic 400 clamp(1.5rem, 3.2vw, 2.4rem)/1 var(--serif); color: var(--orange); }
.board-clock { font: 600 clamp(0.8rem, 1.6vw, 1.1rem)/1 var(--doodle); color: var(--wave-amber); letter-spacing: 0.08em; }
.board-cols,
.board-row {
  display: grid;
  grid-template-columns:
    calc(var(--cell) * 2 + var(--g))
    calc(var(--cell) * 17 + var(--g) * 16)
    calc(var(--cell) * 5 + var(--g) * 4);
  column-gap: calc(var(--cell) * 0.6);
}
.board-cols {
  padding-bottom: 6px;
  font: 600 clamp(0.55rem, 1vw, 0.72rem)/1 var(--doodle);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #8A8580;
}
.board-cols span:last-child { text-align: right; }
.board-row { padding: calc(var(--cell) * 0.22) 0; border-top: 1px dashed #333; }
.board-line, .board-dest, .board-due { display: flex; gap: var(--g); }
.flap {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: none;
  width: var(--cell);
  height: calc(var(--cell) * 1.38);
  border-radius: calc(var(--cell) * 0.14);
  background: linear-gradient(#272727 50%, #1E1E1E 50%);
  color: var(--paper);
  font: 600 calc(var(--cell) * 0.8)/1 var(--sans);
}
/* The split down the middle of every flap. */
.flap::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: rgba(0, 0, 0, 0.75);
}
.board-line .flap { background: var(--line, #272727); color: var(--white); transition: background 200ms ease; }
.board-line .flap::before {
  content: "";
  position: absolute;
  inset: 50% 0 0;
  border-radius: 0 0 inherit inherit;
  background: rgba(0, 0, 0, 0.12);
}
.board-line.light .flap { color: var(--black); }
.board-row.now .board-due .flap { color: var(--orange); }

/* ---------- Cursor ---------- */

.has-cursor, .has-cursor * { cursor: none !important; }
.cursor {
  position: fixed;
  z-index: 102;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: difference;
  transition: opacity 200ms ease;
}
.cursor.on { opacity: 1; }
.cursor::before {
  content: "";
  position: absolute;
  left: -6px;
  top: -6px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--white);
  transition: scale 250ms cubic-bezier(0.22, 1, 0.36, 1);
}
.cursor.link::before { scale: 2.8; }
.cursor.down::before { scale: 0.7; }
.cursor.link.down::before { scale: 2.2; }
.cursor span {
  position: absolute;
  left: 10px;
  top: 12px;
  padding: 3px 12px 5px;
  border: 2px solid var(--black);
  border-radius: 999px;
  background: var(--orange);
  color: var(--black);
  font: 600 0.85rem/1.3 var(--doodle);
  white-space: nowrap;
  scale: 0;
  transform-origin: top left;
  transition: scale 250ms cubic-bezier(0.3, 1.5, 0.5, 1);
}
.cursor.labelled { mix-blend-mode: normal; }
.cursor.labelled::before { scale: 0.6; background: var(--black); outline: 2px solid var(--white); }
.cursor.labelled span { scale: 1; }

/* ---------- Ink buttons ---------- */

/* Buttons lean toward the pointer (fancy.js), and orange ink spreads from where it came in. */
.btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  transition: transform 160ms ease, translate 400ms cubic-bezier(0.22, 1, 0.36, 1), color 250ms ease;
}
.btn-solid:hover { background: var(--black); color: var(--black); }
.night .hero .btn-solid:hover { background: var(--paper); }
.btn-solid::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: var(--mx, 50%);
  top: var(--my, 50%);
  width: 0;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--orange);
  translate: -50% -50%;
  transition: width 550ms cubic-bezier(0.22, 1, 0.36, 1);
}
.btn-solid:hover::before { width: 300%; }

/* ---------- Tilting pages ---------- */

.stage,
.feature.flip .stage,
.feature-grid .stage {
  transform: perspective(1200px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) rotate(var(--tilt, -1deg));
  transition: transform 700ms cubic-bezier(0.22, 1, 0.36, 1);
}
.feature.flip .stage { --tilt: 1deg; }
.feature-grid .stage { --tilt: -0.5deg; }
.stage.tilting { transition-duration: 220ms; }

/* ---------- Page changes ---------- */

/* Going between the site and the privacy page irises open, like the intro. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: none; }
::view-transition-new(root) { animation: iris-open 750ms cubic-bezier(0.7, 0, 0.2, 1); }
@keyframes iris-open {
  from { clip-path: circle(0% at 50% 50%); }
  to { clip-path: circle(150% at 50% 50%); }
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}
/* Over links and buttons the dot opens into a ring, so it doesn't stain the orange ink. */
.cursor.link::before { background: transparent; box-shadow: inset 0 0 0 1px var(--white); }

@media (max-width: 860px) {
  /* On phones the headline fills the top of the sky; the moon rises lower, by the clouds. */
  .sky-wrap::after { left: auto; right: 36px; top: 330px; width: 54px; height: 54px; box-shadow: -12px 8px 0 0 #FFF4D6; }
  .board-cols { display: none; }
}

/* ---------- Boarding pass ---------- */

button.btn { border: 0; font-family: inherit; cursor: pointer; }
button.btn:disabled { opacity: 0.6; cursor: progress; }

.ticket {
  position: relative;
  display: grid;
  grid-template-columns: 116px minmax(0, 1fr);
  width: min(660px, 100%);
  margin: 30px auto 0;
  overflow: hidden;
  text-align: left;
  background: var(--paper);
  border: 2.5px solid var(--black);
  border-radius: 20px 26px 18px 24px / 24px 18px 26px 20px;
  box-shadow: 12px 14px 0 -2px rgba(0, 0, 0, 0.1);
  rotate: -0.6deg;
  scroll-margin-top: 80px;
}

/* The tear-off stub, with notches punched where it joins the ticket. */
.ticket-stub {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  padding: 22px 0;
  border-right: 2.5px dashed var(--black);
  background: repeating-linear-gradient(-45deg, transparent 0 9px, rgba(253, 106, 30, 0.12) 9px 12px);
  font-family: var(--doodle);
}
.ticket-stub::before,
.ticket-stub::after {
  content: "";
  position: absolute;
  right: -15px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--beige);
  border: 2.5px solid var(--black);
}
.ticket-stub::before { top: -15px; }
.ticket-stub::after { bottom: -15px; }
.ticket-admit,
.ticket-no {
  writing-mode: vertical-rl;
  rotate: 180deg;
  font-size: 0.8rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.ticket-stub .stn { font-size: 0.95rem; }

.ticket-main { padding: 26px clamp(20px, 4vw, 34px) 24px; }
.ticket-title {
  margin: 0;
  font: 400 clamp(2.2rem, 4.6vw, 3rem)/1 var(--serif);
  letter-spacing: -0.015em;
}
.ticket-title em { color: var(--orange); }
.ticket-sub { margin-top: 10px; font-size: 0.98rem; color: var(--ink-soft); }

.field { display: grid; gap: 2px; margin-top: 16px; }
.field > span { font: 500 0.82rem/1.4 var(--doodle); color: var(--ink-soft); }
.field i { font-style: normal; color: #8A8580; }
.field input,
.field textarea {
  width: 100%;
  padding: 6px 2px 8px;
  border: 0;
  border-bottom: 2.5px solid var(--black);
  border-radius: 0;
  background: transparent;
  color: var(--black);
  font: 1.05rem/1.4 var(--sans);
  resize: vertical;
  transition: border-color 150ms ease;
}
.field textarea { min-height: 3.2em; }
.field input::placeholder,
.field textarea::placeholder { color: #A9A49E; }
.field input:focus,
.field textarea:focus { outline: none; border-bottom-color: var(--orange); }
.field input:focus-visible,
.field textarea:focus-visible { box-shadow: 0 2px 0 0 var(--orange); }

/* The bots' field, kept out of sight and out of reach. */
.trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.ticket .actions { margin-top: 22px; gap: 12px 18px; }
.ticket-fine { font-size: 0.85rem; color: #6D6965; }
.ticket-fine a { text-decoration-color: var(--orange); text-underline-offset: 3px; }
.ticket-status { min-height: 1.5em; margin-top: 14px; font: 500 0.95rem/1.5 var(--doodle); color: var(--ink-soft); }
.ticket-status.ok { color: #2E7D46; }
.ticket-status.error { color: #C0392B; }
.ticket.sending .ticket-main { opacity: 0.7; }

/* Stamped when it goes through. */
.ticket-stamp {
  position: absolute;
  top: 22px;
  right: 24px;
  padding: 4px 16px 6px;
  border: 3.5px solid var(--orange);
  border-radius: 10px;
  color: var(--orange);
  font: italic 400 2.1rem/1 var(--serif);
  mix-blend-mode: multiply;
  pointer-events: none;
  opacity: 0;
  rotate: -14deg;
  scale: 2.2;
}
.ticket.done .ticket-stamp {
  opacity: 0.9;
  scale: 1;
  transition: scale 350ms cubic-bezier(0.5, 1.8, 0.5, 1), opacity 120ms ease;
}

@media (max-width: 600px) {
  .ticket { grid-template-columns: minmax(0, 1fr); }
  .ticket-stub {
    flex-direction: row;
    padding: 12px 22px;
    border-right: 0;
    border-bottom: 2.5px dashed var(--black);
  }
  .ticket-stub::before,
  .ticket-stub::after { right: auto; top: auto; bottom: -15px; }
  .ticket-stub::before { left: -15px; }
  .ticket-stub::after { right: -15px; }
  .ticket-admit, .ticket-no { writing-mode: horizontal-tb; rotate: none; }
  .ticket-stamp { top: 70px; font-size: 1.7rem; }
}
.ticket .actions { justify-content: flex-start; }

/* ---------- Sign up, express ---------- */

/* Streaks of speed while the page rides down to the ticket. They invert whatever is under them,
   so they show on the beige and the black alike. express.js sets their strength from the speed. */
.express-streaks {
  position: fixed;
  z-index: 99;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: difference;
  transition: opacity 250ms ease-out;
  background-image: repeating-linear-gradient(90deg,
    transparent 0 37px, rgba(255, 255, 255, 0.6) 37px 39px,
    transparent 39px 83px, rgba(255, 255, 255, 0.4) 83px 84px,
    transparent 84px 131px, rgba(255, 255, 255, 0.5) 131px 133px, transparent 133px 179px);
  -webkit-mask-image: repeating-linear-gradient(180deg, #000 0 140px, transparent 140px 260px, #000 260px 330px, transparent 330px 520px);
  mask-image: repeating-linear-gradient(180deg, #000 0 140px, transparent 140px 260px, #000 260px 330px, transparent 330px 520px);
}
.expressing .express-streaks { transition: none; animation: streak 240ms linear infinite; }
@keyframes streak {
  from { -webkit-mask-position: 0 0; mask-position: 0 0; }
  to { -webkit-mask-position: 0 calc(-520px * var(--dir, 1)); mask-position: 0 calc(-520px * var(--dir, 1)); }
}

/* On arrival the boarding pass feeds out, a line at a time like a ticket printer, then glows
   to say it's ready. */
.outro .ticket.printing {
  animation:
    ticket-print 950ms steps(16, end) both,
    ticket-ready 1s ease-out 950ms;
}
/* The crop ends well outside the ticket, so it doesn't square off the glow and shadow after. */
@keyframes ticket-print {
  from { clip-path: inset(-40px -40px 100% -40px); translate: 0 -28px; }
  to { clip-path: inset(-40px); translate: 0 0; }
}
@keyframes ticket-ready {
  from { box-shadow: 12px 14px 0 -2px rgba(0, 0, 0, 0.1), 0 0 0 0 rgba(253, 106, 30, 0.55); }
  to { box-shadow: 12px 14px 0 -2px rgba(0, 0, 0, 0.1), 0 0 0 22px rgba(253, 106, 30, 0); }
}
