/* ============================================================================
   onboarding.css — the first-run tour.

   Paired with static/js/bw-onboarding.js and templates/_onboarding.html. The
   template owns every string (it is the only place {{ _('...') }} works), the
   script owns sequencing, and this owns what the thing looks like.

   Loaded from templates/_app_ios.html alongside app-ios.css and
   app-states.css, for the reason that file documents: every page declares its
   CSS in an inline <style>, so a sheet linked from <head> loses every tie on
   source order. The rules here have to settle those ties against the
   dashboard's own 3,500-line block without reaching for !important.

   ── The spotlight, and why there is no geometry in this file ──────────────

   Pointing at a real control the obvious way — measure it, punch a hole in a
   scrim over it — means getBoundingClientRect plus listeners on resize,
   scroll, orientationchange and the visual viewport, and it is still wrong
   the moment an iOS keyboard opens or the safe-area inset changes. Every one
   of those failures shows up as a cyan rectangle sitting next to the button
   it is supposed to be circling.

   So nothing is measured. The scrim covers the page; the nav bar is lifted
   above it by a class, which is enough to make it the only lit thing on the
   screen; and a second class dims the tabs that are not being talked about.
   Three z-indexes and an opacity. Correct at every viewport, in both
   orientations, with the keyboard up, forever.

   ── The stacking order it plugs into ─────────────────────────────────────

     .id-header .............   900   the top bar
     .bottom-nav ............  9999   the tab bar
     .bw-ob-scrim ...........  10000  over both — the page goes dark
     .bw-ob-lit .............  10001  the nav, pulled back out of the dark
     .bw-ob-card ............  10002  the caption, over everything
     account sheet ..........  10070  above the tour, and never open during it

   ── Motion ───────────────────────────────────────────────────────────────

   Durations and easings come from the spec in tools/drift_audit.py: 150 /
   200 / 350ms, standard cubic-bezier(0.4,0,0.2,1) or decelerate
   cubic-bezier(0.16,1,0.3,1). There is deliberately no pulsing ring: an
   infinite animation needs a duration the spec does not have, and a throbbing
   outline beside a blacked-out screen reads as an alarm to exactly the reader
   this is written for.
   ========================================================================= */

/* ── Scroll lock ─────────────────────────────────────────────────────────
   The page behind must not move while a step is talking about it. Applied to
   <html> rather than <body> because the canvas is <html>'s here (app-ios.css
   §6), and locking the body alone leaves the rubber-band gutter scrolling.

   `overflow: hidden` only — deliberately no `touch-action: none`. An
   element's effective touch-action is the intersection of its own value with
   every ancestor's, so `none` up here would also forbid panning *inside* the
   card, and the tallest step needs to scroll on a short phone (see
   .bw-ob-card's max-height below). The card contains its own overscroll
   instead, which is what stops a flick reaching the page. */
html.bw-ob-open,
html.bw-ob-open body {
  overflow: hidden;
}

