/*
 * Homepage sections.
 *
 * Every element here is styled in its FINAL state. GSAP animates from an
 * offset toward these values, so visitors with reduced motion, with JS off,
 * or on a slow connection see the complete page — never a blank one waiting
 * for a script. Nothing below may hardcode a color: read tokens.css.
 */

/* ---------------------------------------------------------------------------
 * Shared section rhythm
 * ------------------------------------------------------------------------ */

.home-section {
  display: block;
  padding-block: var(--jw-section-gap);
  border-top: 1px solid var(--jw-line-faint);
}

/* Half the page on desktop so headlines break into a poster block; full
   width below the tablet breakpoint, where half a column is unreadable. */
.section-head {
  max-width: 50%;
  margin-bottom: var(--jw-space-12);
}

.section-head h2 {
  font-size: var(--jw-text-headline);
  line-height: var(--jw-leading-tight);
  letter-spacing: var(--jw-tracking-tight);
}

/* ---------------------------------------------------------------------------
 * 01 · Hero
 * ------------------------------------------------------------------------ */

/* The hero is exactly one viewport tall, less the fixed bar, and its content
   is centred in what is left. The device is allowed to run past the bottom
   edge and is cut off there rather than being shrunk to fit. */
/* Exactly one fold: the space between the fixed bar and the bottom of the
   viewport. A fixed height, not a minimum, so the device column is bounded -
   that is what both clips the device and leaves the controls their row. */
.home-hero {
  position: relative;
  height: calc(100svh - var(--jw-topbar-height));
  display: grid;
}

.home-grid {
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(320px, 0.84fr) minmax(300px, 0.58fr);
  gap: clamp(22px, 5vw, 72px);
  /* Stretch, not centre: the device column needs the full fold height so it
     can be cut off at the bottom edge. The copy centres itself below. */
  align-items: stretch;
  padding-top: var(--jw-space-6);
}

/* Centred in the fold, independently of how tall the device column is. */
.hero {
  min-width: 0;
  align-self: center;
  display: grid;
  align-content: center;
  gap: var(--jw-space-5);
  padding-bottom: var(--jw-space-10);
}

.hero-copy {
  display: grid;
  gap: 0;
}

.hero h1 {
  max-width: 15ch;
  font-size: clamp(2.1rem, min(6.2vw, 8.4svh), 5rem);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--jw-space-3);
  align-items: center;
}

/* GSAP owns transform on pressable buttons; keep it out of the transition. */
.hero-actions .button {
  min-height: 50px;
  padding: 0 var(--jw-space-6);
  font-size: var(--jw-text-base);
}

/* ---------------------------------------------------------------------------
 * 02 · Marquee
 *
 * Breaks the shell to full viewport width. The track is duplicated in the
 * markup so the -50% translation loops seamlessly.
 * ------------------------------------------------------------------------ */

.marquee {
  margin-inline: calc(50% - 50vw);
  padding-block: var(--jw-space-5);
  border-block: 1px solid var(--jw-line-faint);
  background: var(--jw-surface-veil);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}

.marquee-track {
  display: flex;
  align-items: center;
  gap: var(--jw-space-6);
  width: max-content;
  color: var(--jw-text-muted);
  font-size: clamp(1rem, 2vw, 1.5rem);
  font-weight: var(--jw-weight-bold);
  white-space: nowrap;
  animation: marquee-drift 38s linear infinite;
}

.marquee-track i {
  color: var(--jw-accent);
  font-style: normal;
}

@keyframes marquee-drift {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-50%, 0, 0); }
}

/* ---------------------------------------------------------------------------
 * 03 · Steps
 * ------------------------------------------------------------------------ */

.step-list {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
}

.step {
  display: grid;
  grid-template-columns: minmax(0, 7rem) minmax(0, 1fr) minmax(0, 1.4fr);
  gap: var(--jw-space-6);
  align-items: start;
  /* Breathes equally above and below each rule; the list closes without one -
     the ownership section below opens rule-free. */
  padding-block: var(--jw-space-10);
  border-top: 1px solid var(--jw-line);
}

/* The ownership statement stands on whitespace alone. */
.feature-section { border-top: 0; }

.step-index {
  color: var(--jw-accent);
  font-size: clamp(2rem, 4vw, 3.2rem);
  font-weight: var(--jw-weight-black);
  line-height: 0.9;
  letter-spacing: var(--jw-tracking-tight);
}

