/* Feed — full-bleed vertical snap cards. Owned by the feed builder.
   TikTok's body, Level Up's soul: one card per viewport, confident Bricolage
   headlines, a mono "honesty line" where precision and assurance live, and a
   ladder-rail position indicator instead of dots. All colors are app.css
   tokens; card types differ by composition, never by new hues. */

.feed { position: relative; height: 100dvh; background: var(--canvas); }

.feed__scroll {
  height: 100%;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  overscroll-behavior-y: contain;
  scrollbar-width: none;
}
.feed__scroll::-webkit-scrollbar { display: none; }
.feed__scroll:focus-visible { outline: none; }

/* ------------------------------------------------------------- the card */

.fcard {
  position: relative;
  height: 100dvh;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  overflow: hidden;
}

/* Centred, not bottom-anchored. The note card was already centred and every
   other type was not, which is two compositions for one surface. Measure, type
   sizes and left alignment inside the column are unchanged; only the vertical
   anchor moves. */
.fcard__body {
  position: absolute;
  inset: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 0 104px;
  z-index: 2;
}
.fcard__col {
  width: min(660px, 100%);
  display: flex; flex-direction: column; gap: 14px;
}

/* Entrance: content steps up as the card snaps in. */
.fcard__col {
  opacity: 0; transform: translateY(18px);
  transition: opacity .5s cubic-bezier(.2,.7,.3,1), transform .5s cubic-bezier(.2,.7,.3,1);
}
.fcard.live .fcard__col { opacity: 1; transform: none; }

.fcard__eyebrow {
  font-family: var(--mono);
  font-size: 12px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent-text);
  display: flex; align-items: flex-start; gap: 9px;
}
/* The glyph and the words are separate flex children so a wrapped second
   line aligns under the first word, never under the glyph. */
.fcard__eyebrow .rung { color: var(--accent-text); margin-top: 3px; }
.fcard__eyebrow .etext { min-width: 0; }

.fcard__title {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(32px, 4.4vw, 56px);
  line-height: 1.04;
  letter-spacing: -.015em;
  text-wrap: balance;
  margin: 0;
}

.fcard__text {
  font-size: 16.5px; line-height: 1.55;
  color: var(--text-hi);
  max-width: 56ch;
}

/* The honesty line: where time precision, confidence and assurance live.
   In-card muted runs brighter than the app's --muted: this text sits on pure
   canvas at arm's length, and it is the point of the card, not a footnote. */
.fcard__truth {
  font-family: var(--mono);
  font-size: 13.5px;
  color: var(--text-mid);
  letter-spacing: .02em;
  line-height: 1.7;
}
.fcard__truth b { color: var(--text); font-weight: 500; }

.fcard__chips { display: flex; flex-wrap: wrap; gap: 8px; }

.fcard__actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 4px; }
.fcard__aside { font-size: 13px; color: var(--text-mid); }

/* Answered state (accept / decline / rsvp) — replaces the buttons in place.
   While the POST is still in flight it wears .pending: the same climbing
   rung the buttons use, so "we heard you" and "it is settled" read apart. */
.fcard__done { display: flex; flex-direction: column; gap: 10px; }
.fcard__done .headline { font-weight: 600; font-size: 15.5px; }
.fcard__done.pending .headline::after {
  content: '';
  display: inline-block;
  width: 11px; height: 11px;
  margin-left: 10px;
  vertical-align: -1px;
  background: var(--accent-text);
  clip-path: polygon(50% 0%, 100% 44%, 78% 44%, 78% 100%, 22% 100%, 22% 44%, 0% 44%);
  animation: climb .7s ease-in-out infinite;
}
.fcard__done.pending .headline { opacity: .85; }

/* -------------------------------------------------------- type: clip */

/* A clip card is media: it is lit by its own footage under its own dark
   scrim, in either theme. So this block re-pins the foreground tokens to
   their dark values — white text over a media scrim is a property of the
   scrim, not of the app's theme — and the scrim and its literals stay. */
