/* Styles for the App page: playful hero, screen showcase, character, practice toy. */

/* The brand mark as a tintable shape — colour it with `color` on the element. */
.mark { display: block; aspect-ratio: 943 / 594; background: currentColor; -webkit-mask: url(/assets/merle-mark-transparent.png) center/contain no-repeat; mask: url(/assets/merle-mark-transparent.png) center/contain no-repeat; }
@keyframes bob { 0%, 100% { transform: translateY(0) rotate(var(--tilt, 0deg)); } 50% { transform: translateY(-16px) rotate(calc(var(--tilt, 0deg) + 5deg)); } }
@keyframes fadeUp { from { opacity: 0; transform: translateY(16px); } }

/* ---------- Full-screen hero, with pieces of the app floating in it ---------- */
.app-hero {
  position: relative;
  isolation: isolate;
  display: grid;
  place-items: center;
  overflow: hidden;
  min-height: 100svh;
  padding: 150px 24px 90px;
  background: var(--espresso);
  color: var(--parchment);
  text-align: center;
}
.app-hero-copy { position: relative; z-index: 2; max-width: 900px; }

.app-icon {
  display: block;
  width: clamp(92px, 11vw, 132px);
  height: auto;
  margin: 0 auto 28px;
  border-radius: 26%;
  box-shadow: 0 20px 44px rgba(0,0,0,.42);
}

/* Louder than the rest of the site on purpose: this is the page about the part
   children see. Heavier weight, tighter leading, and a size that runs right up
   to the edge of the column. */
.app-hero h1 {
  margin: 0 auto 26px;
  max-width: 15ch;
  font-size: clamp(42px, 7.2vw, 88px);
  font-weight: 600;
  letter-spacing: -.045em;
  line-height: .98;
}
.app-hero h1 em { color: var(--lime); font-style: normal; }
.app-hero .page-lede { margin: 0 auto 36px; max-width: 580px; color: rgba(245,241,232,.78); font-size: clamp(16px, 1.4vw, 19px); }

.store-buttons { display: flex; flex-wrap: wrap; gap: 13px; justify-content: center; }
.store-button {
  font-family: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 11px 21px 11px 17px;
  border: 1px solid rgba(245,241,232,.34);
  border-radius: 14px;
  background: rgba(245,241,232,.06);
  color: var(--parchment);
  text-align: left;
  transition: border-color .2s ease, background .2s ease, transform .2s ease;
}
.store-button:hover { border-color: var(--lime); background: rgba(200,255,76,.12); transform: translateY(-2px); }
.app-page .toast { left: 50%; right: auto; bottom: 32px; min-width: 220px; max-width: calc(100% - 40px); padding: 18px 28px; border: 1px solid rgba(245,241,232,.25); border-radius: 999px; background: var(--nav-green); color: var(--parchment); text-align: center; font-size: 17px; transform: translate(-50%, 12px); }
.app-page .toast.show { transform: translate(-50%, 0); }
.store-button img { width: 25px; height: 25px; object-fit: contain; }
/* The Apple glyph ships as solid black, which disappears on the brown hero, so
   it is drawn as a mask in the button's own colour. The Play glyph is
   multi-coloured and stays an image. */
.store-glyph {
  width: 23px;
  height: 23px;
  background: currentColor;
  -webkit-mask: url(/assets/app/store-apple.png) center/contain no-repeat;
  mask: url(/assets/app/store-apple.png) center/contain no-repeat;
}
.store-button span { display: grid; }
.store-button small { font-size: 11px; letter-spacing: .04em; opacity: .74; }
.store-button strong { font-size: 17px; font-weight: 500; letter-spacing: -.02em; }

/* Game pieces drift behind the copy. They are decorative, so they are hidden
   from assistive technology and sit under a readable gap in the middle. */
.hero-floats { position: absolute; z-index: 1; inset: 0; pointer-events: none; }
/* Each piece waits out of sight until the cursor comes near, then fades back
   out on its own. `.is-near` is added by the pointer handler; the scale keeps
   the arrival from feeling like a hard cut. */