.step h3 {
  font-size: clamp(1.5rem, 2.6vw, 2.1rem);
  line-height: var(--jw-leading-tight);
}

.step p {
  max-width: 46ch;
  color: var(--jw-text-body);
  font-size: var(--jw-text-lg);
  line-height: var(--jw-leading-normal);
}

/* ---------------------------------------------------------------------------
 * 04 · Features
 * ------------------------------------------------------------------------ */

/* Editorial rather than boxed: three columns, each card opening with a
   hairline rule that takes the accent on hover. No shadows, no card chrome -
   the type and the spacing do the work. */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--jw-space-8) var(--jw-space-8);
}

.feature-card {
  display: grid;
  align-content: start;
  gap: var(--jw-space-3);
  padding: var(--jw-space-6) 0 0;
  border-top: 1px solid var(--jw-line-strong);
  transition: border-color var(--jw-duration-slow) var(--jw-ease-out);
}

.feature-card:hover { border-top-color: var(--jw-accent); }

.feature-card h3 { font-size: clamp(1.25rem, 1.8vw, 1.5rem); }

.feature-card p {
  max-width: 38ch;
  color: var(--jw-text-body);
  line-height: var(--jw-leading-normal);
}

/* Drawn icons, filled in the accent — never emoji, which ignore the brand
   and render differently on every platform. */
.feature-icon {
  display: block;
  width: 26px;
  height: 26px;
  color: var(--jw-accent);
}

.feature-icon svg {
  width: 100%;
  height: 100%;
  fill: currentColor;
}

/* ---------------------------------------------------------------------------
 * 05 · Showcase
 * ------------------------------------------------------------------------ */

.showcase-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--jw-space-4);
}

.showcase-item {
  position: relative;
  grid-column: span 2;
  margin: 0;
  border: 1px solid var(--jw-card-border);
  border-radius: var(--jw-radius-lg);
  background: var(--jw-surface-sunken);
  overflow: hidden;
}

.showcase-item.wide { grid-column: span 3; }

.showcase-item img {
  width: 100%;
  height: clamp(220px, 26vw, 340px);
  display: block;
  object-fit: cover;
  object-position: top center;
  transition: transform var(--jw-duration-slower) var(--jw-ease-out);
}

.showcase-item:hover img { transform: scale(1.035); }

.showcase-item figcaption {
  position: absolute;
  inset: auto 0 0 0;
  display: grid;
  gap: 2px;
  padding: var(--jw-space-6) var(--jw-space-4) var(--jw-space-4);
  background: linear-gradient(180deg, transparent, rgba(6, 10, 9, 0.82));
  color: var(--jw-neutral-0);
}

.showcase-item figcaption strong {
  font-size: var(--jw-text-lg);
  font-weight: var(--jw-weight-bold);
}

.showcase-item figcaption span {
  color: rgba(255, 255, 255, 0.76);
  font-size: var(--jw-text-sm);
}

/* ---------------------------------------------------------------------------
 * 06 · Ownership statement
 *
 * The headline reads as faint text that fills with ink as it scrolls past.
 * The fill is a background-clip gradient driven by --fill (0 to 1); with no
 * JS the fallback below leaves it fully inked and legible.
 * ------------------------------------------------------------------------ */

.statement-section { text-align: left; }

.statement {
  --fill: 1;
  max-width: 18ch;
  margin-bottom: var(--jw-space-10);
  font-size: var(--jw-text-display);
  line-height: var(--jw-leading-tight);
  letter-spacing: var(--jw-tracking-tight);
  background-image: linear-gradient(
    90deg,
    var(--jw-text-primary) calc(var(--fill) * 100%),
    var(--jw-text-subtle) calc(var(--fill) * 100%)
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.statement-detail {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--jw-space-8);
  max-width: 900px;
}

.statement-detail p {
  color: var(--jw-text-body);
  font-size: var(--jw-text-lg);
  line-height: var(--jw-leading-relaxed);
}

/* ---------------------------------------------------------------------------
 * 07 · Closing CTA
 * ------------------------------------------------------------------------ */

.cta-section { border-top: 0; }

.cta-card {
  display: grid;
  justify-items: start;
  gap: var(--jw-space-4);
  padding: clamp(32px, 6vw, 72px);
  border: 1px solid var(--jw-card-border);
  border-radius: var(--jw-radius-xl);
  background:
    radial-gradient(circle at 8% 0%, var(--jw-accent-soft), transparent 46%),
    radial-gradient(circle at 92% 100%, var(--jw-highlight-soft), transparent 46%),
    var(--jw-card-bg);
  box-shadow: var(--jw-shadow-lg);
}

.cta-card h2 {
  max-width: 16ch;
  font-size: var(--jw-text-headline);
  line-height: var(--jw-leading-tight);
  letter-spacing: var(--jw-tracking-tight);
}

.cta-card .lead { margin-top: 0; }

/* Full-width stacked actions, at every size. */
.cta-card .hero-actions {
  width: 100%;
  flex-direction: column;
  align-items: stretch;
}

.cta-card .hero-actions .button { width: 100%; }

/* ---------------------------------------------------------------------------
 * 08 · Footer
 * ------------------------------------------------------------------------ */

.site-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--jw-space-6);
  padding-block: var(--jw-space-10);
  border-top: 1px solid var(--jw-line);
}