/* ── The scrim ───────────────────────────────────────────────────────────── */
.bw-ob-scrim {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background: var(--scrim);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  opacity: 0;
  transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
.bw-ob-scrim.is-in { opacity: 1; }

/* ── The lit navigation bar ──────────────────────────────────────────────
   z-index alone does the spotlight. The bar keeps its own fill, blur and
   hairline — it is meant to look exactly like itself, only now it is the one
   thing with the lights on.

   The class is repeated four times, and this is not decoration.
   _fixed_chrome.html pins the tab bar with

     html body .bottom-nav.bottom-nav.bottom-nav { z-index: 9999 !important }

   at (0,3,2) — and its own comment says the tripling is there to sit "clear
   of every selector in the codebase and of the obvious next one someone
   writes". A plain `.bw-ob-lit` at (0,1,0) is exactly that obvious next one:
   it loses, the bar stays under the scrim, and the spotlight silently lights
   nothing. Four repeats reach (0,4,2), which wins on specificity rather than
   on source order, so it cannot be undone by a later import either.

   Selecting on this file's own class — not on .bottom-nav — is what lets the
   same rule serve the desktop bar, which is a different element. */
html body .bw-ob-lit.bw-ob-lit.bw-ob-lit.bw-ob-lit {
  z-index: 10001 !important;
}

/* Dim the tabs that are not the subject of this step. `opacity` and nothing
   else: a filter would knock the bar's backdrop-blur out on WebKit, and a
   colour change would fight whatever active state the tab already carries. */
.bw-ob-lit[data-ob-focus] [data-tour] {
  opacity: 0.28;
  transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
.bw-ob-lit[data-ob-focus="home"]   [data-tour="home"],
.bw-ob-lit[data-ob-focus="search"] [data-tour="search"],
.bw-ob-lit[data-ob-focus="picks"]  [data-tour="picks"],
.bw-ob-lit[data-ob-focus="live"]   [data-tour="live"],
.bw-ob-lit[data-ob-focus="bets"]   [data-tour="bets"] {
  opacity: 1;
}

/* The ring. `outline` rather than `box-shadow` on purpose: an outline is not
   clipped by the bar's overflow, takes no part in layout, and so cannot nudge
   a tab sideways at the moment the reader is being told where it is. */
.bw-ob-ring {
  outline: 2px solid var(--cyan);
  outline-offset: -2px;
  border-radius: var(--r-control);
}

/* ── The card ────────────────────────────────────────────────────────────
   One position for all six steps. A card that jumps from centre to bottom
   and back reads as a new thing appearing each time rather than as one guide
   still talking. On a phone it sits above the tab bar it is pointing at; on
   desktop the nav is the top bar, so it centres instead. */
.bw-ob-card {
  position: fixed;
  z-index: 10002;
  left: var(--pad);
  right: var(--pad);
  bottom: calc(var(--bottom-h) + var(--safe-bottom) + var(--sp-4));
  margin: 0 auto;
  max-width: 460px;
  box-sizing: border-box;
  /* The card grows upward from the bar it points at, so a long step on a
     short phone pushes its own heading off the top of the screen — the last
     step (three definitions plus two exits) did exactly that at 320x720.
     Cap it against everything already spoken for: the tab bar and its inset
     below, the top bar and the notch above. The flex column below is what
     keeps the foot in view once this cap bites.

     dvh after vh: mobile Safari's vh is the *largest* viewport, measured
     with the toolbar collapsed, so a vh-only cap is still too tall while the
     toolbar is showing. Older engines ignore the second declaration and keep
     the first. */
  max-height: calc(100vh  - var(--bottom-h) - var(--safe-bottom)
                          - var(--id-h) - var(--safe-top) - var(--sp-6));
  max-height: calc(100dvh - var(--bottom-h) - var(--safe-bottom)
                          - var(--id-h) - var(--safe-top) - var(--sp-6));
  display: flex;
  flex-direction: column;
  padding: var(--sp-5) var(--sp-4) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--surface-border);
  border-radius: var(--r-sheet);
  box-shadow: var(--shadow-pop);
  font-family: 'DM Sans', sans-serif;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1),
              transform 350ms cubic-bezier(0.16, 1, 0.3, 1);
}
.bw-ob-card.is-in {
  opacity: 1;
  transform: translateY(0);
}

@media (min-width: 600px) {
  .bw-ob-card {
    top: 50%;
    bottom: auto;
    transform: translateY(calc(-50% + 12px));
    /* Centred rather than anchored, so the only thing to clear is the window
       itself — the desktop bar is the top bar and the card is nowhere near
       it. */
    max-height: calc(100vh  - var(--sp-8) - var(--sp-8));
    max-height: calc(100dvh - var(--sp-8) - var(--sp-8));
  }
  .bw-ob-card.is-in { transform: translateY(-50%); }
}

/* ── The scrolling half ──────────────────────────────────────────────────
   Only the step scrolls. The foot carries Back / Skip / Next and the
   progress dots, and a reader who cannot see the way forward is stuck — so
   it stays put and the copy moves under it.

   `min-height: 0` is what makes that work: a flex item's default
   `min-height: auto` refuses to shrink below its content, so without this
   the section wins the argument and the card overflows exactly as it did
   before the cap. `overscroll-behavior: contain` keeps a flick that reaches
   the end of the copy from being handed to the page underneath. */
.bw-ob-step {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.bw-ob-foot { flex: 0 0 auto; }

/* ── Card head ───────────────────────────────────────────────────────────── */
.bw-ob-mark {
  width: 42px;
  height: 42px;
  margin-bottom: var(--sp-3);
  border-radius: var(--r-control);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--cyan-dim);
  border: 1px solid var(--cyan-line);
  color: var(--cyan);
  font-size: var(--fs-headline);
}