.hero-float {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  transform: translate(-50%, -50%) rotate(var(--tilt)) scale(.78);
  filter: drop-shadow(0 16px 26px rgba(0,0,0,.34));
  opacity: 0;
  transition: opacity 1.1s ease, transform 1.1s cubic-bezier(.2,.8,.2,1);
}
.hero-float.is-near {
  opacity: 1;
  transform: translate(-50%, -50%) rotate(var(--tilt)) scale(1);
  transition: opacity .28s ease, transform .42s cubic-bezier(.2,.8,.2,1);
  animation: heroDrift var(--dur) ease-in-out var(--delay, 0s) infinite;
}

/* Without a pointer to move there is nothing to reveal them with, so on touch
   screens they simply stay visible and drift. */
@media (hover: none), (pointer: coarse) {
  .hero-float { opacity: 1; transform: translate(-50%, -50%) rotate(var(--tilt)); animation: heroDrift var(--dur) ease-in-out var(--delay, 0s) infinite; }
}
@keyframes heroDrift {
  0%, 100% { transform: translate(-50%, -50%) rotate(var(--tilt)); }
  50%      { transform: translate(-50%, calc(-50% - 22px)) rotate(calc(var(--tilt) * -1)); }
}

/* Nothing here is load-bearing, so motion-sensitive visitors get the same
   layout without the drift, and every step's copy at full strength. */
@media (prefers-reduced-motion: reduce) {
  .hero-float { animation: none; }
  .flow-card { opacity: 1; transform: none; }
  .phone-frame, .world { transition: none; }
}

/* Over the brown hero the header has to invert, the same way the therapists
   page inverts over its green one. The wordmark is an opaque PNG, so it is
   redrawn as a mask tinted with `currentColor` rather than swapped for a second
   file. Only the unscrolled state is touched: once the header condenses into
   its pill it travels over pale sections too, and the site default already
   handles that. */
.hero-brown .site-header:not(.scrolled) { color: var(--lime); }
.hero-brown .site-header:not(.scrolled) .scroll-tagline { color: rgba(245,241,232,.6); }
.hero-brown .site-header:not(.scrolled) .nav-link,
.hero-brown .site-header:not(.scrolled) .text-link { color: rgba(245,241,232,.86); }
.hero-brown .site-header:not(.scrolled) .nav-link:hover,
.hero-brown .site-header:not(.scrolled) .text-link:hover { color: var(--lime); }
.hero-brown .site-header:not(.scrolled) .button-light { border-color: rgba(245,241,232,.5); color: var(--parchment); }
.hero-brown .site-header:not(.scrolled) .button-light:hover { border-color: var(--parchment); background: var(--parchment); color: var(--espresso); }
.hero-brown .site-header:not(.scrolled) .button-dark { border-color: var(--lime); background: var(--lime); color: var(--espresso); }
.hero-brown .site-header:not(.scrolled) .button-dark:hover { border-color: var(--lime); background: transparent; color: var(--lime); }
.hero-brown .site-header:not(.scrolled) .mobile-menu-toggle span { background: var(--lime); }

.hero-brown .site-header:not(.scrolled) .brand-crop { position: relative; }
.hero-brown .site-header:not(.scrolled) .brand-crop img { visibility: hidden; }
.hero-brown .site-header:not(.scrolled) .brand-crop::after { content: ""; position: absolute; inset: 0; background: currentColor; -webkit-mask: var(--brand-art) center/contain no-repeat; mask: var(--brand-art) center/contain no-repeat; }
.hero-brown .site-header:not(.scrolled) .brand-wordmark { --brand-art: url(/assets/merle-wordmark-transparent.png); }
.hero-brown .site-header:not(.scrolled) .brand-mark { --brand-art: url(/assets/merle-mark-transparent.png); }

/* ---------- The round, screen by screen: the phone holds still ---------- */
.flow { position: relative; background: var(--paper); padding: 0 24px; }
/* The rows are declared rather than left implicit: `grid-row: 1 / -1` on the
   phone counts -1 from the end of the EXPLICIT grid, so without these the phone
   would span a single row and stop sticking after the first step. */
.flow-grid {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  grid-template-rows: repeat(6, auto);
  gap: 0 clamp(28px, 5vw, 78px);
  max-width: 1240px;
  margin: 0 auto;
}

/* The phone spans every row and sticks, so only the picture inside it changes. */
.flow-phone {
  grid-column: 2;
  grid-row: 1 / -1;
  position: sticky;
  top: 0;
  display: grid;
  place-items: center;
  height: 100svh;
}

