/* Mobile first, and mobile only in practice - everyone who opens this is standing on a closed
   street holding a phone. Nothing here assumes a pointer or a hover. */

:root {
  --ink: #14181d;
  --ink-soft: #4a545f;
  --line: #d9dee4;
  --paper: #ffffff;
  --shade: #f4f6f8;
  --tap: 44px;

  /* Colors are addressed by role, not by name. A palette change reassigns these and no rule
     below moves. Every pair is checked against WCAG AA:
       red    #d62828 on white ............ 5.01:1   (pure #ff0000 is 4.00:1 and fails)
       blue   #1d4ed8 on white ............ 6.70:1
       ink    #14181d on yellow chip ..... 11.08:1   (yellow as TEXT on white is 1.61:1 - never)
       white  #ffffff on flag blue ........ 9.05:1
       yellow #ffc300 on flag blue ........ 5.63:1                                            */
  --accent: #d62828;
  --accent-soft: #fdeceb;
  --link: #1d4ed8;
  --chip-bg: #ffc300;
  --chip-ink: #14181d;
  --header-bg: #00449e;
  --header-ink: #ffffff;
  --header-sub: #cfe0f5;
  --nav-ink: #cfe0f5;
  --nav-active: #ffc300;
}

*, *::before, *::after { box-sizing: border-box; }

/* No overflow-x: hidden on the body. It would hide the exact failure `sday` looks for. */
body {
  margin: 0;
  background: var(--shade);
  color: var(--ink);
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
}

main { padding: 0.9rem 0.9rem 2.5rem; max-width: 40rem; margin: 0 auto; }

header.site {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--header-bg);
  color: var(--header-ink);
  padding: 0.7rem 0.9rem 0;
}

header.site h1 { margin: 0; font-size: 1.15rem; line-height: 1.25; }
header.site p { margin: 0.1rem 0 0.5rem; font-size: 0.85rem; color: var(--header-sub); }

nav.tabs { display: flex; gap: 0.15rem; overflow-x: auto; }

nav.tabs a {
  flex: 0 0 auto;
  min-height: var(--tap);
  display: flex;
  align-items: center;
  padding: 0 0.7rem;
  color: var(--nav-ink);
  text-decoration: none;
  font-size: 0.9rem;
  border-bottom: 3px solid transparent;
}

/* All four labels fit at 390px with room to spare, and overflow by ~58px at 320px, where the
   last tab is cut off with nothing to say so. Tightening the padding below 360px keeps every
   section reachable without a swipe nobody would guess at. */
@media (max-width: 359px) {
  header.site { padding-left: 0.6rem; padding-right: 0.6rem; }
  nav.tabs a { padding: 0 0.4rem; font-size: 0.85rem; }
}

nav.tabs a.here {
  color: var(--nav-active);
  border-bottom-color: var(--nav-active);
  font-weight: 600;
}

h2.section {
  margin: 0.4rem 0 0.6rem;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

ul.cards { list-style: none; margin: 0; padding: 0; }
ul.cards > li { margin: 0 0 0.6rem; }

/* `tapr`. The row is the link or it is a plain card - there is no shape in between, and nothing
   inside a card is a second target. */
a.card, div.card {
  display: block;
  padding: 0.85rem 0.95rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
  color: inherit;
  text-decoration: none;
}

a.card { min-height: var(--tap); }
a.card:active { background: var(--shade); }

/* One unbreakable token - a long URL, an email address, a hyphen-free compound - is enough to
   push a card past the viewport and scroll the whole page sideways. There is deliberately no
   overflow-x guard on the body to catch it, so the wrapping has to be right here.
   break-word first: iOS Safari before 15.4 does not know `anywhere`, and those phones are exactly
   the ones still in pockets. */
.card { overflow-wrap: break-word; overflow-wrap: anywhere; }

/* Focus has to be visible on its own. text-decoration is already gone from cards, and :active
   only fires for touch. */
a.card:focus-visible,
nav.tabs a:focus-visible,
.back a:focus-visible,
.trouble .retry:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 2px;
}

nav.tabs a:focus-visible { outline-color: var(--nav-active); }

.card h3 { margin: 0 0 0.15rem; font-size: 1.05rem; line-height: 1.3; }
.card .when { font-size: 0.95rem; font-weight: 700; color: var(--accent); }
.card .where, .card .meta { margin: 0.15rem 0 0; font-size: 0.9rem; color: var(--ink-soft); }
.card .blurb { margin: 0.3rem 0 0; font-size: 0.92rem; }