.footer-brand {
  display: flex;
  align-items: center;
  gap: var(--jw-space-3);
}

.footer-brand strong {
  display: block;
  color: var(--jw-text-primary);
  font-weight: var(--jw-weight-black);
}

.footer-brand span {
  max-width: 42ch;
  color: var(--jw-text-muted);
  font-size: var(--jw-text-sm);
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--jw-space-5);
}

.footer-links a {
  color: var(--jw-text-muted);
  font-size: var(--jw-text-sm);
  font-weight: var(--jw-weight-bold);
  transition: color var(--jw-duration-base) var(--jw-ease-out);
}

.footer-links a:hover { color: var(--jw-text-primary); }

/* ---------------------------------------------------------------------------
 * Responsive
 * ------------------------------------------------------------------------ */

@media (max-width: 980px) {
  .section-head { max-width: 100%; }
  .step {
    grid-template-columns: minmax(0, 4rem) minmax(0, 1fr);
    gap: var(--jw-space-4);
  }
  .step p { grid-column: 2; }
  .feature-grid { grid-template-columns: 1fr; }
  .showcase-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .showcase-item, .showcase-item.wide { grid-column: span 1; }
}

@media (max-width: 640px) {
  .hero { min-height: auto; }
  /* Side by side in the hero; the lead goes: the phone needs the room. */
  .hero .hero-actions { flex-wrap: nowrap; }
  .hero .hero-actions .button { flex: 1 1 0; width: auto; }
  .hero .lead { display: none; }

  .showcase-grid { grid-template-columns: 1fr; }
  .site-footer { flex-direction: column; align-items: flex-start; }
}

/* Reduced motion: the marquee is decorative, so it simply stops. */
@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation: none; }
}

/* ---------------------------------------------------------------------------
 * Hero device
 *
 * The frame itself comes from device.css (generated from devices.css, MIT).
 * That stylesheet draws the iPhone at its true 428x868 size, so everything
 * here is sizing, placement and the bits of finish the site adds on top.
 *
 * The resting three-quarter angle lives in CSS, so the device is already
 * presented correctly with JS off. GSAP only animates away from it.
 * ------------------------------------------------------------------------ */

.phone-stage {
  /* The frame is authored at 428x868; scale sets the rendered size. */
  --device-scale: 0.98;
  /* Chassis thickness, in the device's own 428-wide coordinate space. */
  --device-depth: 48px;
  --phone-width: calc(428px * var(--device-scale));
  --phone-height: calc(868px * var(--device-scale));
  /* The device RESTS flat to the display; the three-quarter angle exists
     only inside the entrance swing, in home-motion.js. */
  --phone-tilt-y: 0deg;
  --phone-tilt-x: 0deg;
  --phone-tilt-z: 0deg;

  min-height: 0;
  align-self: stretch;
  display: grid;
  /* The device takes what is left; the controls and hint always keep theirs. */
  grid-template-rows: minmax(0, 1fr) max-content max-content;
  justify-items: center;
  gap: var(--jw-space-4);
  padding-bottom: var(--jw-space-5);
}

.phone-stage:focus-visible {
  outline: 2px solid var(--jw-field-border-focus);
  outline-offset: var(--jw-space-4);
  border-radius: var(--jw-radius-lg);
}

/* Clips the device where it runs past the hero. Only the bottom edge is cut:
   a plain `overflow: clip` would also crop the device's ambient shadow and
   leave a visible rectangle, so the clip is opened out on the other three
   sides. Carries the perspective too, being the direct parent of .phone. */