.phone {
  position: relative;
  width: min(338px, 70vw, calc(40svh + 11px));
  padding: 11px;
  border-radius: 46px;
  background: #15140f;
  box-shadow: 0 34px 70px rgba(32,24,18,.38), inset 0 0 0 1px rgba(255,255,255,.12);
}
.phone-notch {
  position: absolute;
  z-index: 2;
  top: 20px;
  left: 50%;
  width: 88px;
  height: 20px;
  transform: translateX(-50%);
  border-radius: 999px;
  background: #15140f;
}
/* A fixed 430 x 860 window, the same shape the captures were taken at, so the
   screen is filled edge to edge rather than letterboxed inside the frame. */
.phone-screen {
  position: relative;
  overflow: hidden;
  aspect-ratio: 430 / 860;
  border-radius: 36px;
  background: #fff;
}
.phone-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .5s ease;
}
.phone-frame.is-active { opacity: 1; }

/* `display: contents` lets each step sit directly in .flow-grid, so a step can
   take column 1 or column 3 and alternate around the phone. The list roles are
   written on the markup because this display value drops them otherwise. */
.flow-steps { display: contents; }
.flow-step {
  display: grid;
  align-items: center;
  min-height: 100svh;
  padding: 40px 0;
}
/* One step per row, alternating the side it sits on. Rows are explicit because
   auto-placement would otherwise pair a left and a right step into one row. */
.flow-step:nth-child(1) { grid-row: 1; grid-column: 1; }
.flow-step:nth-child(2) { grid-row: 2; grid-column: 3; }
.flow-step:nth-child(3) { grid-row: 3; grid-column: 1; }
.flow-step:nth-child(4) { grid-row: 4; grid-column: 3; }
.flow-step:nth-child(5) { grid-row: 5; grid-column: 1; }
.flow-step:nth-child(6) { grid-row: 6; grid-column: 3; }

.flow-card { max-width: 400px; opacity: .32; transform: translateY(14px); transition: opacity .45s ease, transform .45s ease; }
.flow-step:nth-child(even) .flow-card { margin-left: auto; }
.flow-card.is-current { opacity: 1; transform: none; }
.flow-num { margin: 0 0 14px; color: var(--accent-dark); font-family: var(--mono); font-size: 12px; letter-spacing: .14em; }
.flow-card h2 { margin: 0 0 14px; font-family: var(--serif); font-size: clamp(27px, 3vw, 37px); font-weight: 350; letter-spacing: -.045em; line-height: 1.1; }
.flow-card p { margin: 0; color: #4b4945; font-size: 17px; line-height: 1.55; }

/* ---------- Full-bleed worlds that fade into one another ---------- */
/* Three worlds, each worth one screen of scrolling. A sticky element can only
   stay pinned for (container height - its own height), so the container is four
   screens tall to buy three screens of pinning. */
.worlds { position: relative; height: 400svh; }
.worlds-stage { position: sticky; top: 0; overflow: hidden; height: 100svh; }
.world { position: absolute; inset: 0; margin: 0; opacity: 0; transition: opacity .8s ease; }
.world.is-active { opacity: 1; }
.world > picture { display: block; width: 100%; height: 100%; }
.world img { width: 100%; height: 100%; object-fit: cover; }

/* A vignette on the side the words sit on, so the copy always has something
   dark to sit against whatever the artwork is doing underneath. */
.world::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(18,14,10,.6), transparent 42%),
    radial-gradient(130% 100% at 50% 50%, transparent 38%, rgba(18,14,10,.72));
  pointer-events: none;
}
.world-copy::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -34px -40px -30px;
  border-radius: 40px;
  background: radial-gradient(70% 78% at 50% 55%, rgba(14,11,8,.68), transparent 72%);
}
.world-copy {
  position: absolute;
  isolation: isolate;
  z-index: 2;
  bottom: clamp(60px, 11vh, 130px);
  width: min(430px, calc(100% - 2 * clamp(24px, 6vw, 88px)));
  color: var(--parchment);
}
.world-left  { left: clamp(24px, 6vw, 88px); }
.world-right { right: clamp(24px, 6vw, 88px); text-align: right; }
.world-copy .eyebrow { margin-bottom: 16px; color: var(--lime); }
.world-copy h2 { margin: 0 0 14px; font-family: var(--serif); font-size: clamp(32px, 4.4vw, 54px); font-weight: 350; letter-spacing: -.05em; line-height: 1.05; }
.world-copy h2 em { color: var(--lime); font-style: italic; }
.world-copy p { margin: 0; color: rgba(245,241,232,.82); font-size: 17px; line-height: 1.55; }