/* ── The brand block (step 1 only) ───────────────────────────────────────
   Stands in for .bw-ob-mark on the welcome step: the app icon and the
   wordmark, drawn the way _public_brand.html draws them so the tour opens on
   the same signature the signup page closed on. The mark is a little larger
   than the glyph disc it replaces because it is a picture rather than a
   symbol, and it is the only thing above the fold on that step. */
.bw-ob-brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}
.bw-ob-brand-mark {
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  border-radius: var(--r-control);
  /* The icon is drawn on its own dark ground, so it needs no fill behind it —
     only the app's usual glow, which is what keeps it from sitting flat on
     the card in light mode. */
  box-shadow: 0 0 0 1px var(--cyan-line), 0 6px 18px rgba(0, 0, 0, 0.28);
}
.bw-ob-brand-word {
  font-family: 'Orbitron', 'Segoe UI', sans-serif;
  font-size: var(--fs-title3);
  font-weight: 700;
  letter-spacing: 0.5px;
  line-height: 1;
  color: var(--text-strong);
}
.bw-ob-brand-accent {
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.bw-ob-title {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-title3);
  font-weight: 800;
  line-height: 1.25;
  color: var(--text-strong);
}

/* 15px, not 13px. The reader this is written for is being asked to read a
   paragraph on a dimmed screen, possibly at arm's length. */
.bw-ob-body {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 500;
  line-height: 1.6;
  color: var(--text2);
}
.bw-ob-body + .bw-ob-body { margin-top: var(--sp-3); }
.bw-ob-body b { color: var(--text); font-weight: 700; }

/* ── The five-button legend (step 3) ─────────────────────────────────────
   Icons repeat the marks in the bar directly below, so the list and the thing
   it describes can be read against each other without translating names. */
.bw-ob-legend {
  list-style: none;
  margin: var(--sp-3) 0 0;
  padding: 0;
}
.bw-ob-legend li {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) 0;
  font-size: var(--fs-subhead);
  font-weight: 500;
  line-height: 1.4;
  color: var(--text2);
}
.bw-ob-legend li + li { border-top: 1px solid var(--glass-border); }
.bw-ob-legend b { color: var(--text); font-weight: 700; }
.bw-ob-legend .bw-ob-legend-icon {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border-radius: var(--r-control);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--glass-bg2);
  border: 1px solid var(--glass-border);
  color: var(--cyan);
  font-size: var(--fs-caption);
}

/* ── The league picker (step 2) ──────────────────────────────────────────── */
.bw-ob-leagues {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}
.bw-ob-league {
  flex: 1 0 auto;
  min-width: 88px;
  min-height: var(--tap);
  padding: 0 var(--sp-4);
  /* The logo and the name are one label, so the button is a centred row
     rather than a block of text with an image floated into it. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  border-radius: var(--r-control);
  background: var(--glass-bg2);
  border: 1px solid var(--glass-border);
  color: var(--text);
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-body);
  font-weight: 700;
  letter-spacing: 0.3px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 150ms cubic-bezier(0.4, 0, 0.2, 1),
              border-color 150ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* Bigger than team-crests.css's default 15px: these sit on a 44px button that
   a reader is picking from across the card, not inline in a table row. */
.bw-ob-league-logo {
  width: 20px;
  height: 20px;
}
.bw-ob-league:hover { border-color: var(--cyan-line); }
.bw-ob-league:active { background: var(--hover-bg); }
.bw-ob-league[aria-pressed="true"] {
  background: var(--cyan-dim);
  border-color: var(--cyan);
  color: var(--cyan);
}

/* ── The tip line ────────────────────────────────────────────────────────
   Amber because it is advice, not a warning — the app reserves red for things
   that went wrong. Same rule tutorial.html's .tut-tip follows. */
.bw-ob-tip {
  display: flex;
  gap: var(--sp-2);
  align-items: flex-start;
  margin-top: var(--sp-4);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-control);
  background: var(--amber-dim);
  border: 1px solid var(--amber-line);
  font-size: var(--fs-caption);
  font-weight: 500;
  line-height: 1.5;
  color: var(--text2);
}
.bw-ob-tip i {
  flex: 0 0 auto;
  margin-top: 2px;
  color: var(--amber);
  font-size: var(--fs-caption);
}

