/*
 * First-run onboarding (Onboarding.js) — the clubs picker, the competitions
 * picker, the notifications ask and the done card, and the two pickers
 * reopened from the league strip's "+".
 *
 * Constrained to the shell width rather than the window, same as every other
 * takeover: on a phone that is genuinely full-bleed, and on desktop it keeps
 * the mini app inside its own frame.
 *
 * Two layers that stay apart, for the reason the search overlay's do — they
 * animate different properties:
 *
 *   .onboarding          the fade. Also the ground, so nothing of the page
 *                        behind shows through mid-transition.
 *   .onboarding__sheet   the travel — a short rise on entry.
 *
 * Everything it draws is the app's own material. The search field is the
 * search overlay's `.search-field`; the switches and the chips on the done
 * card are the filter sheet's `.filter-switch` and `.filter-chip`; the
 * expanders are its `.filter-chip--more`; the crest discs are the search
 * card's badge disc, one size up. What is new here is only the grid, the
 * tray, the progress rail and the two screens after the picker.
 */

.onboarding {
  --enter-y: 12px;

  position: fixed;
  inset: 0;
  /*
   * Above everything, including the story viewer's 100. It is either the
   * first thing on screen — a gate, opened at boot over whatever a deep link
   * hydrated underneath — or reopened from the home screen's league strip,
   * where nothing else is up. Nothing is ever opened from it.
   */
  z-index: 101;
  display: flex;
  max-width: var(--app-max-width);
  margin-inline: auto;
  background: var(--bg);
  opacity: 0;
  transition: opacity var(--duration) var(--easing);
}

/* A class beats the UA [hidden] rule, so display has to be turned off by hand. */
.onboarding[hidden] {
  display: none;
}

.onboarding[data-open="true"] {
  --enter-y: 0px;

  opacity: 1;
}

.onboarding__sheet {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding-top: var(--safe-top);
  transform: translateY(var(--enter-y));
  transition: transform var(--duration) var(--easing);
}

/* --- Bar ------------------------------------------------------------------ */

/* The app bar with the club page's spacing above it. */
.onboarding__bar {
  flex: none;
  margin-top: var(--space-4);
}

/* `.icon-btn` sets display, which outranks the UA [hidden] rule. */
.onboarding__bar .icon-btn[hidden] {
  display: none;
}

/* --- Progress ------------------------------------------------------------- */

/*
 * One segment per step, in the bar's own gutter. Filled in the accent
 * up to and including the current step — the nav indicator's "this one is
 * active", laid flat. Not a bar that grows: the segments are the steps, and
 * a reader can count them.
 */
.onboarding__progress {
  flex: none;
  display: flex;
  gap: 6px;
  /* A beat below the rail before the scroller's edge, so a card scrolled to
     the top is clipped a little under it rather than hard against it. */
  padding: var(--space-3) var(--space-4) var(--space-2);
}

.onboarding__progress[hidden] {
  display: none;
}

.onboarding__progress-seg {
  flex: 1 1 0;
  height: 4px;
  border-radius: var(--radius-full);
  background: var(--surface-pressed);
  transition: background-color var(--duration) var(--easing);
}

.onboarding__progress-seg[data-state="done"],
.onboarding__progress-seg[data-state="current"] {
  background: var(--accent);
}

/* --- Body ----------------------------------------------------------------- */

.onboarding__body {
  position: relative;
  flex: 1;
  overflow-y: auto;
  /* The page behind is already scroll-locked; this stops a flick at either end
     from handing the gesture back to it anyway. */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: var(--space-4) var(--space-3) var(--space-5);
}

.ob-panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  transition:
    opacity var(--duration) var(--easing),
    transform var(--duration) var(--easing);
}

.ob-panel[hidden] {
  display: none;
}

/*
 * The step switch — the bottom nav's fade-through (TabPanes.js, layout.css).
 * The panel leaving fades on the press timing; the one arriving rises 8px
 * through its fade on the ordinary duration. Never both at once.
 */