.phone-viewport {
  width: 100%;
  min-height: 0;
  display: grid;
  justify-items: center;
  align-items: start;
  clip-path: inset(-60% -60% 0 -60%);
  /* Short enough to give real foreshortening: at 1700px the device read as a
     flat rectangle that happened to be rotated. */
  perspective: 1150px;
  perspective-origin: 62% 42%;
}

/* GSAP owns this element's transform. It is sized to the scaled device so it
   never widens the column. */
/*
 * GSAP owns this element's transform.
 *
 * It must NOT carry `filter`, `opacity` below 1, or `overflow`: every one of
 * those flattens a preserve-3d context, which collapses the side wall into
 * the face and is exactly why the device used to read as a flat picture. The
 * shadow lives on the back plate instead.
 */
.phone {
  position: relative;
  width: var(--phone-width);
  height: var(--phone-height);
  transform-style: preserve-3d;
  transform:
    rotateY(var(--phone-tilt-y))
    rotateX(var(--phone-tilt-x))
    rotateZ(var(--phone-tilt-z));
}

/*
 * The device is a real slab in 3D space, not a rotated picture of one.
 *
 * ONE wrapper carries the scale, and the three surfaces sit inside it in the
 * frame's own 428x868 coordinates: the glass face at z=0, a side wall standing
 * perpendicular at the right edge, and a back plate behind. Scaling the
 * wrapper rather than each surface is what keeps them a single object -
 * previously they scaled about different origins and the rail drifted off the
 * body.
 */
.phone-slab {
  position: absolute;
  top: 0;
  left: 50%;
  width: 428px;
  height: 868px;
  margin-left: -214px;
  transform: scale(var(--device-scale));
  transform-origin: top center;
  transform-style: preserve-3d;
}

.phone-slab > * {
  position: absolute;
  top: 0;
  left: 0;
}

.phone-slab .device {
  width: 428px;
  height: 868px;
  transform-style: preserve-3d;
}

/*
 * The side wall gives the device its thickness. Inset from top and bottom so
 * it stays within the straight part of the chassis: a full-height rectangle
 * overhangs the 68px corner radius and reads as a bar stuck to the phone.
 */
.phone-edge {
  top: 62px;
  left: auto;
  right: 0;
  width: var(--device-depth);
  height: calc(868px - 124px);
  border-radius: 3px;
  background: linear-gradient(
    180deg,
    #101012 0%,
    #3b3c40 7%,
    #1d1e21 24%,
    #47484c 47%,
    #161719 68%,
    #333438 87%,
    #0c0c0e 100%
  );
  transform: rotateY(-90deg);
  transform-origin: right center;
}

/* The back plate closes the slab so no light leaks through the body. It also
   carries the shadow, since .phone cannot take a filter. */
.phone-back {
  width: 428px;
  height: 868px;
  border-radius: 68px;
  background: linear-gradient(150deg, #202024 0%, #0e0e10 46%, #19191d 100%);
  box-shadow: var(--jw-device-shadow);
  transform: translateZ(calc(var(--device-depth) * -1));
}

/* Directional light: the near edge catches the room, the far edge falls off.
   Sits above the screen so it reads as glass rather than as a layer. */
.phone-glare::after {
  content: "";
  position: absolute;
  inset: -19px;
  border-radius: 68px;
  background: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0.1) 0%,
    transparent 26%,
    transparent 74%,
    rgba(0, 0, 0, 0.22) 100%
  );
  pointer-events: none;
}

/* No sheen on the glass: any gradient over the screen reads as a dirty
   display next to real page content. The element stays for layout only. */
.phone-glare { display: none; }

.phone-stage .device-screen {
  position: relative;
  display: flex;
  flex-direction: column;
  /* An iOS status bar owns the top of the glass, so the page inside never
     runs underneath the island the way no real site ever would. The island
     spans 10-45px of the screen; the 62px zone lets it float with air below,
     and the time and glyphs centre on the island's own axis. */
  padding-top: 62px;
  /* The status band stays black; below it the in-between ground is the light
     page tone, so the island and glyphs keep their contrast while slides
     swap, and pages fade over a plausible loading ground. */
  background: linear-gradient(180deg, var(--jw-black) 0 62px, var(--jw-white) 62px);
  overflow: hidden;
}

.phone-stage .device-screen::before {
  content: "9:41";
  position: absolute;
  top: 10px;
  left: 0;
  right: 0;
  height: 35px;
  z-index: 6;
  display: flex;
  align-items: center;
  padding-left: 46px;
  color: var(--jw-white);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.01em;
  pointer-events: none;
}

