/* ── Onboarding (node 390:3454) ───────────────────────────────────────────────
   Splash animation → Sport Selection → What to do most → Where you work out. */

/* ── Splash ─────────────────────────────────────────────────────────────────── */
.ob-splash { position: relative; height: 100%; overflow: hidden;
  background: linear-gradient(180deg, #FA3030 59%, #FE6E3C 84%, #FEC389 95%, #D1FEFF 101.5%); }
/* White → warm → (reveals red) wash on entry. */
.ob-splash::before { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, #FFFFFF 18%, #FFE7CE 55%, #DAF6FA 90%);
  animation: ob-wash 1.9s ease forwards; }
@keyframes ob-wash { 0% { opacity: 1; } 25% { opacity: 1; } 100% { opacity: 0; } }

.ob-logo { position: absolute; left: 50%; top: 330px; width: 314px; height: 45px; margin-left: -157px;
  animation: ob-logo 1s cubic-bezier(.2,.7,.2,1) 1s both; }
.ob-logo img { width: 100%; height: 100%; display: block;
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 100%); mask-image: linear-gradient(90deg, #000 0, #000 100%); }
@keyframes ob-logo { from { opacity: 0; transform: translateY(10px) scale(.96); } }

.ob-turn { position: absolute; left: 0; right: 0; top: 277px; text-align: center;
  font-family: var(--font-supreme-bold); font-size: 22px; line-height: 1.2; letter-spacing: -1px; color: var(--color-black);
  animation: ob-fade .6s ease 2.1s both; }
/* Anchored to the FOOT, not 604 from the top. The splash is the one screen with no
   scroller (.ob-splash is overflow:hidden), so a viewport shorter than the design's 780
   simply cut the button off with no way to reach it — measured on a 360x640 phone, Get
   Started ran from 606 to 702 with 640 of screen. 81px is the gap the 780 frame already
   had below it (780 − 604 − 95), so nothing moves at the design size and it follows the bottom everywhere
   else. */
.ob-cta { position: absolute; left: 16px; right: 16px; bottom: 81px; animation: ob-fade .6s ease 2.35s both; }
.ob-get { display: flex; align-items: center; justify-content: center; gap: 4px; background: var(--color-black); border-radius: 999px; padding: 16px 20px; text-decoration: none;
  font-family: var(--font-supreme-bold); font-size: 18px; letter-spacing: -0.54px; color: #fff; }
.ob-get img { width: 20px; height: 20px; display: block; filter: brightness(0) invert(1); }
.ob-account { display: block; margin-top: 18px; text-align: center; font-family: var(--font-supreme-bold); font-size: 16px; letter-spacing: -0.5px; color: rgba(0,0,0,0.58); text-decoration: none; }
@keyframes ob-fade { from { opacity: 0; transform: translateY(6px); } }
.ob-splash .status-bar { position: absolute; top: 0; left: 0; z-index: 3; background: transparent; }
/* The dark-glyph plate that covers the white half of the wash. Multiply drops its own
   white ground, so only the glyphs are laid over the screen, and it leaves on exactly
   the wash's curve — same name, same duration, so the two can never drift apart. */
.ob-splash .sb-early { position: absolute; left: 0; top: 0; width: 100%;
  mix-blend-mode: multiply; animation: ob-wash 1.9s ease forwards; }

/* ── Shared onboarding page chrome (gray frame like setup) ────────────────────── */
.ob-screen { background: var(--color-neutral-100); }
/* Bottom bar is grey, not black — square off the screen's bottom so no black inverse-round shows. */
.phone:has(> .tabbar) > .screen.ob-screen { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.ob-screen .status-bar { background: var(--color-neutral-100); }
.ob-screen .statusbar-svg { mix-blend-mode: multiply; }
.ob-appbar { display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; box-sizing: border-box; }
.ob-appbar .back img { width: 24px; height: 24px; display: block; filter: brightness(0) invert(0.09); }
.ob-appbar .skip { font-family: var(--font-supreme); font-size: 16px; letter-spacing: -0.5px; color: var(--color-neutral-900); text-decoration: none; }
.ob-title { padding: 8px 16px 24px; }
.ob-title h1 { margin: 0; font-family: var(--font-supreme-bold); font-size: 32px; line-height: 1.2; letter-spacing: -1.5px; color: var(--color-black); }
.ob-title p { margin: 12px 0 0; font-family: var(--font-supreme); font-size: 15px; line-height: 1.4; letter-spacing: -0.5px; color: var(--color-neutral-500); }
/* Scrollable body (sport grid is taller than the viewport). */
.ob-body { flex: 1; overflow-y: auto; scrollbar-width: none; padding: 0 12px 12px; }
.ob-body::-webkit-scrollbar { display: none; }

/* ── Sport masonry grid ──────────────────────────────────────────────────────── */
.ob-grid { display: flex; gap: 4px; }
.ob-col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.ob-card { position: relative; box-sizing: border-box; border-radius: 20px; overflow: hidden; cursor: pointer; background: #fff; }
.ob-card.tall { height: 166px; }
.ob-card.short { height: 108px; }
.ob-card .t { position: relative; z-index: 2; margin: 0; padding: 16px; font-family: var(--font-supreme-bold); font-size: 20px; line-height: 1.2; letter-spacing: -1px; color: var(--color-black); }

/* How a sport card is actually built in Figma, and now here.
   The artwork is a GREYSCALE CUTOUT on transparency, and the red is a gradient laid over
   it in plus-lighter — one asset serving both states, because the two states differ only
   in which layer does the lightening:
       unselected   white card  ->  cutout, then the gradient over it (the red silhouette)
       selected     gradient card -> the cutout itself lightens what is already red
   Each figure has its own box inside the card, given here as --ix/--iy/--iw/--ih straight
   from the design; several of them are bigger than the card and the card's overflow clips
   them, which is the cropping the design intends. Exported at that box's size, so the
   picture is never resized into a shape it was not drawn for. */
.ob-card .img { position: absolute; left: var(--ix, 0); top: var(--iy, 0); width: var(--iw, 100%); height: var(--ih, 100%); }
/* The photograph, at whatever exposure this state wants. It sits on ::before rather than
   on .img itself because a filter makes a stacking context, and the gradient below has to
   blend with the CARD, not stop at the picture. --dim is the card's own number: these are
   photographs of very different brightness and one level for all of them is what washed
   three of the cards out.
   NOTE the ../ in each card's --art: a url() inside a custom property is resolved against
   the sheet that USES it, not the document that declared it, and this sheet is in styles/. */
.ob-card .img::before { content: ""; position: absolute; inset: 0;
  background: var(--art) center / 100% 100% no-repeat;
  filter: brightness(var(--dim, 1)); }
.ob-card .img::after { content: ""; position: absolute; inset: 0; mix-blend-mode: plus-lighter;
  background: var(--grad, linear-gradient(180deg, #FA3030, #FEB179)); }
/* Selected: Newton gradient fill + white title + the cutout lightening it + check + glow. */
.ob-card.sel { background: linear-gradient(180deg, #FA3030 48%, #FE6E3C 77.6%, #FEC389 100.5%, #D1FEFF 107.5%);
  box-shadow: 0 15px 58.32px 10px rgba(0,0,0,0.05), inset 0 0 16px 6px rgba(255,255,255,0.6); }
/* Selected, the picture is what lightens the gradient — so it goes back up, to the
   exposure the design gives the selected artwork (a little under 5.3x the dim one), and
   the gradient overlay steps aside. */
.ob-card.sel .img::before { filter: brightness(calc(var(--dim, 1) * var(--sel-lift, 5.3))); mix-blend-mode: plus-lighter; }
.ob-card.sel .img::after { content: none; }
.ob-card.sel .t { color: #fff; }

/* ── "What do you want to do most?" list ─────────────────────────────────────── */
.ob-list { display: flex; flex-direction: column; gap: 4px; }
.ob-row { position: relative; display: flex; align-items: center; height: 85.2px; box-sizing: border-box; border-radius: 20px; overflow: hidden; cursor: pointer; background: #fff; }
.ob-row .t { position: relative; z-index: 2; margin: 0; padding: 0 20px; font-family: var(--font-supreme-bold); font-size: 20px; line-height: 1.2; letter-spacing: -1px; color: var(--color-black); }
/* The figure does NOT span the row. In the design (node 43:6432) every one of these sits
   in a 122x152 box at left 180, top -33 — taller than the 85.2 row, so the row's own
   overflow crops the head and the feet, which is the crop the design intends. The old
   version stretched the picture across the whole 336x85 row instead, and a standing figure
   pulled into a 4:1 box is what came out looking squashed.
   The gradient is over the BOX, not the row: plus-lighter over the white card leaves the
   card white and only the figure turns red.
   NOTE the ../ in each row's --art: a url() inside a custom property is resolved against
   the sheet that USES it, not the document that declared it, and this sheet is in styles/. */
.ob-row .img { position: absolute; left: 180px; top: -33px; width: var(--iw, 122px); height: 152px; }
.ob-row .img::before { content: ""; position: absolute; inset: 0;
  background: var(--art) center / 100% 100% no-repeat;
  /* Only where the design's own fill is exposed down from the photograph — measured per
     row against Figma's render, so most rows carry no --dim at all. */
  filter: brightness(var(--dim, 1)); }
.ob-row .img::after { content: ""; position: absolute; inset: 0; mix-blend-mode: plus-lighter;
  background: var(--grad, linear-gradient(180deg, #FA3030, #FD9562)); }
/* Selected, the row IS the gradient and the picture is what lightens it. */
.ob-row.sel .img::before { filter: none; mix-blend-mode: plus-lighter; }
.ob-row.sel .img::after { content: none; }
/* 직사각형_Selected, as the style is registered (node 2774:1124): the ramp runs DOWN the
   row, not across it, and the two effects are the drop shadow and the inner white glow. */
.ob-row.sel {
  background: linear-gradient(180deg, #FA3030 53.869%, #FE6E3C 85.083%, #FEC389 104.71%, #D1FEFF 104.72%);
  box-shadow: 0 15px 58.32px 10px rgba(0,0,0,0.05), inset 0 0 16px 6px rgba(255,255,255,0.6);
}
.ob-row.sel .t { color: #fff; }

/* ── "Where do you work out?" (Indoors / Outdoors / Both) ─────────────────────── */
.ob-where { display: flex; gap: 4px; }
.ob-where .col { display: flex; flex-direction: column; gap: 4px; }
.ob-where .col:first-child { width: 166px; }
.ob-where .col:last-child { flex: 1; }
.ob-wcard { position: relative; box-sizing: border-box; border-radius: 20px; overflow: hidden; cursor: pointer; padding: 16px; background: #fff; }
.ob-wcard.h { height: 219px; }
.ob-wcard.full { height: 442px; }
.ob-wcard .t { margin: 0; font-family: var(--font-supreme-bold); font-size: 20px; line-height: 1.2; letter-spacing: -1px; color: var(--color-black); position: relative; z-index: 2; }
.ob-wcard .s { margin: 2px 0 0; font-family: var(--font-supreme); font-size: 13px; line-height: 1.4; letter-spacing: -0.5px; color: var(--color-neutral-500); position: relative; z-index: 2; }
/* Same build as the goal rows, and the same reason: in the design (nodes I246:16630;43:6892
   and 246:16637) the picture is a box pinned to the CARD'S BOTTOM — 166 tall on the short
   pair, 266 on Both — not a fill of the whole card. Spreading it over the card is what
   pulled Outdoors' runner up into the text and cut his head off.
   Selected, the picture goes over the card's gradient in plus-lighter, which is what makes
   the figure read as light on red; multiply, which is what it used to do, made it dark. */
.ob-wcard .img { position: absolute; left: 0; bottom: 0; width: 166px; height: 166px; overflow: hidden; }
.ob-wcard.full .img { height: 266px; }
.ob-wcard .img::before { content: ""; position: absolute; inset: 0;
  background: var(--art) center / 100% 100% no-repeat; }
.ob-wcard .img::after { content: ""; position: absolute; inset: 0; mix-blend-mode: plus-lighter;
  background: var(--grad, linear-gradient(180deg, #FA3030 28.508%, #FD9562 80.191%)); }
.ob-wcard.sel .img::before { mix-blend-mode: plus-lighter; }
.ob-wcard.sel .img::after { content: none; }
/* 직사각형_Selected + the registered `selected` effect pair. */
.ob-wcard.sel { background: linear-gradient(180deg, #FA3030 53.869%, #FE6E3C 85.083%, #FEC389 104.71%, #D1FEFF 104.72%);
  box-shadow: 0 15px 58.32px 10px rgba(0,0,0,0.05), inset 0 0 16px 6px rgba(255,255,255,0.6); }
.ob-wcard.full.sel { box-shadow: 0 15px 58.32px 10px rgba(0,0,0,0.05), inset 0 0 14px 10px rgba(255,255,255,0.45); }
.ob-wcard.sel .t { color: #fff; }
.ob-wcard.sel .s { color: var(--color-neutral-100); }

/* ── Bottom bar (Next) ───────────────────────────────────────────────────────── */
.ob-bottom { justify-content: space-between; padding: 12px 16px 0; box-sizing: border-box; background: var(--color-neutral-100); }
.ob-bottom .sb-row { display: flex; align-items: center; justify-content: flex-end; height: 32px; }
.ob-next { display: flex; align-items: center; gap: 2px; font-family: var(--font-supreme-bold); font-size: 22px; line-height: 1.2; letter-spacing: -1px; color: var(--color-black); text-decoration: none; }
.ob-next img { width: 13px; height: 12px; display: block; margin: 0 5px; filter: brightness(0) invert(0.03); }
/* Gated pages dim it until they are answered — same rule the setup bar follows, so a
   Next that is not yet a Next looks the same everywhere. */
.ob-next.gated { color: var(--color-neutral-400, #A3A3A3); cursor: default; transition: color .3s ease; }
.ob-next.gated img { filter: brightness(0) invert(0.68); transition: filter .3s ease; }
.ob-next.gated.ready { color: var(--color-black); }
.ob-next.gated.ready img { filter: brightness(0) invert(0.03); }

/* Where each family hangs the shared tick (see main.css for the mark itself). */
.ob-card .ob-check  { top: 4px;  right: 4px; }
.ob-wcard .ob-check { top: 8px;  right: 8px; }
.ob-row .ob-check   { top: 50%; right: 8px; margin-top: -26px; }

/* ── Arrival ──────────────────────────────────────────────────────────────────
   The cards come up from below when the step opens, a beat apart down each column and
   the right column half a beat behind the left, so the two read as one wave rather than
   two lists starting at once. Runs once, on load; nothing re-triggers it. */
@keyframes ob-rise { from { opacity: 0; transform: translateY(22px); } }
.ob-grid .ob-card, .ob-list .ob-row, .ob-where .ob-wcard {
  animation: ob-rise .52s cubic-bezier(.2,.85,.25,1) both;
  animation-delay: var(--rise, 0ms);
}
.ob-col > :nth-child(1), .ob-list > :nth-child(1), .ob-where .col > :nth-child(1) { --rise: 40ms; }
.ob-col > :nth-child(2), .ob-list > :nth-child(2), .ob-where .col > :nth-child(2) { --rise: 100ms; }
.ob-col > :nth-child(3), .ob-list > :nth-child(3) { --rise: 160ms; }
.ob-col > :nth-child(4), .ob-list > :nth-child(4) { --rise: 220ms; }
.ob-col > :nth-child(5), .ob-list > :nth-child(5) { --rise: 280ms; }
.ob-col > :nth-child(6) { --rise: 340ms; }
.ob-grid .ob-col:last-child > * { animation-delay: calc(var(--rise, 0ms) + 30ms); }
.ob-where .col:last-child > * { animation-delay: calc(var(--rise, 0ms) + 30ms); }
@media (prefers-reduced-motion: reduce) {
  .ob-grid .ob-card, .ob-list .ob-row, .ob-where .ob-wcard { animation: none; }
}

/* ── The top of the scroller ──────────────────────────────────────────────────
   Cards used to pass under the heading and stop dead on a hard line. They now fade out
   into it instead: the strip sits on the title (which is the element directly above the
   scroller, whatever each page's heading height turns out to be) and carries both a wash
   of the page's own grey and a little blur, so what is leaving is soft rather than cut. */
.ob-title { position: relative; z-index: 2; }
/* Only where the body actually scrolls. On the two short pages the list ends well above
   the foot, so a fade under the heading is a gradient over nothing. */
.ob-screen:has(.ob-list) .ob-title::after,
.ob-screen:has(.ob-where) .ob-title::after,
.ob-screen:has(.sc-list) .ob-title::after { content: none; }
.ob-title::after {
  content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 26px;
  pointer-events: none;
  background: linear-gradient(180deg, var(--color-neutral-100) 12%, rgba(242,242,242,0) 100%);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  -webkit-mask-image: linear-gradient(180deg, #000 20%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 20%, transparent 100%);
}
