/* Boston Café Bikers — shared stylesheet
   Linked from every page (index.html, gallery.html, shopify.html,
   meta-business.html, donate.html) via <link rel="stylesheet" href="styles.css">.
   Page-specific rules live in a small inline <style> on each page. Keep the
   café palette custom properties here — do not introduce new hex values. */

:root {
  --espresso: #2e1d13;
  --roast:    #4a2c1a;
  --crema:    #b07a4a;
  --latte:    #f6ece0;
  --foam:     #fffaf4;
  --oat:      #e6d5c2;
  --ink:      #33261d;
  --muted:    #7a685a;
  --radius:   14px;
  /* Readability "setting" for the photo-backed sections ([data-bg]): the
     espresso scrim's opacity. Raise it to darken the photo more when the text
     over it needs stronger contrast; lower it to let more of the photo
     through. Default .7 was raised from .55 (2026-08-13) so body copy over
     the photos clears WCAG AA — measured worst-case contrast was ~2.6:1 at
     .55 and is ~4.2:1 at .7. */
  --bg-overlay-opacity: .7;
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--latte);
  color: var(--ink);
  /* 1rem (not a px literal) so inherited body copy scales with the desktop
     root-font bump at ≥760px below — 16px on mobile, 18px on desktop. */
  font: 1rem/1.6 ui-sans-serif, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
}

.wrap {
  width: 100%;
  max-width: 680px;
  margin: 0 auto;
  padding: 0 20px;
}

h1, h2, h3 {
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  line-height: 1.2;
  margin: 0 0 .5rem;
}

a { color: var(--roast); }

/* --- hero --- */
/* The espresso gradient is the no-JS / pre-load fallback: the hero photo is
   deferred (app.js copies the [data-bg] URL into background-image only after
   window.load), so this gradient is what renders on first paint and for
   anyone without JS. */
.hero {
  background: linear-gradient(160deg, var(--roast) 0%, var(--espresso) 100%);
  color: var(--foam);
  padding: 32px 0 24px;
  text-align: center;
}
.hero h1 { font-size: clamp(1.7rem, 7vw, 2.4rem); letter-spacing: -.01em; }
.hero .tagline {
  font-size: 1rem;
  color: var(--oat);
  margin: 0;
}
/* The mark is the group's logo (its Partiful profile picture): a small
   rounded square — an accent above the h1, not a second title, so it is
   sized in rem like the old pictogram was (3rem: 48px on a phone, 54px
   at the desktop root size). width/height attributes on the <img> only
   fix the aspect ratio so nothing shifts before it loads. */
.hero .mark {
  display: block;
  width: 3rem;
  height: 3rem;
  margin: 0 auto .5rem;
  border-radius: 25%;
  object-fit: cover;
}
.hero a { color: var(--foam); }

/* --- photo-backed sections ([data-bg]) --- */
/* Any section carrying a data-bg attribute (app.js copies the URL into
   background-image only after window.load) becomes a photo-backed section:
   the espresso gradient is the no-JS / pre-load fallback, then a translucent
   espresso ::before scrim sits over the photo (its opacity is the
   --bg-overlay-opacity setting in :root — raise it to improve readability),
   and the section's .wrap is lifted above the scrim. Body copy goes light so
   it stays readable over the photo; opaque cards (.ride, .links) keep their
   own dark text on their light backgrounds. */
[data-bg] {
  position: relative;
  background: linear-gradient(160deg, var(--roast) 0%, var(--espresso) 100%);
}
[data-bg].bg-loaded {
  background-size: cover;
  background-position: center;
}
[data-bg].bg-loaded::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(46, 29, 19, var(--bg-overlay-opacity)); /* --espresso, translucent */
  z-index: 0;
}
[data-bg].bg-loaded > .wrap {
  position: relative;
  z-index: 1;
}
/* The section is always dark (gradient pre-JS, photo + scrim post-JS), so the
   heading and copy are light regardless. Direct body-copy paragraphs go light;
   the featured ride card's <p> is exempt — its parent is .ride, an opaque oat
   card, so it keeps its dark text. The espresso text-shadow (same rgba as the
   scrim, no new palette hex) is the legibility boost for any bright photo
   patch that survives the scrim — it darkens the pixels just behind the glyphs
   without darkening the whole photo (added 2026-08-13). */
[data-bg] h2 { color: var(--foam); text-shadow: 0 1px 3px rgba(46, 29, 19, .7); }
[data-bg] .note { color: var(--oat); text-shadow: 0 1px 2px rgba(46, 29, 19, .7); }
[data-bg] :not(.ride) > p { color: var(--oat); text-shadow: 0 1px 2px rgba(46, 29, 19, .7); }
[data-bg] ul.checks li { color: var(--oat); text-shadow: 0 1px 2px rgba(46, 29, 19, .7); }
[data-bg] ul.checks li strong { color: var(--foam); text-shadow: 0 1px 2px rgba(46, 29, 19, .7); }