/* The triggers are laid over the pinned region rather than stacked after it, so
   each world's turn lands while the stage is still held in place. */
.world-trigger { position: absolute; left: 0; width: 1px; height: 100svh; pointer-events: none; }
/* Keyed on the data attribute, not nth-of-type: the sticky stage is a div too,
   so counting by type would shift every trigger down by one. */
.world-trigger[data-world="0"] { top: 0; }
.world-trigger[data-world="1"] { top: 100svh; }
.world-trigger[data-world="2"] { top: 200svh; }

/* ---------- Meet the character ---------- */
.char-band { display: grid; grid-template-columns: 1.1fr .9fr; gap: clamp(40px, 7vw, 100px); align-items: center; padding-top: 130px; padding-bottom: 130px; background: var(--paper-deep); }
.char-stage { display: grid; place-items: center; min-height: 420px; padding: 40px; border-radius: 30px; background: linear-gradient(150deg, #dcd8ce, #b9977d 58%, #2b3c2d); box-shadow: 0 26px 60px rgba(60,56,46,.18); }
.char-stage .mark { width: min(330px, 72%); color: var(--parchment); animation: bob 5s ease-in-out infinite; transition: color .4s ease; }
.char-copy p:not(.eyebrow) { max-width: 460px; color: #4b4945; font-size: 18px; line-height: 1.55; }
.char-swatches { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 28px; }
.char-swatch { width: 36px; height: 36px; padding: 0; border: 2px solid transparent; border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(21,21,21,.14); cursor: pointer; transition: transform .2s ease; }
.char-swatch:hover { transform: translateY(-3px); }
.char-swatch.active { border-color: var(--ink); }

/* ---------- The steps, as plain white tiles ---------- */
.fun-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; max-width: 1180px; margin: 0 auto; padding-bottom: 130px; }
.fun-card {
  display: grid;
  align-content: start;
  padding: 36px 38px 40px;
  border: 1px solid var(--line);
  border-radius: 22px;
  background: #fff;
}
.fun-card.wide { grid-column: span 2; }
.fun-num {
  margin-bottom: 10px;
  color: var(--ink);
  font-family: var(--serif);
  font-size: clamp(26px, 2.6vw, 35px);
  font-weight: 400;
  letter-spacing: -.045em;
  line-height: 1;
}
.fun-card h3 {
  margin: 0 0 14px;
  font-family: var(--serif);
  font-size: clamp(26px, 2.6vw, 35px);
  font-weight: 400;
  letter-spacing: -.045em;
  line-height: 1.08;
}
.fun-card p { margin: 0; color: #4b4945; font-size: 16px; line-height: 1.6; }

/* ---------- Practice toy ---------- */
.toy-section { display: grid; grid-template-columns: .88fr 1.12fr; gap: clamp(40px, 7vw, 100px); align-items: center; padding-bottom: 140px; }
.toy-copy p:not(.eyebrow) { max-width: 440px; color: #4b4945; font-size: 18px; line-height: 1.55; }
.toy { padding: 38px 34px 34px; border-radius: 28px; background: var(--nav-green); color: var(--parchment); text-align: center; box-shadow: 0 26px 60px rgba(30,42,32,.22); }
.toy-kicker { color: rgba(245,241,232,.55); font-family: var(--mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; }
.toy-word { margin: 22px 0 12px; font-family: var(--serif); font-size: clamp(46px, 7vw, 84px); font-weight: 350; line-height: 1.04; letter-spacing: -.05em; animation: fadeUp .4s cubic-bezier(.2,.8,.2,1) both; }
.toy-meta { color: rgba(245,241,232,.6); font-size: 13px; }
.toy-dots { display: flex; gap: 8px; justify-content: center; margin: 28px 0 26px; }
.toy-dot { width: 11px; height: 11px; border-radius: 50%; background: rgba(245,241,232,.22); transition: background .25s ease, transform .25s ease; }
.toy-dot.done { background: var(--lime); transform: scale(1.18); }
.toy-actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.toy .button-light { border-color: rgba(245,241,232,.45); color: var(--parchment); }
.toy .button-light:hover { border-color: var(--parchment); background: var(--parchment); color: var(--nav-green); }
.toy-progress { margin-top: 24px; color: rgba(245,241,232,.5); font-family: var(--mono); font-size: 11px; letter-spacing: .08em; }

@media (max-width: 980px) {
  .char-band, .toy-section { grid-template-columns: 1fr; }
  .flow-card { max-width: 330px; }
  .char-stage { order: -1; min-height: 340px; }
  .fun-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fun-card.wide { grid-column: span 2; }
}

/* Narrow: a plain block column. The phone is sticky against the whole section
   rather than a grid row, so it stays pinned at the top while the steps scroll
   up underneath it — the grid-row trick above only works with two columns. */
@media (max-width: 860px) {
  .flow-grid { display: block; }
  .flow-phone {
    position: sticky;
    top: 86px; /* clears the floating header pill */
    z-index: 3;
    height: auto;
    padding: 14px 0 16px;
    background: var(--paper);
  }
  .phone { width: min(190px, 46vw); padding: 7px; border-radius: 30px; }
  .phone-notch { top: 13px; width: 56px; height: 13px; }
  .phone-screen { border-radius: 24px; }
  .flow-step { min-height: 62svh; padding: 20px 0; }
  .flow-card, .flow-step:nth-child(even) .flow-card { max-width: none; margin: 0; }
  .world-copy, .world-right { width: calc(100% - 2 * clamp(20px, 6vw, 40px)); left: clamp(20px, 6vw, 40px); right: auto; text-align: left; }
}

/* Enhanced round: all six messages share a pinned stage. The section supplies
   the scroll distance; only the active message and phone screen are visible. */
.flow.is-pinned { height: calc(100svh + var(--flow-scroll-distance)); }
.flow.is-pinned .flow-grid {
  position: sticky;
  top: 0;
  height: 100svh;
  grid-template-rows: minmax(0, 1fr);
}
.flow.is-pinned .flow-phone { position: static; grid-row: 1; height: 100%; }
.flow.is-pinned .flow-step { grid-row: 1; min-height: 0; height: 100%; padding: 0; pointer-events: none; }
.flow.is-pinned .flow-card { opacity: 0; transform: translateY(18px); }
.flow.is-pinned .flow-card.is-current { opacity: 1; transform: none; pointer-events: auto; }

@media (max-width: 860px) {
  .flow.is-pinned .flow-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
    gap: 24px;
    padding: 100px 0 32px;
  }
  .flow.is-pinned .flow-phone { grid-column: 1; min-height: 0; padding: 0; }
  .flow.is-pinned .phone { width: auto; height: min(100%, 390px); aspect-ratio: 190 / 366; }
  .flow.is-pinned .phone-screen { height: 100%; aspect-ratio: auto; }
  .flow.is-pinned .flow-step { grid-column: 1; grid-row: 2; }
  .flow.is-pinned .flow-card { width: 100%; max-width: 520px; margin: 0 auto; }
  .flow.is-pinned .flow-card p { font-size: 16px; }
}

@media (max-width: 860px) and (max-height: 560px) {
  .flow.is-pinned .flow-grid {
    grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
    grid-template-rows: minmax(0, 1fr);
    padding-top: 90px;
    padding-bottom: 20px;
  }
  .flow.is-pinned .flow-step { grid-column: 2; grid-row: 1; }
  .flow.is-pinned .flow-card h2 { font-size: 27px; }
  .flow.is-pinned .flow-card p { font-size: 15px; }
}

@media (prefers-reduced-motion: reduce) {
  .flow.is-pinned .flow-card { transform: none; transition: none; }
}

@media (max-width: 720px) {
  .app-hero { min-height: 92svh; padding-top: 120px; padding-bottom: 70px; }
  .hero-float { width: calc(var(--w) * .62); }
  /* On one column the copy runs the full width, so the pieces that sit level
     with it would land on the words. Only the top and bottom ones survive. */
  .hero-float-mid { display: none; }
  .char-band { padding-top: 85px; padding-bottom: 85px; }
  .char-stage { min-height: 260px; padding: 26px; border-radius: 22px; }
  .fun-grid { grid-template-columns: 1fr; padding-bottom: 85px; }
  .fun-card { padding: 28px 26px 30px; }
  .fun-card.wide { grid-column: span 1; }
  .toy-section { padding-bottom: 90px; }
  .toy { padding: 28px 22px 26px; border-radius: 22px; }
}
