.screen { background: var(--color-white); padding-bottom: 8px; }

/* ── Report notification ─────────────────────────────────────────────────
   The 66px strip lives above the 80px navbar. When the notification arrives,
   the content frame shrinks up by 66px (its rounded r40 bottom reveals the
   black phone bg over the strip), and the notification fades in. */
/* Concrete px endpoints so the shrink animates — Chrome freezes height
   transitions between calc(%) values. The phone is a fixed 780 (700 content
   + 80 navbar); the notification takes a 66px strip above the navbar. */
/* The 780 frame's two heights, and ONLY there. Unqualified they tie main.css's phone
   rules on specificity (0,4,1 either way) and win on load order, which pinned the content
   frame to 700/634 on a phone whose viewport is 800+ — the frame's rounded foot ended up
   below the pinned navbar, so the concave junction was off-screen and the edge read flat.
   On a phone the height comes from the viewport (main.css), as it should. */
html:not(.installed) .phone:has(> .tabbar) > .screen { height: 700px; }
html:not(.installed) .phone.notif-on:has(> .tabbar) > .screen { height: 634px; }
.notif-bar {
  position: absolute;
  left: 0; right: 0;
  bottom: 80px;
  height: 66px;
  z-index: 25;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity .45s ease .16s;
}
.phone.notif-on .notif-bar { opacity: 1; pointer-events: auto; }
.notif-new {
  display: flex; align-items: center; gap: 8px;
  background: none; border: none; cursor: pointer;
  color: #fff; font-family: var(--font-supreme-bold); font-size: 15px; letter-spacing: -0.5px;
  /* It RISES into the strip the frame has just opened, instead of appearing in place
     while the frame moves under it. Fading alone left the two halves of the arrival
     looking unrelated — the strip slid, the label did not. */
  /* Same curve and the same beat as the frame it rises into (home.html's reveal), so the
     strip and its label read as one thing settling rather than two. */
  transform: translateY(12px);
  transition: transform 1s cubic-bezier(.32,.72,0,1) .12s;
}
.phone.notif-on .notif-new { transform: none; }
.notif-dot { width: 8px; height: 8px; border-radius: 50%; background: #fff; }
.notif-rich { display: none; align-items: center; justify-content: space-between; width: 100%; padding: 0 16px; box-sizing: border-box; }
.phone.notif-open .notif-new { display: none; }
.phone.notif-open .notif-rich { display: flex; }
/* Tapping New Report: the avatar+title (left) and the Open button (right) spread
   out from the centre to their resting edges — a quick, smooth outward expansion. */
@keyframes rich-spread-left  { from { transform: translateX(92px);  opacity: 0; } }
@keyframes rich-spread-right { from { transform: translateX(-92px); opacity: 0; } }
.phone.notif-open .notif-left  { animation: rich-spread-left  .42s cubic-bezier(.22,.9,.3,1) both; }
.phone.notif-open .report-open { animation: rich-spread-right .42s cubic-bezier(.22,.9,.3,1) both; }
.notif-left { display: flex; align-items: center; gap: 8px; }
.notif-av { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; }
.notif-left span { color: #fff; font-family: var(--font-supreme-bold); font-size: 15px; letter-spacing: -0.5px; }
.report-open {
  display: flex; align-items: center; gap: 4px;
  background: var(--color-red); color: #fff; text-decoration: none;
  border-radius: 999px; padding: 8px 12px 8px 16px;
  font-family: var(--font-supreme-bold); font-size: 15px; letter-spacing: -0.5px;
}
.report-open img { width: 18px; height: 18px; filter: brightness(0) invert(1); }
/* Set by tour.js just before it navigates: with no cursor on screen the recording needs
   the button to show it was pressed. */
.report-open { transition: filter .18s ease, transform .18s ease; }
.report-open.picked { filter: brightness(.78); transform: scale(.96); }

/* App bar: 66px tall (logo centered with 16px above/below), sitting flush against
   the card container below it (gap 0) — Figma home 108:16691. */
/* Above the carousel's scroll box, which now overlaps it by 30px of transparent padding
   so the scroller's clip edge is nowhere near the cards. Without this the search and plus
   icons would be sitting under a scroll container and stop taking taps. */
.app-bar { height: 66px; box-sizing: border-box; padding: 16px; position: relative; z-index: 2; }

/* The coral glow belongs to the CARDS, not to the slot they sit in. It used to be one
   blurred rect parked behind the carousel, so swiping left left the shadow behind and the
   next card arrived with nothing under it. It is a box-shadow on each card now, so every
   card carries its own and it travels with the swipe.
   Transcribed from that rect (Figma 108:16695) rather than eyeballed: 271x283 at top 38
   under a 319x326 card is y+16.5 with a -24 spread, and filter: blur(27px) is sigma 27,
   which as a box-shadow blur radius is 54. Colour is the same stack flattened — black
   0.26 over rgba(252,114,88,0.7) composites to rgba(168,76,59,0.78). */
.hero-section { position: relative; }
.hero-shadow { display: none; }
.hero-scroll {
  position: relative;
  z-index: 1;
  display: flex;
  gap: 8px;
  overflow-x: auto;
  /* 20px sides so the first (Akiyama) card sits centered in the 360 viewport on load. */
  padding: 0 20px 0;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  /* Room for each card's glow, taken back with a negative margin so nothing moves. A
     horizontal scroller clips VERTICALLY too, and its clip edge used to sit exactly on
     the card's top edge (Figma gap 0) — the carousel was boxed in against the app bar
     above and the section below, and any glow met a straight container line instead of
     air.
     60/120 rather than 30/60: a box-shadow blur radius B is a Gaussian with sigma B/2,
     and a Gaussian is still faintly painting out at ~1.5 sigma — so the 96px tail carries
     roughly 70px past its shadow rect, not the 48 that half-the-radius suggests. 60px of
     room cut it, and THAT was the straight edge under the carousel.
     This padding lies over the app bar and over Recently Viewed, so both of those are
     raised above it instead (z-index, below) — they have no background of their own, so
     the glow still shows THROUGH them and their taps still land.
     It used to be pointer-events: none here with auto on the cards, which works in
     Chrome but stops iOS panning the scroller at all: WebKit will not pan a scroll
     container that does not take pointer events, whatever its children say. That is why
     the home carousel did nothing on an iPhone. */
  padding-top: 60px;
  margin-top: -60px;
  padding-bottom: 120px;
  margin-bottom: -120px;
}
/* Everything after the carousel sits over its padding. No backgrounds on these, so the
   glow reads through them exactly as before. */
.screen > .app-bar, .screen > section { position: relative; z-index: 2; }
.hero-scroll::-webkit-scrollbar { display: none; }

.hero-card {
  position: relative;
  flex: 0 0 auto;
  width: 319px;
  height: 326px;
  border-radius: 40px;
  overflow: hidden;
  background-size: cover;
  background-position: center;
  text-decoration: none;
  scroll-snap-align: center;
  /* One card per swipe. Without this a flick on a phone sails past two or three cards at
     once — mandatory snap only says WHERE it may stop, not that it has to stop at the
     next one. Packs and the report carousels already carry it; the hero did not. */
  scroll-snap-stop: always;
  /* iOS will not clip a composited child — a <video> is always one — to a parent's
     border-radius unless that parent is a stacking context of its own. Without this the
     clip escaped and the cards read as square-cornered on an iPhone. It is also what
     scopes plus-lighter to the card rather than to whatever is behind it; card 1 had it
     for that reason and 2 and 3 did not. */
  isolation: isolate;
  /* WebKit needs the promise kept, not just declared: on an iPhone the plus-lighter shot
     inside was still reaching the page, which paints the card's own rectangle a shade
     lighter than everything around it and leaves the glow looking cut off at that edge.
     A composited layer cannot blend outside itself, so the isolation actually holds.
     iOS only — on Chrome the declaration is enough and a promoted layer per card is a
     raster it does not need. */
  /* Two shadows, not one: the Figma rect (17/54/-24) IS the glow, but on its own it stops
     dead about 20px under the card — a compact smudge with an edge. The second is the
     same colour spread twice as far and half as strong, purely to give the first one a
     tail to fade into, so the blur runs out instead of ending. */
  box-shadow: inset 0 0 20px 10px rgba(255,255,255,0.2),
              0 17px 54px -24px rgba(168,76,59,0.78),
              0 26px 96px -34px rgba(168,76,59,0.42);
}
/* The first card is the video one, built the way Figma builds it (2476:3531): the empty
   card's own two radial fills, with the clip added on top in plus-lighter. The clip is
   shot on black, and plus-lighter adds luminance — black adds nothing, so the backdrop
   never appears and no keying is needed. It also means the bottom takes care of itself:
   where the frame holds his dark shorts almost nothing is added, so the card's mint
   ending shows through instead of being blown out.
   Gradients transcribed from 카드.svg, ellipse axes and stops unchanged. The card's own
   inset white glow is that file's inner shadow (erode 10 + blur 10, white 0.2) and is
   already on .hero-card.
   Clip geometry is Figma's, exactly: 266x473 at (30, -13) — which is the whole frame,
   uncropped, centred on the card. */
.hero-card-live {
  background:
    radial-gradient(267.32px 273.18px at 159.5px 60.1px, rgba(209,254,255,0) 88.8%, rgba(209,254,255,0.5) 100%),
    radial-gradient(361.63px 345.5px at 160px 104.5px, #FA3030 33.17%, #FEC389 61.42%, #D1FEFF 77.58%);
}
/* Cards 2 and 3 are their own colourways, not tints of card 1 — transcribed from Figma
   2496:280 and 2496:294. Same overlay in both (the D1FEFF radial, stop alpha .9 on a 50%
   layer = .45), same inset glow at 0.3; only the base ramp differs. Its centre sits near
   the top of the card and the ellipse is wide, which is why these two read as vertical
   while card 1 reads as a hot spot. */
.hero-card-2 {
  background:
    radial-gradient(267.32px 273.18px at 159.5px 60.1px, rgba(209,254,255,0) 88.88%, rgba(209,254,255,0.45) 100%),
    radial-gradient(379.15px 362.24px at 160px 36px,
      #FA3030 7.65%, #FB4C2F 24.26%, #FD672E 40.87%, #FF9E2C 74.08%,
      #FFA743 75.93%, #FFB15B 77.77%, #FEC389 81.46%, #E8E1C4 84.89%, #D1FEFF 88.32%);
}
.hero-card-3 {
  background:
    radial-gradient(267.32px 273.18px at 159.5px 60.1px, rgba(209,254,255,0) 88.88%, rgba(209,254,255,0.45) 100%),
    radial-gradient(595.86px 435.76px at 159px 54.74px,
      #920F0F 22.12%, #C01010 36.61%, #EE1010 51.11%, #F42320 54.37%,
      #FA3630 57.63%, #FB502F 60.27%, #FD6A2E 62.91%, #FF9E2C 68.20%);
}
/* These two carry a 0.3 inner glow instead of 0.2 (their Figma nodes), so the whole
   box-shadow list is restated — the outer coral glow has to come along with it. */
.hero-card-2, .hero-card-3 {
  box-shadow: inset 0 0 20px 10px rgba(255,255,255,0.3),
              0 17px 54px -24px rgba(168,76,59,0.78),
              0 26px 96px -34px rgba(168,76,59,0.42);
}
/* The artwork sits in a card-sized wrapper rather than carrying the mask itself, so the
   mask stays in CARD coordinates and every card can size its own picture freely — a
   9:16 video and a near-square still both fade out on the same circle.
   Figma's mask on the figure (2476:3553): a 318x359 alpha mask at -29,-4 in the clip's
   box holding one radial — centre (159,96.5) in the mask's own box, r 262.5, opaque to
   31.25% and out to nothing at 96.65%. In card coordinates that circle is centred
   (160, 79.5). Solid to card y≈161 and only fully gone below the card, so it is a long
   slow fade, not a cut — the text is carried by .hero-blur below, not by this.
   plus-lighter on the wrapper: the artwork is shot on black and additive blending adds
   nothing for black, so the backdrop never appears and no keying is needed.
   Its own rounded clip as well as the card's: on iOS the <video> inside is composited and
   escapes the card's border-radius, and this wrapper is masked (so WebKit rasterises it)
   which makes its overflow clip stick where the card's does not. */
.hero-shot {
  position: absolute;
  inset: 0;
  border-radius: 40px;
  overflow: hidden;
  mix-blend-mode: plus-lighter;
  pointer-events: none;
  /* Figma's stops are the defaults. A card whose artwork stays bright all the way down
     tightens the fade instead of dimming the whole figure: the head and shoulders keep
     their weight, and the picture is gone by the time the title starts, which is what
     card 1 gets for free because Akiyama's frame darkens there on its own. */
  -webkit-mask-image: radial-gradient(262.5px 262.5px at 160px 79.5px, #000 var(--mask-in, 31.25%), rgba(0,0,0,0) var(--mask-out, 96.65%));
  mask-image: radial-gradient(262.5px 262.5px at 160px 79.5px, #000 var(--mask-in, 31.25%), rgba(0,0,0,0) var(--mask-out, 96.65%));
}
/* Centred by default; each card gives its own top/width inline, because the pictures are
   different shapes and the framing is per-picture. */
.hero-clip {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  display: block;
  /* plus-lighter only ever adds, so a bright subject clips to white and takes the title
     with it — soft-light black cannot pull a near-white base back down (its result is
     base², which is 0.96 at base 0.98). The fix has to happen BEFORE the additive step.
     Each card sets its own value so the figure lands in the same luminance range as the
     Figma original: Akiyama's clip reads 106 mean behind the text band, and a card whose
     artwork reads brighter than that is scaled to match. */
  filter: brightness(var(--clip-bright, 1));
}

/* Figma's Blur layer (2476:3535) — #000000, 104 layer blur, soft-light, 279x166 at
   (5,149), under the text container and the button. This is what seats the title and the
   Pack line: soft-light darkens the bright vest behind them without touching the card's
   mint ending.
   It is also where the drift lives. Two black slabs on different periods inside one
   blurred, soft-light parent: the union's silhouette keeps changing, so the soft dark
   pool under the figure and behind the text breathes instead of sitting still. A single
   slab only slides — near its middle a big blur is almost translation-invariant. */
.hero-blur {
  position: absolute;
  left: 5px;
  top: 149px;
  width: 279px;
  height: 166px;
  filter: blur(104px);
  mix-blend-mode: soft-light;
  pointer-events: none;
}
.hero-blur i {
  position: absolute;
  inset: 0;
  background: #000;
  will-change: transform;
}
.hero-blur i:nth-child(1) { animation: blur-drift-a 17s ease-in-out infinite alternate; }
.hero-blur i:nth-child(2) { animation: blur-drift-b 23s ease-in-out infinite alternate; }
@keyframes blur-drift-a {
  0%   { transform: translate(-7%, 6%)  scale(1.00, 0.88); }
  34%  { transform: translate(5%, -3%)  scale(1.10, 1.06); }
  67%  { transform: translate(-3%, 5%)  scale(1.04, 0.94); }
  100% { transform: translate(8%, -4%)  scale(1.12, 1.10); }
}
@keyframes blur-drift-b {
  0%   { transform: translate(9%, -5%)  scale(1.14, 1.04); }
  41%  { transform: translate(-6%, 6%)  scale(1.02, 0.86); }
  73%  { transform: translate(4%, -4%)  scale(1.10, 1.08); }
  100% { transform: translate(-9%, 4%)  scale(1.05, 0.92); }
}
@media (prefers-reduced-motion: reduce) { .hero-blur i { animation: none; } }
.hero-text {
  position: absolute;
  top: 189px;
  left: 20px;
  right: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.hero-title {
  margin: 0;
  font-family: var(--font-supreme-bold);
  font-size: 28px;
  line-height: 1.2;
  letter-spacing: -1.5px;
  color: #fff;
}
.hero-meta {
  display: flex;
  align-items: center;
  /* 4, not the 8 this row used to carry: with the dot between them every meta row in the
     app is now built the same way — tier, 4, dot, 4, length. Its own asset rather than a
     filtered grey one, because this is the only meta row that sits on a photograph. */
  gap: 4px;
  justify-content: center;
  margin-top: 8px;                 /* title → Pack line */
  font-family: var(--font-supreme);
  font-size: 13px;
  line-height: 1.2;
  letter-spacing: -0.5px;
  color: #fafafa;
}
.hero-meta .dim { color: #fff; opacity: 0.9; }
.hero-meta .sep { width: 3px; height: 3px; }
.hero-btn {
  position: absolute;
  bottom: 16px;
  left: 52px;
  right: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 16px 20px;
  border-radius: 999px;
  background: linear-gradient(rgba(0,0,0,.2), rgba(0,0,0,.2)), var(--btn, #FA3030);
  color: #fff;
  font-family: var(--font-supreme-bold);
  font-size: 18px;
  letter-spacing: -0.54px;
}
.hero-btn img { width: 20px; height: 20px; filter: brightness(0) invert(1); }

.section { padding: 0 12px; margin-top: 40px; }
/* Recently Viewed → Today's Movement */
.section + .section { margin-top: 48px; }
.section-title {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0 0 16px;
}
.section-title img { width: 26px; height: 26px; }

.recent-list { display: flex; flex-direction: column; gap: 8px; }
.recent-item {
  display: flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  color: inherit;
}
.recent-thumb { width: 64px; height: 64px; border-radius: 8px; object-fit: cover; flex-shrink: 0; }
.recent-info { flex: 1; display: flex; flex-direction: column; gap: 4px; }
.recent-info p { margin: 0; }
.recent-meta { display: flex; align-items: center; gap: 4px; color: var(--color-neutral-600); }
.recent-meta .dim { color: var(--color-neutral-500); }
.recent-meta .sep { width: 3px; height: 3px; }
.recent-item .play { width: 32px; height: 32px; }

.movement-scroll {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 4px;
}
.movement-scroll::-webkit-scrollbar { display: none; }
/* All three cards fit the 360 frame — three 140s plus the gaps came to 436 and the
   last one was cut off at the right edge. Widths come from the row, so the row is the
   only place the number lives. */
.movement-card {
  flex: 0 0 calc((100% - 16px) / 3);
  text-decoration: none;
  color: inherit;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
/* Two gaps, not one: 8 from the picture to the title, 4 from the title to the tier.
   A column gap can only be one number, so the row gap is the smaller one and the title
   carries the difference as its own margin. Same 8/4 the More Packs cards already use. */
.movement-card p { margin: 0; }
.movement-card p:first-of-type { margin-top: 4px; line-height: 1.3; }
.movement-photo {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 16px;
  object-fit: cover;
}
.movement-collage {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 16px;
  overflow: hidden;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 1px;
  background: linear-gradient(#d1feff, #669293);
}
.movement-collage img { width: 100%; height: 100%; object-fit: cover; display: block; }

.dim { color: var(--color-neutral-500); }

/* "차라락" entrance — same curve and distance as Packs, the Library and My.
   Leaf rows, not whole sections, so the page arrives in reading order: hero, then each
   recent row, then the movement cards. `both` holds them hidden until their turn. */
.hero-section, .section-title, .recent-item, .movement-card {
  animation: home-slide .42s cubic-bezier(.2,.85,.3,1) both;
}
/* 프로토타입 2 opens on Home already built — the report notification is the subject, and
   a page assembling itself underneath it is a competing motion. Named rather than a blunt
   `* { animation: none }` so the notification's own reveal still runs. */
.no-intro .hero-section,
.no-intro .section-title,
.no-intro .recent-item,
.no-intro .movement-card { animation: none; }
.section:nth-of-type(1) .section-title { animation-delay: .06s; }
.recent-item:nth-child(1) { animation-delay: .10s; }
.recent-item:nth-child(2) { animation-delay: .14s; }
.recent-item:nth-child(3) { animation-delay: .18s; }
.section:nth-of-type(2) .section-title { animation-delay: .22s; }
.movement-card:nth-child(1) { animation-delay: .26s; }
.movement-card:nth-child(2) { animation-delay: .30s; }
.movement-card:nth-child(3) { animation-delay: .34s; }
@keyframes home-slide { from { opacity: 0; transform: translateY(18px); } }

html.ios .hero-card { transform: translateZ(0); }
