/* gtfs.media, site-specific styles.
   ==================================================================
   Everything shared comes from the framework. What is left here is the one
   thing this site alone has: a mock departure board, a picture of what a rider
   sees at a stop.

   The history is the point. This file was 610 lines defining 74 classes before
   the engine, then 100 lines defining 14, and now 30 lines defining nothing
   that could collide with anything. Each drop came from the same place: a
   pattern that looked site-specific turned out to be general, and moved into
   the shared layer. The route badge was the last of them, and it is now the
   framework's `[data-route]`.

   One namespaced hook, `data-gtfs-board`, and the interior is positioned
   rather than named. Generic names belong to the framework: two sites each
   wrote a `.logo-row` before either was promoted, and they had drifted.

   Colours come from --fp-* tokens, so every part of this follows the dark-band
   remap and any brand the site later adopts. */

[data-gtfs-board] {
  display: grid;
  background: var(--fp-board);
  border: 1px solid var(--fp-board-line);
  border-radius: var(--fp-radius);
  overflow: hidden;
  font-family: var(--fp-mono);
  color: var(--fp-board-ink);
}

/* the header row: the stop, and the live indicator pushed to the far edge */
[data-gtfs-board] > header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--fp-board-line);
  font-size: 0.82rem;
}
/* The live indicator is a static dot. A blink is motion a reader cannot stop,
   and it says nothing the word "Live" does not. */
[data-gtfs-board] > header > span:last-child:not(:only-child) {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--fp-board-accent);
}
[data-gtfs-board] > header > span:last-child:not(:only-child)::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--fp-board-accent);
}

/* a departure: badge, destination, arrival */
[data-gtfs-board] > div {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.85rem;
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--fp-board-line);
}
[data-gtfs-board] > div:last-child { border-bottom: 0; }
[data-gtfs-board] > div > span:nth-child(2) {
  font-size: 0.9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
[data-gtfs-board] > div > span:last-child {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--fp-amber);
}

/* a service alert along the bottom */
[data-gtfs-board] > footer {
  padding: 0.7rem 1rem;
  background: var(--fp-board-2);
  border-top: 1px solid var(--fp-board-line);
  font-size: 0.82rem;
}

/* ---------- platform pylon ---------- */
/* Two screens in one frame, so the pair reads as one device rather than two
   pictures that happen to be adjacent. Capped narrow and centred, because a
   pylon is tall and thin and a full-width version of it reads as a poster. */
[data-gtfs-pylon] {
  max-width: 19rem;
  margin-inline: auto;
  display: grid;
  gap: 0.6rem;
  padding: 0.8rem;
  background: var(--fp-board);
  border-radius: 16px;
  box-shadow: var(--fp-shadow-lift);
}
[data-gtfs-pylon] img {
  display: block;
  width: 100%;
  height: auto;
  border: 0;
  border-radius: var(--fp-radius-xs);
  box-shadow: none;
}

/* ---------- API reference ---------- */
/* The pattern for a generated document.
   ==================================================================
   A reference is not a sequence of bands. A band is for content a reader
   moves through; this is content a reader searches, so it wants a contents
   rail beside a dense body. That is one region, which is why the generator
   returns one block of a site-local component rather than a block per
   operation. The first version returned a hundred blocks and got a hundred
   alternating stripes at full section padding.

   So: one namespaced hook, and everything inside it positioned rather than
   named. Twenty-four `api-*` classes became zero. The interior is ordinary
   elements, and where the framework already styles them (tables in figures,
   details, chips, code) this adds nothing. */

[data-gtfs-api] {
  display: grid;
  grid-template-columns: 15rem minmax(0, 1fr);
  gap: 3rem;
  align-items: start;
}
@media (max-width: 60rem) {
  [data-gtfs-api] { grid-template-columns: 1fr; gap: 2rem; }
}