.phone-stage .device-screen .status-icons {
  position: absolute;
  top: 10px;
  right: 36px;
  width: 60px;
  height: 35px;
  z-index: 6;
  display: grid;
  place-items: center;
  color: var(--jw-white);
  pointer-events: none;
}

.phone-stage .device-screen .status-icons svg {
  width: 60px;
  height: 12px;
  display: block;
}

/* Upstream devices.css finishes the frame in deep purple. Natural titanium is
   both closer to the current Pro line and quieter behind the screenshot. */
.phone-stage .device-iphone-14-pro .device-frame {
  border-color: #26272b;
  box-shadow:
    inset 0 0 3px 2px #6a6b70,
    inset 0 0 0 6px #3a3b40;
}

.phone-stage .device-iphone-14-pro .device-btns,
.phone-stage .device-iphone-14-pro .device-btns::after,
.phone-stage .device-iphone-14-pro .device-btns::before,
.phone-stage .device-iphone-14-pro .device-power {
  background: #2e2f33;
}

/* --- Screen contents ---------------------------------------------------- */

.example-track {
  display: flex;
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  transition: transform 0.7s var(--jw-ease-out);
  will-change: transform;
}

.live-example-slide {
  flex: 0 0 100%;
  width: 100%;
  min-height: 0;
  /* Black, always: any white ground glitches through at the rounded screen
     edges while slides move or pages load. */
  background: var(--jw-black);
  overflow: hidden;
}

.live-example-shot {
  display: block;
  width: 100%;
  height: auto;
  max-width: none;
  will-change: transform;
}

/*
 * Each slide scrolls its page while it is showing. Paced to read like someone
 * browsing: a beat to take in the top, a long eased travel, then a rest at the
 * bottom before the slide changes. Must stay shorter than the slide interval
 * in creator-ui.js or the scroll gets cut off mid-travel.
 */
.live-example-slide.active .live-example-shot {
  animation: live-page-scroll 8.4s cubic-bezier(0.4, 0, 0.2, 1) both;
}

@keyframes live-page-scroll {
  0%, 14% { transform: translateY(0); }
  86%, 100% { transform: translateY(var(--page-scroll-third, -1200px)); }
}

/* --- Controls, below the device ----------------------------------------- */

.example-controls {
  display: grid;
  grid-template-columns: var(--jw-ring-button-size) auto var(--jw-ring-button-size);
  align-items: center;
  gap: var(--jw-space-3);
}

/* The arrows are the same ring icon buttons as the mobile menu control;
   components.css owns their look entirely. */

.slide-dots {
  display: flex;
  align-items: center;
  gap: var(--jw-space-2);
}

.slide-dot {
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  border-radius: var(--jw-radius-pill);
  background: var(--jw-line-strong);
  cursor: pointer;
  transition:
    width var(--jw-duration-slow) var(--jw-ease-out),
    background var(--jw-duration-slow) var(--jw-ease-out);
}

.slide-dot.active {
  width: 22px;
  background: var(--jw-accent);
}

.slide-dot:focus-visible {
  outline: 2px solid var(--jw-field-border-focus);
  outline-offset: 3px;
}

.example-hint {
  color: var(--jw-text-subtle);
  font-size: var(--jw-text-2xs);
  font-weight: var(--jw-weight-bold);
  letter-spacing: var(--jw-tracking-eyebrow);
  text-transform: uppercase;
}

@media (min-width: 1500px) {
  .phone-stage { --device-scale: 1.12; }
}

@media (min-width: 1800px) {
  .phone-stage { --device-scale: 1.28; }
}

@media (max-width: 1240px) {
  .phone-stage { --device-scale: 0.68; }
}

@media (max-width: 980px) {
  .phone-stage { --device-scale: 0.78; }
  .phone-viewport { max-height: 44svh; }
}

@media (max-width: 640px) {
  .phone-stage { --device-scale: 0.66; }
}

/* The created page fills the phone once generation finishes. */
.live-example-slide.created { background: var(--jw-white); }

.live-example-frame {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  background: var(--jw-black);
}

/* ---------------------------------------------------------------------------
 * Page transition inside the phone
 *
 * Covers the screen between example pages: a small address bar types the next
 * page's URL over a blank page, then a progress hairline sweeps and the new
 * page is revealed. Colours are literal because this is content ON the
 * device's screen — a web page being loaded — not themed site UI.
 * ------------------------------------------------------------------------ */