.loading, .empty { margin: 1.2rem 0; color: var(--ink-soft); font-size: 0.95rem; }

.trouble {
  margin: 1rem 0;
  padding: 0.9rem 1rem;
  border: 1px solid var(--accent);
  border-radius: 10px;
  background: var(--accent-soft);
}

.trouble p { margin: 0 0 0.5rem; }

.trouble .retry {
  min-height: var(--tap);
  padding: 0 1.1rem;
  border: 1px solid var(--accent);
  border-radius: 8px;
  background: var(--paper);
  color: var(--accent);
  font: inherit;
  font-weight: 600;
}

/* An anchored row clears the sticky header instead of hiding behind it. --header-h is measured
   at scroll time; the fallback covers the case where it was never set. */
/* --header-h is measured on load, resize, and rotate. The fallback is sized for the tallest real
   header (129px at 320px, where the h1 wraps) rather than the shortest, so a miss errs toward too
   much clearance instead of tucking the row under the header. */
ul.cards > li[id] { scroll-margin-top: calc(var(--header-h, 8.5rem) + 0.6rem); }

img { max-width: 100%; height: auto; }

/* Detail views. A back link, then the one thing the page is about. */
.back { margin: 0 0 0.6rem; }

.back a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  color: var(--link);
  font-size: 0.95rem;
}

article.detail {
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  padding: 0.95rem 1rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
}

/* Scoped with the child combinator, which is the honest fix: these rules are about the detail
   view's own heading and lines, not about everything nested anywhere inside it. Descendant
   selectors here outrank the .card rules, so a card placed inside a detail view - a business page
   listing its offers, which is the next page to be built - would silently pick up detail styling.
   `>` makes them not match rather than winning a specificity contest. */
article.detail > h2 {
  margin: 0.2rem 0 0.3rem;
  font-size: 1.5rem;
  line-height: 1.2;
}

article.detail > .where { font-size: 1rem; color: var(--ink); }
article.detail > .blurb { margin-top: 0.7rem; }

article.detail > .meta { margin: 0.2rem 0 0; font-size: 0.95rem; color: var(--ink-soft); }

/* Direct children only, same as every rule above, and for the reason the comment above gives:
   `article.detail a` is a descendant selector at (0,1,2) and outranks `a.card { color: inherit }`
   at (0,1,1), so every offer card on this page - which is the next issue - would render as blue
   body text. Written as a descendant selector first and caught in review. The `>` discipline is
   not a style preference; it is the thing that stops a detail view restyling a card it contains. */
article.detail > .meta a,
article.detail > .blurb a { color: var(--link); }

/* Every link on a detail view is a thumb target standing outside in the sun, not a word in a
   paragraph. Phone numbers and websites are the two things someone taps while walking. */
article.detail > .meta a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 600;
}

/* Offers. The card keeps the list shape so a thumb meets the same target it does everywhere else.
   Artwork is shown as handed over: full card width, not cropped, nothing overlaid, no branding
   added. It is not lazy-loaded - there are a handful of offers, all of them near the top, so lazy
   buys nothing and guarantees the card shifts under a thumb as the art arrives. */
.card .promo-art {
  display: block;
  width: 100%;
  height: auto;
  margin: 0.5rem 0 0;
  border-radius: 8px;
}

/* The code as the business wrote it. Ink on the yellow chip, which is the 11.08:1 pair - yellow
   as text on white is 1.61:1 and is never used that way. */
.card .code {
  display: inline-block;
  margin: 0.5rem 0 0;
  padding: 0.25rem 0.6rem;
  border-radius: 6px;
  background: var(--chip-bg);
  color: var(--chip-ink);
  font-weight: 700;
  letter-spacing: 0.04em;
}

.card .terms { margin: 0.4rem 0 0; font-size: 0.85rem; color: var(--ink-soft); }

/* Who's here. A row leads nowhere - the bio is entirely on the card - so per `tapr` it is a plain
   card and not a link. */
.person { display: flex; gap: 0.75rem; align-items: flex-start; }

.card .face {
  position: relative;
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--shade);
}

/* Laid over the initials rather than instead of them, so an image that fails to load reveals what
   was already behind it without moving anything. */
.card .face-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A record with no photo gets initials rather than a broken image, an empty gap, or a shifted
   layout - the row has to be the same height either way. */
.card .noface {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-soft);
  font-weight: 700;
  /* Clamped: at 300% text zoom an unclamped 1.15rem pushes two initials onto two lines inside a
     circle that does not grow with them. */
  font-size: min(1.15rem, 22px);
  letter-spacing: 0.02em;
}