.ob-panel[data-state="leave"] {
  opacity: 0;
  transition-duration: var(--duration-press);
}

.ob-panel[data-state="enter"] {
  opacity: 0;
  transform: translateY(8px);
}

/* --- Head ----------------------------------------------------------------- */

.ob-head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding-inline: var(--space-1);
}

.ob-head--centred {
  align-items: center;
  padding-top: var(--space-4);
  text-align: center;
}

/* The Telegram account's photo, on the empty state's disc — hairline and
   shadow lifting it off the page. */
.ob-head__avatar {
  display: grid;
  place-items: center;
  margin-bottom: var(--space-1);
  padding: 2px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-card);
}

/*
 * --text-xl, the list's own largest voice — the club page's name is set at
 * it. Not --text-2xl: that step is the scoreline's, and a question is not the
 * single most important number on its screen.
 */
.ob-head__title {
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  letter-spacing: -0.02em;
  line-height: 1.2;
  text-wrap: balance;
}

.ob-head__subtitle {
  max-width: 36ch;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: 1.45;
  text-wrap: pretty;
}

/* --- Sections and the grid ------------------------------------------------ */

.ob-browse {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.ob-browse[hidden],
.ob-results[hidden] {
  display: none;
}

.ob-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.ob-section__title {
  padding-inline: var(--space-1);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
}


/*
 * Four across. The tiles divide the width between them, so a long name wraps
 * inside its column rather than widening it — the search overlay's cards make
 * the same deal in a row.
 */
.ob-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-3) var(--space-2);
}

/* --- Club tile ------------------------------------------------------------ */

/*
 * A crest over its name. 0.92 is the search card's press — a disc with
 * nothing around it needs more travel to read as pressed than a row does —
 * and it goes through --press-scale so pressable() still owns the timing.
 */
.ob-tile {
  --press-scale: 0.92;

  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  padding-block: var(--space-1);
}

.ob-tile:focus-visible {
  border-radius: var(--radius-md);
}

/*
 * The badge disc: the search card's, one size up, and round — a club here is
 * the picture, not an identifier in a row. The crest keeps its own shape
 * inside; a transparent PNG needs no plate, so `.logo`'s sunken fill and
 * corner go, the way the club page's identity badge drops them.
 */
.ob-tile__disc {
  position: relative;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-card);
  transition: border-color var(--duration) var(--easing);
}

.ob-tile__disc .logo:not(.logo--monogram) {
  background: none;
  border-radius: 0;
}

/* The fallback still needs its plate, and a round one inside a round disc. */
.ob-tile__disc .logo--monogram {
  border-radius: var(--radius-full);
}

/*
 * A competition's tile is square — the search overlay's own distinction
 * between a club's badge and a competition's crest, at this size. The mark
 * sits a little further in, where a rounded corner has room for it.
 */
.ob-tile--square .ob-tile__disc {
  border-radius: var(--radius-lg);
}

.ob-tile--square .ob-tile__disc .logo--monogram {
  border-radius: var(--radius-md);
}

.ob-tile--square .ob-tile__mark {
  right: -6px;
  bottom: -6px;
}

/*
 * The selection mark, at the disc's corner: the accent fill that means
 * "this one is active" everywhere else, scaled in on the spring. The 2px of
 * page colour around it is what keeps it a mark on the disc rather than a
 * blot on the crest.
 */
.ob-tile__mark {
  position: absolute;
  right: -3px;
  bottom: -3px;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  background: var(--accent);
  border-radius: var(--radius-full);
  box-shadow: 0 0 0 2px var(--bg);
  color: var(--accent-text);
  transform: scale(0);
  transition: transform var(--spring-duration) var(--spring);
}

.ob-tile[aria-pressed="true"] .ob-tile__mark {
  transform: scale(1);
}

/* The hairline joins the mark — a grey edge beside a blue badge reads as a
   rendering artifact, not a border. */