/* ── The two exits on the last step ──────────────────────────────────────── */
.bw-ob-exits {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}
.bw-ob-exit {
  flex: 1 1 auto;
  min-height: var(--tap);
  padding: 0 var(--sp-4);
  border-radius: var(--r-control);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  background: var(--glass-bg2);
  border: 1px solid var(--glass-border);
  color: var(--text);
  text-decoration: none;
  font-size: var(--fs-subhead);
  font-weight: 700;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 150ms cubic-bezier(0.4, 0, 0.2, 1);
}
.bw-ob-exit:hover { border-color: var(--cyan-line); }
.bw-ob-exit.is-primary {
  background: var(--cyan-dim);
  border-color: var(--cyan-line);
  color: var(--cyan);
}

/* ── Foot: dots on the left, controls on the right ───────────────────────── */
.bw-ob-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--glass-border);
}

/* Indicators, not controls — so they carry no 44px obligation. The step count
   is also announced in text for a screen reader; see .bw-ob-count. */
.bw-ob-dots {
  display: flex;
  align-items: center;
  gap: 6px;
}
.bw-ob-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--glass-border2);
  transition: background 200ms cubic-bezier(0.4, 0, 0.2, 1),
              width 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
.bw-ob-dot.is-done { background: var(--muted); }
.bw-ob-dot.is-now {
  width: 18px;
  border-radius: var(--pill-radius);
  background: var(--cyan);
}

.bw-ob-count {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.bw-ob-controls {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

/* Skip and Back are quiet; Next is the one filled thing on the card. All three
   clear 44px — this is the row a nervous reader hunts for. */
.bw-ob-quiet {
  min-height: var(--tap);
  padding: 0 var(--sp-3);
  border: 0;
  border-radius: var(--r-control);
  background: none;
  color: var(--muted2);
  font-family: 'DM Sans', sans-serif;
  font-size: var(--fs-subhead);
  font-weight: 600;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color 150ms cubic-bezier(0.4, 0, 0.2, 1);
}
.bw-ob-quiet:hover { color: var(--text); }
.bw-ob-quiet[hidden] { display: none; }

.bw-ob-next {
  min-height: var(--tap);
  padding: 0 var(--sp-5);
  border: 0;
  border-radius: var(--r-control);
  background: var(--cyan);
  color: var(--on-accent);
  font-family: 'DM Sans', sans-serif;
  font-size: var(--fs-body);
  font-weight: 700;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);
}
.bw-ob-next:active { opacity: 0.85; }
.bw-ob-next[hidden] { display: none; }

/* Focus is visible on everything here. A keyboard user is trapped inside this
   card by design; losing the caret inside a trap is a dead end. */
.bw-ob-card :focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}

/* ── Steps ───────────────────────────────────────────────────────────────── */
.bw-ob-step[hidden] { display: none; }

/* ── `hidden` has to be re-stated ────────────────────────────────────────
   The UA sheet's `[hidden] { display: none }` and this file's
   `.bw-ob-card { display: flex }` are both (0,1,0), and an author rule beats
   a UA rule at equal specificity — so declaring a display on the card
   silently disabled its own hidden attribute. The card stayed in the layout
   after the tour closed: invisible at opacity 0, and still swallowing every
   tap across its footprint. Same trap the steps above already avoid, which
   is why that line was there first.

   Both elements are listed rather than just the card, so a display added to
   the scrim later cannot reopen the same hole. */
.bw-ob-card[hidden],
.bw-ob-scrim[hidden] { display: none; }

/* ── Reduced motion ──────────────────────────────────────────────────────
   Keep the fade, drop the travel. Something still has to mark the step
   changing, or the card looks frozen when the copy swaps underneath it. */
@media (prefers-reduced-motion: reduce) {
  .bw-ob-card {
    transform: none;
    transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1);
  }
  .bw-ob-card.is-in { transform: none; }
  .bw-ob-dot { transition: background 200ms cubic-bezier(0.4, 0, 0.2, 1); }
  @media (min-width: 600px) {
    .bw-ob-card,
    .bw-ob-card.is-in { transform: translateY(-50%); }
  }
}