/* the contents rail */
[data-gtfs-api] > nav {
  position: sticky;
  top: var(--fp-sticky-top);
  max-height: calc(100vh - var(--fp-header-clear));
  overflow-y: auto;
  font-size: 0.9rem;
}
@media (max-width: 60rem) {
  [data-gtfs-api] > nav { position: static; max-height: none; }
}
[data-gtfs-api] > nav section + section { margin-top: 1.4rem; }
[data-gtfs-api] > nav h2 {
  margin-bottom: 0.5rem;
  font-size: 0.78rem;
  font-weight: var(--fp-weight-ui);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--fp-ink-mute);
}
[data-gtfs-api] > nav ul { display: block; margin: 0; padding: 0; list-style: none; }
[data-gtfs-api] > nav li { display: block; margin: 0 0 0.15rem; max-width: none; padding: 0; }
[data-gtfs-api] > nav li::before { content: none; }
[data-gtfs-api] > nav a {
  display: flex;
  gap: 0.4rem;
  align-items: baseline;
  /* These are standalone controls: each is the whole content of its list
     item, so 2.5.5 applies and the framework's 44px stands. The first version
     overrode it to 30px on the argument that a nav landmark is skippable as a
     whole, which is not one of the criterion's exceptions, and the gate said
     so: 60 failures at 320px. The rail already scrolls inside its own box, so
     the taller rows cost nothing but the scroll it was going to have anyway. */
  padding: 0.1rem 0.4rem;
  border-left: 2px solid transparent;
  border-radius: var(--fp-radius-xs);
  color: var(--fp-ink-soft);
  text-decoration: none;
}
[data-gtfs-api] > nav a:hover {
  background: var(--fp-bg-alt);
  border-left-color: var(--fp-accent);
  color: var(--fp-ink);
}
[data-gtfs-api] > nav a > span:last-child { overflow-wrap: anywhere; }

/* the method, in the rail and on every operation heading */
[data-gtfs-api] :is(nav a, h3) > span:first-child {
  flex: none;
  font-family: var(--fp-mono);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--fp-accent);
}

/* the body */
[data-gtfs-api] > div > section { margin-bottom: 3rem; }
[data-gtfs-api] > div > section > section {
  margin-bottom: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--fp-rule);
  /* an anchor lands clear of the sticky header */
  scroll-margin-top: var(--fp-header-clear);
}
[data-gtfs-api] > div > section > section > h3 {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
  font-size: 1.05rem;
}
[data-gtfs-api] h3 > code {
  font-size: 0.95rem;
  overflow-wrap: anywhere;
}
/* a required parameter says so in words, not only in a column */
[data-gtfs-api] [data-required] {
  margin-left: 0.35rem;
  font-family: var(--fp-mono);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fp-bronze);
}

/* A reference is dense, so its headings step down: the page's own h1 does not
   need the weight a landing page's does, and an operation heading sits closer
   to body size than to a section heading. The framework's scale is for pages a
   reader moves through. */
[data-gtfs-api] > div > h1 { font-size: var(--fp-h2); }
[data-gtfs-api] > div > section > h2 { font-size: 1.4rem; }
[data-gtfs-api] > div > section > p { color: var(--fp-ink-soft); }

/* ---------- the eye ---------- */
/* The framework sizes a brand mark for an image lockup, 3.2rem tall. This one
   is a small mark beside a wordmark, which is a different shape of brand, so
   the site turns the knob the framework leaves for it. */
body > header > a:first-child { --fp-logo-height: 1.5rem; }

/* The eye blinks when you point at it.
   ==================================================================
   Two animations that have to agree. The lids squeeze shut on the Y axis; the
   mark's visible band clips inward in lockstep, because otherwise the pupils
   and strokes carry on showing through the closed lids and the eye reads as
   broken rather than blinking.

   The two paths are addressed by position rather than named. The SVG is in
   this site's own header partial, so the coupling is to markup this repo
   controls and can see: the first path is the lids, the second is the mark.
   Anyone editing that SVG needs to know it, which is what this comment is for.

   Hover only, once per hover, 400ms. An eye that blinks on a timer is a
   distraction on every page; an eye that blinks when noticed is a reward for
   noticing. */

body > header > a:first-child svg path:first-child {
  transform-box: fill-box;
  transform-origin: center;
}
@keyframes gtfs-blink-lids {
  0%, 100% { transform: scaleY(1); }
  45%, 55% { transform: scaleY(0.08); }
}
@keyframes gtfs-blink-mark {
  0%, 100% { clip-path: inset(0% 0%); }
  45%, 55% { clip-path: inset(44% 0%); }
}
body > header > a:first-child:hover svg path:first-child { animation: gtfs-blink-lids 0.4s ease-in-out; }
body > header > a:first-child:hover svg path:last-child { animation: gtfs-blink-mark 0.4s ease-in-out; }

/* Motion a reader cannot stop is a WCAG 2.3.3 failure, and this one is
   decorative: the mark says the same thing standing still.

   The guard has to match the specificity of what it is switching off. Written
   as `... svg path`, it lost to the `:first-child` and `:last-child` rules
   above and did nothing: the framework's global reduced-motion rule was the
   only thing actually stopping this, and that one works by zeroing duration
   with !important rather than by clearing the animation. Worth knowing that
   `cms check` sees a reduced-motion block and is satisfied; it does not verify
   that the block wins. */
@media (prefers-reduced-motion: reduce) {
  body > header > a:first-child:hover svg path:first-child,
  body > header > a:first-child:hover svg path:last-child { animation: none; }
}