.ob-tile[aria-pressed="true"] .ob-tile__disc {
  border-color: var(--accent);
}

/* Two lines, then it clips — the search card's own rule. */
.ob-tile__name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  max-width: 100%;
  color: var(--text-secondary);
  font-size: var(--text-2xs);
  font-weight: var(--weight-medium);
  line-height: 1.25;
  text-align: center;
  transition: color var(--duration) var(--easing);
}

.ob-tile[aria-pressed="true"] .ob-tile__name {
  color: var(--accent);
  font-weight: var(--weight-semibold);
}

/*
 * A player's club, under the name. One line, muted — the squads are
 * placeholders today and the club is the part of the label that means
 * anything. Tightened against the name so the two read as one label.
 */
.ob-tile__sub {
  max-width: 100%;
  margin-top: calc(-1 * var(--space-1));
  color: var(--text-muted);
  font-size: var(--text-2xs);
  line-height: 1.25;
  text-align: center;
}

/* A player's tile is a portrait, so the disc is the picture — the photo (or
   the monogram standing in for it) fills it edge to edge. */
/*
 * The portrait fills the disc edge to edge, so it is the portrait that is
 * clipped round — not the disc. Clipping the disc took the selection mark
 * with it: the mark sits a few pixels outside the disc's edge on every
 * tile, and under `overflow: hidden` it vanished behind the face.
 */
.ob-tile--player .ob-tile__disc .logo {
  border-radius: var(--radius-full);
  object-fit: cover;
}

.ob-tile--player .ob-tile__name {
  -webkit-line-clamp: 1;
  line-clamp: 1;
}

/*
 * The selection overshoot, on the disc: the filter chip's own pop. --easing
 * rather than --spring, because the keyframe already carries the overshoot.
 */
.ob-tile__disc[data-pop="true"] {
  animation: ob-disc-pop var(--spring-duration) var(--easing);
}

@keyframes ob-disc-pop {
  0% {
    transform: scale(1);
  }
  45% {
    transform: scale(1.08);
  }
  100% {
    transform: scale(1);
  }
}

/* --- Competition groups --------------------------------------------------- */

.ob-groups {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.ob-groups__more:empty {
  display: none;
}

/* The fixtures accordion's card: white, hairline, shallow lift. */
.ob-group {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.ob-group__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3);
  text-align: left;
}

.ob-group__head:active {
  background: var(--surface-sunken);
}

.ob-group__text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.ob-group__name {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.ob-group__region {
  color: var(--text-muted);
  font-size: var(--text-xs);
}

/* Right when closed, down when open — the fixtures accordion's scheme. */
.ob-group__chevron {
  display: grid;
  place-items: center;
  color: var(--text-muted);
  transform: rotate(-90deg);
  transition: transform var(--duration) var(--easing);
}

.ob-group__head[aria-expanded="true"] .ob-group__chevron {
  transform: rotate(0deg);
}

.ob-group__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: 0 var(--space-3) var(--space-3);
}

.ob-group__body[hidden] {
  display: none;
}

/* --- Competition rows ----------------------------------------------------- */

/*
 * The competitions step's feed list: the group head above, with a mark at
 * the trailing edge in place of the chevron. Rows rather than tiles because
 * the names are long and often identical — eight of this export's
 * competitions are called "Cup" — and the country is what tells them apart.
 */
.ob-rows {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.ob-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  text-align: left;
  transition: border-color var(--duration) var(--easing);
}

.ob-row:active {
  background: var(--surface-sunken);
}

.ob-row__text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.ob-row__name {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  transition: color var(--duration) var(--easing);
}

.ob-row__region {
  color: var(--text-muted);
  font-size: var(--text-xs);
}

/*
 * The mark: an empty ring at rest — the mid grey tokens.css keeps for
 * exactly "an empty selection ring" — and the accent fill with the tick once
 * followed. The glyph inside scales in on the spring, the tile's own move.
 */
.ob-row__mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius-full);
  color: var(--accent-text);
  transition:
    background-color var(--duration) var(--easing),
    border-color var(--duration) var(--easing);
}