.page-transition {
  position: absolute;
  inset: 0;
  z-index: 7;
  display: grid;
  align-content: start;
  justify-items: center;
  padding-top: 56px;
  background: #fdfdfd;
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms ease;
}

.page-transition.show { opacity: 1; }

.pt-bar {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 32px;
  max-width: 86%;
  border-radius: var(--jw-radius-pill);
  background: #ececec;
  color: #3c3c3c;
  padding: 0 15px;
  font-family: var(--jw-font-sans);
  font-size: 0.8rem;
  font-weight: var(--jw-weight-medium);
  white-space: nowrap;
  overflow: hidden;
}

.pt-lock {
  width: 10px;
  height: 12px;
  flex: none;
  fill: #8a8a8a;
  stroke: #8a8a8a;
  stroke-width: 1.4;
}

.pt-caret {
  width: 1.5px;
  height: 14px;
  flex: none;
  background: #3c3c3c;
  animation: pt-blink 0.9s steps(2) infinite;
}

@keyframes pt-blink { 50% { opacity: 0; } }

/* Loading hairline under the bar, swept once when the address is complete. */
.pt-progress {
  width: 100%;
  height: 2px;
  margin-top: 14px;
  background: linear-gradient(90deg, var(--jw-accent), var(--jw-highlight));
  transform: scaleX(0);
  transform-origin: left center;
}

.page-transition.loading .pt-progress {
  transform: scaleX(1);
  transition: transform 320ms var(--jw-ease-in-out);
}

/* Close/open bookends around the address-typing transition. The URL bar
   itself is untouched; these animate the page inside the screen. */
.live-example-screen.closing .live-example-slide.active {
  animation: page-close 240ms cubic-bezier(0.4, 0, 1, 1) both;
}

@keyframes page-close {
  to {
    opacity: 0;
    transform: translateY(26px) scale(0.977);
  }
}

.live-example-screen.opening .live-example-slide.active {
  animation: page-open 400ms var(--jw-ease-out) both;
}

@keyframes page-open {
  from {
    opacity: 0;
    transform: translateY(30px) scale(0.982);
  }
}

/* ---------------------------------------------------------------------------
 * Mobile menu
 *
 * A ring FAB bottom-right opens a full-screen glass overlay: items centred
 * in the display face, appearance control seated at the bottom. Desktop
 * keeps the plain nav; all of this exists under 981px only.
 * ------------------------------------------------------------------------ */

.mobile-menu-button {
  display: none;
  position: fixed;
  right: var(--jw-space-5);
  bottom: var(--jw-space-5);
  z-index: var(--jw-z-overlay);
  --jw-ring-button-size: 54px;
}

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: var(--jw-z-modal);
  display: none;
  flex-direction: column;
  background: var(--jw-modal-bg);
  -webkit-backdrop-filter: blur(26px);
  backdrop-filter: blur(26px);
  padding: var(--jw-space-6);
}

.mobile-menu.open { display: flex; }

/* The close sits exactly where the menu button was, so the thumb never
   moves; the appearance row lifts above it. */
.mobile-menu-close {
  position: absolute;
  right: var(--jw-space-5);
  bottom: var(--jw-space-5);
  --jw-ring-button-size: 54px;
}

.mobile-menu-items {
  flex: 1;
  display: grid;
  align-content: center;
  justify-items: start;
  gap: var(--jw-space-6);
}

.mobile-menu-items a {
  font-family: var(--jw-font-display);
  font-size: clamp(2.2rem, 10vw, 3.4rem);
  font-weight: 700;
  color: var(--jw-text-primary);
  line-height: 1.3;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

.mobile-menu-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: var(--jw-space-5);
  /* Clears the close button parked at the corner below. */
  margin-bottom: calc(54px + var(--jw-space-6));
  border-top: 1px solid var(--jw-line);
}

.mobile-menu-foot span {
  color: var(--jw-text-muted);
  font-size: var(--jw-text-xs);
  font-weight: var(--jw-weight-bold);
  letter-spacing: var(--jw-tracking-eyebrow);
  text-transform: uppercase;
}

@media (max-width: 980px) {
  .mobile-menu-button { display: inline-flex; }
  .topbar .nav a, .topbar #themeToggle { display: none; }
}

/* SVG chevrons render identically everywhere, unlike glyph arrows. */
.example-arrow svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.mobile-menu-button svg, .mobile-menu-close svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
}