/* --- buttons --- */
.btn {
  display: inline-block;
  background: var(--crema);
  color: #2b1a10;
  text-decoration: none;
  font-weight: 600;
  padding: 12px 22px;
  border-radius: 999px;
  border: 0;
}
.btn:hover, .btn:focus { background: #c68f5d; }
/* Tap feedback on touch: brightness darkens the whole button on press
   without introducing a new palette hex. */
.btn:active { filter: brightness(.92); }
/* Keyboard-focus ring (2026-08-24): :focus-visible only, so a mouse click
   doesn't get a ring — hover/tap feedback above is untouched. .btn's own
   fill is crema, so the ring is roast instead (ring ≠ fill); .links a below
   is foam-filled, so it keeps the default crema ring. */
.btn:focus-visible { outline: 2px solid var(--roast); outline-offset: 2px; }
/* .links a is duplicated per-page (index.html, contact.html each define the
   base rule in their own inline <style>) — one shared ring here covers both
   without duplicating it twice. */
.links a:focus-visible { outline: 2px solid var(--crema); outline-offset: 2px; }

/* --- tab header nav --- */
/* Static espresso bar that scrolls with the page — the organizer re-opened
   the earlier "keep the nav pinned" request as its opposite ("make top nav
   not stay permanently on screen"), so position: sticky / top: 0 were
   removed (2026-08-13). No JS or page CSS depends on the nav being pinned. */
.nav {
  background: var(--espresso);
  border-bottom: 1px solid rgba(246, 236, 224, .15);
}
.nav .wrap {
  display: flex;
  justify-content: center;
  padding-top: 8px;
  padding-bottom: 8px;
}
.nav .tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav .tabs a {
  display: block;
  color: var(--oat);
  text-decoration: none;
  font-size: .85rem;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 999px;
  white-space: nowrap;
}
.nav .tabs a:hover,
.nav .tabs a:focus { color: var(--foam); background: rgba(246, 236, 224, .1); }
.nav .tabs a:active { background: rgba(246, 236, 224, .25); }
.nav .tabs a:focus-visible { outline: 2px solid var(--crema); outline-offset: 2px; }
.nav .tabs a.is-active {
  background: var(--crema);
  color: #2b1a10;
}
/* Five tabs (Rides / Cafés / Gallery / Contact / Donate, since the cafés page
   landed 2026-08-23) no longer fit one row at 380px with the default 12px pill
   padding: the row wrapped and left "Donate" alone on a second line, which
   reads as a mistake rather than as a tab bar. Tighten the pill padding, gap
   and type a notch on narrow phones so the five stay on one line; every tab is
   still comfortably wider than a fingertip, and nothing changes from 421px up.
   The .tabs flex-wrap above stays as the safety net for a sixth tab. */
@media (max-width: 420px) {
  .nav .tabs { gap: 2px; }
  .nav .tabs a { padding: 6px 9px; font-size: .82rem; }
}

/* --- sections --- */
section { padding: 40px 0; }
section + section { border-top: 1px solid var(--oat); }
section h2 { font-size: 1.6rem; }
.lede { color: var(--muted); margin-top: 0; }

/* --- WIP placeholder badge --- */
.wip {
  display: inline-block;
  background: var(--foam);
  border: 2px dashed var(--crema);
  border-radius: var(--radius);
  padding: 14px 20px;
  margin: 0 0 1rem;
  font-weight: 600;
  color: var(--roast);
}

footer {
  background: var(--espresso);
  color: var(--oat);
  text-align: center;
  padding: 32px 0;
  font-size: .9rem;
}
footer a { color: var(--oat); }
footer a:focus-visible { outline: 2px solid var(--crema); outline-offset: 2px; }
footer .footer-brand {
  margin: 0 0 .75rem;
  color: var(--foam);
}
footer .footer-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px 14px;
  margin: 0 0 .75rem;
}
footer .footer-nav a {
  text-decoration: none;
  font-weight: 600;
  font-size: .85rem;
}
footer .footer-nav a:hover,
footer .footer-nav a:focus,
footer .footer-social a:hover,
footer .footer-social a:focus {
  color: var(--foam);
}
footer .footer-social {
  margin: 0;
}
footer .footer-social a {
  font-weight: 600;
}
footer .footer-social .sep {
  margin: 0 .3rem;
  color: var(--muted);
}

@media (min-width: 560px) {
  .hero { padding: 48px 0 32px; }
  section { padding: 56px 0; }
}

/* --- desktop typography (2026-08-13) --- */
/* The mobile-first base is 16px, which reads comfortably on a phone (~45
   chars/line at 380px). On a desktop the same 16px in the 680px wrap
   stretches to ~85 chars/line — past the ~75-char reading-comfort limit —
   and the rem-based small print (notes, calendar labels, footer) stays tiny.
   Bumping the root font-size at desktop widths scales every rem-based size
   proportionally (body copy, nav, notes, calendar), so text on a big monitor
   is at least as readable as on a phone. The wrap stays 680px: at 18px the
   measure is ~75 chars, the top of the comfortable range. */
@media (min-width: 760px) {
  html { font-size: 18px; }
}