.ob-row__mark .icon {
  transform: scale(0);
  transition: transform var(--spring-duration) var(--spring);
}

.ob-row[aria-pressed="true"] {
  border-color: var(--accent);
}

.ob-row[aria-pressed="true"] .ob-row__name {
  color: var(--accent);
}

.ob-row[aria-pressed="true"] .ob-row__mark {
  background: var(--accent);
  border-color: var(--accent);
}

.ob-row[aria-pressed="true"] .ob-row__mark .icon {
  transform: scale(1);
}

.ob-row__mark[data-pop="true"] {
  animation: ob-disc-pop var(--spring-duration) var(--easing);
}

.ob-empty {
  padding-inline: var(--space-1);
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* --- Footer --------------------------------------------------------------- */

/*
 * Pinned outside the scroller, and clearing whichever bottom obstruction is
 * larger — the device safe area, or the slice of the window Telegram's own
 * chrome is covering. The filter sheet's footer, on the page instead of a
 * sheet, which is why it takes the page's ground rather than a card's.
 */
.onboarding__footer {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-3)
    calc(var(--space-4) + max(var(--safe-bottom), var(--tg-chrome-inset, 0px)));
  background: var(--bg);
  border-top: 1px solid var(--border);
}

/* --- Tray ----------------------------------------------------------------- */

/*
 * What has been picked, as a stack of crests and one line of words. It sits
 * over the button so the count and the button's label say the same thing at
 * the same moment.
 */
.ob-tray {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 28px;
  padding-inline: var(--space-1);
}

.ob-tray__crests {
  display: flex;
  align-items: center;
}

.ob-tray__crests:empty {
  display: none;
}

/* Overlapped, each cut out of the one before by a ring of page colour. */
.ob-tray__crest {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  margin-left: -8px;
  background: var(--surface);
  border-radius: var(--radius-full);
  box-shadow: 0 0 0 2px var(--bg);
}

.ob-tray__crest:first-child {
  margin-left: 0;
}

.ob-tray__crest .logo:not(.logo--monogram) {
  background: none;
}

/* A competition's crest in the tray keeps its square, on a square plate. */
.ob-tray__crest--square {
  border-radius: var(--radius-sm);
}

/* An arrival springs in; a crest already there is left alone. */
.ob-tray__crest[data-appeared="true"] {
  animation: ob-crest-in var(--spring-duration) var(--spring) backwards;
}

@keyframes ob-crest-in {
  from {
    transform: scale(0.4);
    opacity: 0;
  }
}

.ob-tray__more {
  display: grid;
  place-items: center;
  height: 28px;
  margin-left: -8px;
  padding-inline: var(--space-2);
  background: var(--surface-sunken);
  border-radius: var(--radius-full);
  box-shadow: 0 0 0 2px var(--bg);
  color: var(--text-secondary);
  font-size: var(--text-2xs);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}

.ob-tray__text {
  flex: 1;
  min-width: 0;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.3;
}

.ob-tray[data-empty="true"] .ob-tray__text {
  color: var(--text-muted);
  font-weight: var(--weight-regular);
}

/* --- CTA ------------------------------------------------------------------ */

/*
 * The filter sheet's footer button — `.btn--primary`, full width — a step
 * taller and a step larger in type, because it is the one control on a screen
 * rather than the close of a sheet under a list.
 */
.ob-cta {
  position: relative;
  width: 100%;
  height: 52px;
  justify-content: center;
  font-size: var(--text-sm);
}

/*
 * Nothing picked is not an error and not a disabled control — the button
 * still moves on, it just stops wearing the accent, which is reserved for
 * something worth doing. The filter sheet's zero-results button, exactly.
 */
.ob-cta[data-empty="true"] {
  background: var(--surface-pressed);
  color: var(--text-muted);
  box-shadow: none;
}

.ob-cta__label {
  transition: opacity var(--duration) var(--easing);
}