.fcard--clip {
  --text: #FFFFFF;
  --muted: #8E8E93;
  --accent-text: #EC4A9C;
  --text-hi: rgba(255,255,255,.88);
  --text-mid: rgba(255,255,255,.62);
  --line: #2E2E33;
  --glass-raised: rgba(35,35,38,.72);
  --glass-raised-hov: rgba(46,46,51,.85);
  --accent-line-soft: rgba(224,48,138,.35);
  --accent-tint: rgba(224, 48, 138, .12);
}

/* Behind the pillarbox: the same clip again, blurred and scaled, so the
   frame is lit by the clip's own light instead of ending at a raw cut edge. */
.fcard--clip .vid-back {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(1.35);
  filter: blur(52px) saturate(1.2) brightness(.75);
  opacity: .9;
  z-index: 0;
  pointer-events: none;
}
.fcard--clip .vid-main {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  height: 100%; width: auto; max-width: 100%;
  object-fit: cover;
  z-index: 1;
}
.fcard--clip::after {
  /* readability scrim over the lower third */
  content: '';
  position: absolute; inset: 55% 0 0 0;
  background: linear-gradient(to bottom, transparent, rgba(13,13,15,.88));
  z-index: 2;
  pointer-events: none;
}
.fcard--clip .fcard__body { z-index: 3; }
.fcard--clip .fcard__title { font-size: clamp(26px, 3.2vw, 40px); }
.fcard--clip .fcard__truth { color: rgba(255,255,255,.72); }
.fcard--clip .fcard__truth b { color: #fff; }

/* --------------------------------------------------------- type: step */

/* The viewer's own accepted step, pinned first. Same decoration grammar as
   the quest card — plum stays decoration-only — but the ghost rung stands
   upright and alone: not an offer circling, a commitment already made. No
   celebration treatment anywhere on this card; it is a reminder, not a
   reward. */
.fcard--step::before {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(110% 85% at 16% 100%, rgba(142,44,110,.24), transparent 62%);
  pointer-events: none;
}
.fcard--step .step-rung {
  position: absolute; right: -6vh; top: -4vh;
  width: 58vh; height: 58vh;
  background: linear-gradient(180deg, var(--plum), var(--accent));
  clip-path: polygon(50% 0%, 100% 44%, 78% 44%, 78% 100%, 22% 100%, 22% 44%, 0% 44%);
  opacity: .1;
  pointer-events: none;
}

/* -------------------------------------------------------- type: quest */

/* Plum belongs to decoration only: a low glow and an oversized ghost of the
   brand rung, never behind text at reading contrast. */
.fcard--quest::before {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(110% 85% at 16% 100%, rgba(142,44,110,.30), transparent 62%),
    radial-gradient(70% 55% at 88% 0%, rgba(224,48,138,.10), transparent 60%);
  pointer-events: none;
}
.fcard--quest .ghost-rung {
  position: absolute; right: -12vh; top: -8vh;
  width: 66vh; height: 66vh;
  background: linear-gradient(180deg, var(--plum), var(--accent));
  clip-path: polygon(50% 0%, 100% 44%, 78% 44%, 78% 100%, 22% 100%, 22% 44%, 0% 44%);
  opacity: .12;
  transform: rotate(14deg);
  pointer-events: none;
}

/* ------------------------------------------------------- type: moment */

/* Concentric rings: a place known to a radius, not a pinpoint. Sized past
   the viewport so the radius wash reaches every corner of the frame. */
.fcard--moment::before {
  content: '';
  position: absolute; left: 50%; bottom: -58dvh;
  width: 200dvh; height: 200dvh;
  transform: translateX(-50%);
  border-radius: 50%;
  background: repeating-radial-gradient(circle,
    transparent 0 8.5dvh,
    rgba(236,74,156,.085) 8.5dvh calc(8.5dvh + 1.5px));
  -webkit-mask-image: radial-gradient(circle, rgba(0,0,0,.9), transparent 72%);
  mask-image: radial-gradient(circle, rgba(0,0,0,.9), transparent 72%);
  pointer-events: none;
}
.fcard--moment::after {
  /* the known point itself: a soft plum ground-glow under the text */
  content: '';
  position: absolute; left: 50%; bottom: -30dvh;
  width: 110dvh; height: 80dvh;
  transform: translateX(-50%);
  background: radial-gradient(closest-side, rgba(142,44,110,.22), transparent 70%);
  pointer-events: none;
}
.fcard--moment.noplace::after { display: none; }

/* The rings mean "a place, known to a radius" — a moment with no place
   recorded gets no rings, because decoration is not allowed to imply data. */
.fcard--moment.noplace::before { display: none; }

/* --------------------------------------------------------- type: rung */

/* Full-frame identity: the ladder itself, drawn at viewport scale. One
   oversized rung per real step climbs the empty upper frame along a rail;
   the steps this person has actually reached glow brighter. The decoration
   is the data, so the top half of the screen reads designed, not unpainted. */
.fcard--rung .rungscape {
  position: absolute; inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.fcard--rung .rungscape__rail {
  position: absolute;
  left: 14%; right: -8%;
  top: 36%;
  height: 2px;
  background: linear-gradient(90deg, transparent, rgba(142,44,110,.55) 30%, rgba(236,74,156,.5) 78%, transparent);
  transform: rotate(-25deg);
  transform-origin: center;
  opacity: .55;
}
.fcard--rung .bigrung {
  position: absolute;
  width: 21dvh; height: 21dvh;
  left: calc(30% + var(--i) * 19%);
  bottom: calc(36dvh + var(--i) * 19dvh);
  background: linear-gradient(180deg, var(--accent), var(--plum));
  clip-path: polygon(50% 0%, 100% 44%, 78% 44%, 78% 100%, 22% 100%, 22% 44%, 0% 44%);
  opacity: .07;
  transform: rotate(6deg);
}
.fcard--rung .bigrung.done { opacity: .17; }

.fcard--rung .ladder { margin-top: 2px; position: relative; z-index: 1; }
.fcard--rung .step { padding: 12px 0; }
.fcard--rung .step .what { font-weight: 500; font-size: 15.5px; }
.fcard--rung .step.todo .what { color: var(--muted); font-weight: 400; }
.fcard--rung .step .why {
  font-family: var(--mono); font-size: 12px; color: var(--text-mid); margin-top: 3px;
}

/* -------------------------------------------------------- type: event */

.fcard--event::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(155deg, rgba(142,44,110,.20), transparent 46%);
  pointer-events: none;
}
.fcard--event .lotus-edge { width: 88px; }

.roster { display: flex; flex-wrap: wrap; gap: 8px; }

/* --------------------------------------------------------- type: note */

/* The facilitator whispers where content speaks: centred, small, plain.
   Full-frame identity: concentric arcs enter from beyond the top and bottom
   edges and curve around the words — a ripple noticed from somewhere else,
   deliberately unlike the moment card's rings, which stand on their spot. */
.fcard--note::before { content: ''; }
.fcard--note::before,
.fcard--note .fcard__arc {
  position: absolute; left: 50%;
  width: 240dvh; height: 240dvh;
  transform: translateX(-50%);
  border-radius: 50%;
  background: repeating-radial-gradient(circle,
    transparent 0 10dvh,
    rgba(236,74,156,.14) 10dvh calc(10dvh + 2px));
  -webkit-mask-image: radial-gradient(circle, transparent 33%, rgba(0,0,0,.9) 46%, transparent 64%);
  mask-image: radial-gradient(circle, transparent 33%, rgba(0,0,0,.9) 46%, transparent 64%);
  pointer-events: none;
}
.fcard--note::before { top: -178dvh; }
.fcard--note .fcard__arc { bottom: -178dvh; }

.fcard--note .fcard__body {
  position: absolute; inset: 0;
  align-items: center;
  padding: 0 104px;
}
.fcard--note .fcard__col {
  max-width: 460px;
  align-items: center; text-align: center;
  gap: 22px;
}
.fcard--note .fcard__notetext {
  font-size: 20.5px; line-height: 1.6;
  color: var(--text-hi);
}
.fcard--note .lotus-edge { width: 64px; }
.fcard--note .fcard__eyebrow { justify-content: center; }

/* ---------------------------------------------------- right action rail */

.fcard__acts {
  position: absolute;
  right: 22px; bottom: 60px;
  display: flex; flex-direction: column; gap: 18px;
  align-items: center;
  z-index: 3;
}
.actwrap { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.actbtn {
  width: 52px; height: 52px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--glass-raised);
  backdrop-filter: blur(10px);
  color: var(--text);
  display: grid; place-items: center;
  cursor: pointer; padding: 0;
  position: relative;
  transition: transform var(--t), background var(--t), color var(--t);
}
.actbtn:hover { background: var(--glass-raised-hov); }
.actbtn:active { transform: scale(.9); }
.actbtn svg { width: 22px; height: 22px; }
.actbtn.on { color: var(--accent-text); border-color: var(--accent-line-soft); background: var(--accent-tint); }
.actbtn[aria-busy="true"] { pointer-events: none; }
.actbtn[aria-busy="true"] svg { visibility: hidden; }
.actbtn[aria-busy="true"]::after {
  content: '';
  position: absolute; inset: 0; margin: auto;
  width: 13px; height: 13px;
  background: var(--accent-text);
  clip-path: polygon(50% 0%, 100% 44%, 78% 44%, 78% 100%, 22% 100%, 22% 44%, 0% 44%);
  animation: climb .7s ease-in-out infinite;
}
.actlbl { font-size: 10.5px; color: var(--muted); letter-spacing: .02em; }

/* --------------------------------------------- left ladder-rail indicator */

.feed__rail {
  position: absolute;
  left: 20px; top: 50%;
  transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 8px;
  align-items: center;
  z-index: 3;
}
.feed__rail .tick {
  width: 16px; height: 12px;
  display: grid; place-items: center;
  background: transparent; border: 0; padding: 0;
  cursor: pointer;
}
.feed__rail .tick .bar {
  width: 10px; height: 2px;
  background: var(--faint);
  border-radius: 1px;
  transition: background var(--t), width var(--t);
}
.feed__rail .tick:hover .bar { background: var(--faint-strong); }
.feed__rail .tick.on .bar {
  width: 12px; height: 11px;
  background: var(--accent-text);
  clip-path: polygon(50% 0%, 100% 44%, 78% 44%, 78% 100%, 22% 100%, 22% 44%, 0% 44%);
  border-radius: 0;
}
.feed__count {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .08em;
  color: var(--faint-mid);
  margin-top: 8px;
  white-space: nowrap;
}

/* ------------------------------------------------------------ skeleton */

.fcard--skel .fcard__col > div { border-radius: var(--r-s); }

/* ------------------------------------------------------------- empty */

.fcard--empty .fcard__body { position: absolute; inset: 0; align-items: center; }
.fcard--empty .fcard__col { max-width: 420px; text-align: center; align-items: center; }

/* --------------------------------------------------------------- phone */

@media (max-width: 760px) {
  .feed, .fcard { height: 100dvh; }
  /* The bottom padding keeps the centred column optically clear of the tab bar. */
  .fcard__body { padding: 0 78px var(--nav-h) 40px; justify-content: flex-start; }
  .fcard__title { font-size: clamp(28px, 8.4vw, 38px); }
  .fcard--clip .vid-main { width: 100%; }
  .fcard__acts { right: 12px; bottom: calc(var(--nav-h) + 32px); gap: 14px; }
  .actbtn { width: 46px; height: 46px; }
  .feed__rail { left: 9px; gap: 6px; }
  /* The counter turns to read down the rail, so it never leaves the 16px
     column and never collides with card text. */
  .feed__count { font-size: 9.5px; margin-top: 6px; writing-mode: vertical-rl; }
  .fcard--note .fcard__body { padding: 0 56px; }
  .fcard--quest .ghost-rung { width: 34vh; height: 34vh; right: -8%; top: 6%; }
  .fcard--step .step-rung { width: 30vh; height: 30vh; right: -6%; top: 8%; }
  .fcard--rung .bigrung { width: 13dvh; height: 13dvh; left: calc(24% + var(--i) * 24%); bottom: calc(46dvh + var(--i) * 14dvh); }
  .fcard--rung .rungscape__rail { left: 8%; right: -8%; top: 36%; transform: rotate(-13deg); }
}

@media (prefers-reduced-motion: reduce) {
  .fcard__col { opacity: 1; transform: none; }
}