/* Inline on the button, where the work was asked for: label gives way to a
   compact spinner. */
.ob-cta__spinner {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 18px;
  height: 18px;
  margin: -9px 0 0 -9px;
  border: 2px solid rgb(var(--text-inverse-rgb) / 0.35);
  border-top-color: var(--text-inverse);
  border-radius: var(--radius-full);
  opacity: 0;
  transition: opacity var(--duration) var(--easing);
}

.ob-cta[data-loading="true"] .ob-cta__label {
  opacity: 0;
}

.ob-cta[data-loading="true"] .ob-cta__spinner {
  opacity: 1;
  animation: boot-spin 0.9s linear infinite;
}

/* Bare accent type under the button — the filter sheet's Reset, centred. */
.ob-later {
  align-self: center;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  color: var(--accent);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.ob-later[hidden] {
  display: none;
}

/* --- Notifications -------------------------------------------------------- */

/*
 * A chat bubble from the bot, as a picture. The card the whole app is made
 * of, with one corner squared where the tail of a message would be, and the
 * mark in a small disc beside it the way a sender's photo sits.
 */
.ob-preview {
  display: flex;
  align-items: flex-end;
  gap: var(--space-2);
  padding-inline: var(--space-1);
}

.ob-preview__avatar {
  --mark-height: 16px;

  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
}

.ob-preview__bubble {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-width: 84%;
  padding: var(--space-2) var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  border-bottom-left-radius: var(--radius-sm);
  box-shadow: var(--shadow-card);
}

.ob-preview__sender {
  color: var(--accent);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}

.ob-preview__text {
  font-size: var(--text-sm);
  line-height: 1.4;
}

.ob-preview__meta {
  align-self: flex-end;
  color: var(--text-muted);
  font-size: var(--text-2xs);
  font-weight: var(--weight-medium);
}

.ob-switches {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/*
 * The switch was built to sit inside the white sheet, where the sunken grey
 * is a fill inside a card. On the page it is nearly the page's own colour, so
 * here each one is a card — tokens.css's rule for a control that sits
 * directly on the page.
 */
.ob-switches .filter-switch {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
}

/* --- Done ----------------------------------------------------------------- */

/*
 * The checkmark draws in — a ring, then the tick a beat behind it, both
 * inside the app's ceiling. stroke-dashoffset is a paint property: it
 * repaints the stroke and reflows nothing, and it is the only way to
 * genuinely draw a stroke on. The story ring's own device.
 */
.ob-check {
  display: block;
  margin-bottom: var(--space-2);
  background: var(--accent-soft);
  border-radius: var(--radius-full);
}

.ob-check__ring,
.ob-check__tick {
  fill: none;
  stroke: var(--accent);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* 2π × 29, rounded up. */
.ob-check__ring {
  stroke-dasharray: 183;
  stroke-dashoffset: 183;
  animation: ob-draw var(--spring-duration) var(--easing) forwards;
}

/* The two legs, 12 and 24 long. */
.ob-check__tick {
  stroke-dasharray: 37;
  stroke-dashoffset: 37;
  animation: ob-draw var(--duration) var(--easing) forwards;
  animation-delay: calc(var(--stagger-step) * 3);
}

@keyframes ob-draw {
  to {
    stroke-dashoffset: 0;
  }
}

.ob-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
}

.ob-card__title {
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
}

.ob-card__hint {
  margin-top: calc(-1 * var(--space-2));
  color: var(--text-muted);
  font-size: var(--text-xs);
}

/* --- Page behind ---------------------------------------------------------- */

body[data-onboarding-open] {
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .ob-tile__disc[data-pop="true"],
  .ob-row__mark[data-pop="true"],
  .ob-tray__crest[data-appeared="true"],
  .ob-check__ring,
  .ob-check__tick {
    animation: none;
  }

  /* Drawn already, rather than never drawn. */
  .ob-check__ring,
  .ob-check__tick {
    stroke-dashoffset: 0;
  }
}
