:root {
  --canvas: #f9f5f2;
  --nav-bg: #1c1b19;
  --white: #ffffff;
  --nav-text: #f0f0f0;
  --muted: #a29e9b;
  --accent: #bef264;
  --accent-ink: 10 10 10;
  --font: "Satoshi", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-display: "InterVariable", "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  min-height: 100%;
  background: var(--canvas);
  font-family: var(--font);
}

/* Keeps the scrollbar's space when Lenis freezes the page under the trailer
   overlay, so the layout doesn't jump by a scrollbar width. */
html {
  scrollbar-gutter: stable;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Lenis's own required rules (from its docs) */
html.lenis,
html.lenis body {
  height: auto;
}

.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}

.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}

.lenis.lenis-stopped {
  overflow: clip;
}

.lenis.lenis-smooth iframe {
  pointer-events: none;
}

.sprite {
  position: absolute;
  width: 0;
  height: 0;
}

/*
 * Hero — the title hangs just under the floating nav rather than sitting on the
 * viewport's middle. An extra 100px gives the floating header breathing room
 * and moves all following content down in the normal document flow.
 */
.hero {
  --nav-top: 10px;
  --nav-h: 44px;
  padding: calc(var(--nav-top) + var(--nav-h) + 140px) 24px 0;
  text-align: center;
}

/* One line, sized so the sentence spans about three fifths of the page. */
.hero__title {
  margin-inline: auto;
  font-family: var(--font-display);
  font-size: clamp(22px, 4.6vw, 155px);
  font-weight: 520;
  letter-spacing: -0.035em;
  line-height: 1.05;
  white-space: nowrap;
  color: var(--nav-bg);
}

/* Two lines, broken where the copy asks for it rather than by measure, small
   and light under the title. */
.hero__lede {
  width: 60vw;
  max-width: 100%;
  margin-inline: auto;
  margin-top: 30px;
  font-family: var(--font-display);
  font-size: clamp(13px, 1.2vw, 25px);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: var(--muted);
}

/* Trailer: the video alone, a short drop under the button */
.trailer {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 44px;
  padding-bottom: clamp(56px, 10vh, 120px);
}

/* Video, badge and copy share one column, so the text below starts and ends
   exactly on the video's edges. */
.reel {
  width: calc(100% - 200px);
}

.reel__frame {
  position: relative;
}

/* Nearly the full page, with a 100px gutter either side. The corner is the
   same 10px the image tiles above it used — softened, not a pill. */
.reel__thumb {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 0;
  border-radius: 10px;
  /* Transparent, not the site's ink: behind the rounded corners a fill shows
     through as a dark hairline where the clip antialiases. */
  background: transparent;
  /* The label follows the pointer and would spill past the edge and the page */
  overflow: hidden;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.reel__thumb:focus-visible {
  outline: 2px solid var(--nav-bg);
  outline-offset: 3px;
}

.reel__preview {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  object-fit: cover;
}

/* Positioned by JS (spring-driven translate); exclusion keeps it readable over
   light and dark frames alike. */
.reel__cursor {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  /* js/showreel.js drives it from the pointer; js/reel-scroll.js drives it from
     the scroll when there is no pointer on the thumbnail. */
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  color: var(--white);
  mix-blend-mode: exclusion;
  opacity: 0;
  pointer-events: none;
  user-select: none;
  will-change: transform, opacity;
}

.reel__cursor svg {
  width: 16px;
  height: 16px;
  fill: currentColor;
  stroke: currentColor;
}

/*
 * shadcn/ui Badge, ported the same way as the Button: the cva base and the
 * icon-inline-start padding, with one variant of its own — frosted glass,
 * after the liquid-glass panel this page used to carry. It is centred on the
 * video by the inset + auto-margin trick and takes no pointer events, so the
 * hover label and the click-to-play underneath still work.
 */
[data-slot="badge"] {
  display: inline-flex;
  width: fit-content;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  overflow: hidden;
  border: 1px solid transparent;
  border-radius: 2rem;
  padding: 0.125rem 0.5rem;
  font-family: var(--font);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

[data-slot="badge"] > svg {
  pointer-events: none;
  width: 0.75rem;
  height: 0.75rem;
}

[data-slot="badge"]:has(> [data-icon="inline-start"]) {
  padding-left: 0.375rem;
}

/*
 * Sized well up from the component's h-5, since it sits on a full-width video,
 * and skinned as ui-layouts' LiquidGlassCard rather than as a flat tint. The
 * card's three layers are kept as the component stacks them — blur + bend
 * below, then the glow, then the inset edge, with the label above all of it —
 * at its blurIntensity="sm" / glowIntensity="sm" / shadowIntensity="sm" preset.
 * The one departure is the ink: the component's own demo sets its content
 * white, which would disappear against the pale frames this trailer opens on,
 * so the label carries the nav's dark ink instead.
 */
.reel__badge[data-slot="badge"] {
  position: absolute;
  inset: 0;
  z-index: 3;
  height: 4rem;
  margin: auto;
  padding: 0 1.75rem;
  color: var(--nav-bg);
  font-size: 1.125rem;
  font-weight: 500;
  letter-spacing: -0.015em;
  pointer-events: none;
}

.glass__bend,
.glass__glow,
.glass__edge {
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

/* backdrop-blur-xs, then the fractal displacement (#glass-blur, index.html) */
.glass__bend {
  z-index: 0;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  filter: url(#glass-blur);
}

/* glowIntensity="sm" */
.glass__glow {
  z-index: 1;
  box-shadow: 0 4px 4px rgb(0 0 0 / 0.15), 0 0 12px rgb(0 0 0 / 0.08),
    0 0 24px rgb(255 255 255 / 0.1);
}

/* shadowIntensity="sm" */
.glass__edge {
  z-index: 2;
  box-shadow: inset 2px 2px 2px 0 rgb(255 255 255 / 0.35),
    inset -2px -2px 2px 0 rgb(255 255 255 / 0.35);
}

.reel__badge-label {
  position: relative;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
}

.reel__badge-label > svg {
  width: 1.375rem;
  height: 1.375rem;
}

/* Two lines the width of the video, in the nav's ink. */
.reel__copy {
  margin-top: 6px;
  font-family: var(--font-display);
  font-size: clamp(16px, 2.06vw, 35px);
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: var(--nav-bg);
}

/*
 * The held line, pinned. The section is three-and-a-bit screens tall and the
 * stage inside it is sticky, so the line holds still in the middle of the
 * screen while those screens of scroll go by — the pin is the sticky element,
 * not a scroll library. js/orb-scene.js reads how far through the section the
 * page is and cycles the orbs across that same range.
 */
.statement {
  position: relative;
  height: 560svh;
}

.statement__stage {
  position: sticky;
  top: 0;
  display: grid;
  place-items: center;
  height: 100svh;
  padding-inline: 24px;
  overflow: hidden;
  text-align: center;
}

/* Its own stacking context, under the line. Without it the z-index the scene
   writes per orb (which orders the near and far sides of a turn against each
   other) would compete with the line itself and paint over the words. */
.statement__orbs {
  position: absolute;
  inset: 0;
  z-index: 0;
  isolation: isolate;
}

/*
 * Above the canvas: the orbs pass behind the words. It costs nothing later,
 * since the line has left before the dark orb grows over the screen.
 *
 * The line is a row rather than a run of text, because the mark opens out
 * between the two halves on hover (after fancy's MediaBetweenText): the media
 * box is what animates, from no width to its own, and the words are simply
 * pushed apart by it.
 */
.statement__line {
  position: relative;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  will-change: transform, opacity;
  font-family: var(--font-display);
  font-size: clamp(28px, 3.6vw, 64px);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--nav-bg);
}

.statement__word {
  white-space: nowrap;
}

/*
 * Closed. Only the width animates, so the words move with it rather than
 * sliding under anything.
 *
 * Two things open it: the scroll, through --open, which the scene sets as the
 * scene plays; and hover, which takes it to full. The larger wins, so hovering
 * mid-scene cannot make it jump backwards.
 */
.statement__media {
  --media: clamp(44px, 5.8vw, 98px);
  --open: 0;
  display: block;
  flex: none;
  width: calc(var(--media) * var(--open));
  height: var(--media);
  margin-inline: clamp(2px, 0.5vw, 8px);
  overflow: hidden;
  transition: width 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Inverted: the file is a dark body with a light swoosh, which sinks into this
   page as a blob. Flipped, the body goes light and the swoosh dark, and the
   mark reads as a mark. */
.statement__media img {
  display: block;
  width: var(--media);
  height: 100%;
  object-fit: contain;
  filter: invert(1);
}

.statement__line:hover .statement__media {
  width: var(--media);
}

@media (prefers-reduced-motion: reduce) {
  .statement__media {
    transition-duration: 0s;
  }
}

/*
 * The scene's two canvases, one either side of the line. Orbs still rising
 * toward it are drawn on the front layer and pass over the words; from the
 * moment they are level with it they are drawn on the back layer and pass
 * behind. Each layer is one WebGL context (js/orb-gl.js) drawing all of its
 * orbs, so within a layer the draw order is the depth order.
 */
.statement__orbs {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.statement__orbs--back {
  z-index: 2;
}

.statement__orbs--front {
  z-index: 4;
}

/*
 * The surface the last orb settles into, after smoothui's MorphSurface: a dock
 * with the orb on its left and a label beside it, which opens into a composer
 * when pressed. The orb is not in here — it is still on the canvas above, drawn
 * at this slot's place — so the two never have to hand over, they simply meet,
 * and the orb stays put while the surface grows around it.
 *
 * Width and height are what animate, as in the reference; the label and the
 * composer cross-fade inside them.
 */
.dock {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 16px;
  width: clamp(262px, 24vw, 310px);
  height: clamp(72px, 9vh, 96px);
  padding: 0 16px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--background);
  box-shadow: 0 10px 34px rgb(0 0 0 / 0.16);
  font-family: var(--font);
  color: var(--foreground);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -50%);
  transition: width 0.42s var(--ease-out), height 0.42s var(--ease-out),
    border-radius 0.42s var(--ease-out);
  will-change: transform, opacity;
}

/* Open, it is a box rather than a pill — a bar you type into, cornered like
   the trailer above it. */
.dock.is-open {
  width: min(620px, 78vw);
  height: clamp(112px, 14vh, 140px);
  border-radius: 16px;
}

/*
 * The frame the bar rests on: a plate of the same picture the comparison runs
 * on, cornered like the trailer. js/orb-scene.js sizes and places it from the
 * bar's own box each frame, so it tracks the bar through the morph without the
 * two having to agree on any numbers.
 */
.dock-plate {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 0;
  border-radius: 14px;
  background: linear-gradient(rgb(10 18 8 / 0.42), rgb(10 18 8 / 0.5)),
    url("../brandidentity/logo/background1.png") center / cover no-repeat;
  box-shadow: 0 12px 40px rgb(0 0 0 / 0.2);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* Kept empty: it only reserves the orb's place in the row and gives the scene
   something to measure. */
.dock__slot {
  display: block;
  width: clamp(48px, 6vh, 64px);
  height: clamp(48px, 6vh, 64px);
  flex: none;
}

/* Centred on the composer, not pinned to its top: with a single-line input
   beside it, the middle is where it belongs. */
.dock.is-open .dock__slot {
  align-self: center;
}

/* The closed state: label and press glyph. Both leave when it opens. */
.dock__trigger {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: opacity 0.2s ease, transform 0.12s ease;
}

.dock__trigger:active {
  transform: scale(0.97);
}

.dock.is-open .dock__trigger {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

/* The same dark circle the composer sends with, so the closed bar already
   shows what pressing it leads to. */
.dock__go {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex: none;
  border-radius: 50%;
  background: var(--nav-bg);
  color: var(--white);
}

.dock__go svg {
  width: 17px;
  height: 17px;
}

/* The open state */
.dock__composer {
  position: absolute;
  inset: 0 16px 0 calc(16px + clamp(48px, 6vh, 64px) + 16px);
  display: flex;
  align-items: center;
  gap: 10px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.24s ease 0.06s;
}

.dock.is-open .dock__composer {
  opacity: 1;
  pointer-events: auto;
}

.dock__input {
  flex: 1;
  align-self: center;
  min-width: 0;
  padding: 10px 2px;
  border: 0;
  background: none;
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.5;
  resize: none;
  color: var(--foreground);
  outline: none;
}

.dock__input::placeholder {
  color: var(--muted);
}

.dock__send {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex: none;
  border: 0;
  border-radius: 50%;
  background: var(--nav-bg);
  color: var(--white);
  cursor: pointer;
  transition: transform 0.12s ease, opacity 0.15s ease;
}

.dock__send:active {
  transform: scale(0.94);
}

.dock__send svg {
  width: 17px;
  height: 17px;
}

@media (prefers-reduced-motion: reduce) {
  .dock {
    transition-duration: 0s;
  }
}

.dock__label {
  font-size: clamp(19px, 2.2vh, 24px);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1;
  white-space: nowrap;
}

/*
 * The plate: the comparison over a picture, cornered like the trailer above it
 * so the two read as the same kind of object. The image is a layer rather than
 * a background so it can be cropped by the box and dimmed on its own.
 */
/*
 * The plate opens out to the full width of the page as the section arrives and
 * draws back in as it leaves — js/compare-frame.js sets the width and the squircle's
 * blur from the same scroll value, so the frame is wide and square when it is
 * being read and small and soft-cornered when it is not. The content inside
 * keeps its own measure, so nothing but the frame moves.
 */
.compare__plate {
  position: relative;
  isolation: isolate;
  width: min(720px, calc(100% - 48px));
  padding: clamp(68px, 10vh, 132px) clamp(18px, 3vw, 44px) clamp(36px, 6vh, 72px);
  border-radius: 10px;
  overflow: hidden;
  will-change: width;
}

.compare__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A scrim over the picture. The table is white on top of it, and a frame this
   busy needs a floor under the contrast or the thin type dissolves into it. */
.compare__plate::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(rgb(10 18 8 / 0.52), rgb(10 18 8 / 0.62));
  pointer-events: none;
}

/* Set like the paragraph above it — same family and weight, a size down — and
   given room, so it sits clear of the table rather than on top of it. */
.compare__title {
  margin: 0 0 clamp(18px, 3vh, 34px);
  font-family: var(--font-display);
  font-size: clamp(24px, 2.6vw, 46px);
  font-weight: 450;
  letter-spacing: -0.024em;
  line-height: 1.08;
  text-align: center;
  color: var(--white);
}

/*
 * The waitlist notice, after HeroUI's Toast: a landmark region at the foot of
 * the screen holding one alert dialog — indicator, title, description and a
 * dismiss button. Fixed, above everything, and out of the way of pointers
 * except on the message itself.
 */
.toasts {
  position: fixed;
  left: 50%;
  bottom: clamp(16px, 4vh, 40px);
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: min(460px, calc(100% - 32px));
  transform: translateX(-50%);
  pointer-events: none;
}

/* Glass, like the trailer's pill: a translucent pane over whatever it covers,
   with the same inset edges. The blur is what keeps the type legible over a
   moving frame underneath. */
.toast {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 14px 14px 16px;
  border: 1px solid rgb(255 255 255 / 0.5);
  border-radius: 16px;
  background: rgb(255 255 255 / 0.62);
  backdrop-filter: blur(16px) saturate(1.5);
  -webkit-backdrop-filter: blur(16px) saturate(1.5);
  box-shadow: 0 12px 34px rgb(0 0 0 / 0.16), inset 1.5px 1.5px 2px rgb(255 255 255 / 0.6),
    inset -1.5px -1.5px 2px rgb(255 255 255 / 0.45);
  font-family: var(--font);
  color: var(--foreground);
  opacity: 0;
  transform: translateY(14px) scale(0.98);
  transition: opacity 0.26s var(--ease-out), transform 0.26s var(--ease-out);
  pointer-events: auto;
}

.toast.is-in {
  opacity: 1;
  transform: none;
}

.toast.is-out {
  opacity: 0;
  transform: translateY(8px) scale(0.98);
}

.toast__indicator {
  display: grid;
  place-items: center;
  flex: none;
  width: 22px;
  height: 22px;
  margin-top: 1px;
  color: var(--nav-bg);
}

/* The reference's variants, as keyframes: a scale up and a short rock, once. */
.toast.is-in .toast__indicator svg {
  animation: badge-alert 0.5s ease-in-out 0.12s both;
}

@keyframes badge-alert {
  0% {
    transform: scale(1) rotate(0deg);
  }

  20% {
    transform: scale(1.1) rotate(-3deg);
  }

  40% {
    transform: scale(1.1) rotate(3deg);
  }

  60% {
    transform: scale(1.1) rotate(-2deg);
  }

  80% {
    transform: scale(1.05) rotate(2deg);
  }

  100% {
    transform: scale(1) rotate(0deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .toast.is-in .toast__indicator svg {
    animation: none;
  }
}

.toast__indicator svg {
  width: 18px;
  height: 18px;
}

.toast__content {
  flex: 1;
  min-width: 0;
}

.toast__title {
  margin: 0;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.3;
}

.toast__description {
  margin: 4px 0 0;
  font-size: 13px;
  line-height: 1.4;
  color: var(--muted);
}

.toast__action {
  flex: none;
  align-self: center;
  padding: 7px 13px;
  border: 1px solid rgb(255 255 255 / 0.6);
  border-radius: 999px;
  background: rgb(255 255 255 / 0.5);
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  color: var(--foreground);
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.toast__action:hover {
  background: var(--white);
}

@media (prefers-reduced-motion: reduce) {
  .toast {
    transition-duration: 0s;
  }
}

/*
 * Sticky footer, after fancy's: the footer sits at the bottom of the document
 * behind the page, and the page — which has its own background and a higher
 * z-index — slides off it as the scroll ends, so it is revealed rather than
 * scrolled to. Three things do the work: the page's stacking, the footer's
 * `sticky; bottom: 0`, and the page's opaque background.
 */
.page {
  position: relative;
  z-index: 10;
  background: var(--canvas);
}

.footer {
  position: sticky;
  bottom: 0;
  left: 0;
  z-index: 0;
  height: clamp(280px, 42vh, 380px);
  background: var(--nav-bg);
  color: var(--canvas);
}

.footer__inner {
  position: relative;
  display: flex;
  justify-content: flex-end;
  height: 100%;
  padding: clamp(28px, 5vh, 52px) clamp(20px, 4vw, 64px);
  overflow: hidden;
}

.footer__links {
  display: flex;
  gap: clamp(36px, 7vw, 96px);
  text-align: right;
  font-family: var(--font);
  font-size: clamp(13px, 1.2vw, 19px);
}

.footer__links ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.footer__links li + li {
  margin-top: 6px;
}

.footer__links a,
.footer__link {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-decoration: none;
  opacity: 0.82;
  cursor: pointer;
  transition: opacity 0.15s ease;
}

.footer__links a:hover,
.footer__link:hover {
  opacity: 1;
  text-decoration: underline;
}

/* Set past the bottom edge and clipped by the footer, as in the reference: the
   word reads as the ground the page ends on rather than as a caption. */
.footer__word {
  position: absolute;
  left: clamp(-6px, -0.6vw, 0px);
  bottom: 0;
  margin: 0;
  font-family: var(--font);
  font-size: clamp(72px, 15vw, 210px);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 0.82;
  color: var(--canvas);
  transform: translateY(30%);
  pointer-events: none;
}

/*
 * Sticky footer, after fancy's: the footer sits at the bottom of the document
 * behind the page, and the page — which has its own background and a higher
 * z-index — slides off it as the scroll ends, so it is revealed rather than
 * scrolled to. Three things do the work: the page's stacking, the footer's
 * `sticky; bottom: 0`, and the page's opaque background.
 */
.page {
  position: relative;
  z-index: 10;
  background: var(--canvas);
}

.footer {
  position: sticky;
  bottom: 0;
  left: 0;
  z-index: 0;
  height: clamp(280px, 42vh, 380px);
  background: var(--nav-bg);
  color: var(--canvas);
}

.footer__inner {
  position: relative;
  display: flex;
  justify-content: flex-end;
  height: 100%;
  padding: clamp(28px, 5vh, 52px) clamp(20px, 4vw, 64px);
  overflow: hidden;
}

.footer__links {
  display: flex;
  gap: clamp(36px, 7vw, 96px);
  text-align: right;
  font-family: var(--font);
  font-size: clamp(13px, 1.2vw, 19px);
}

.footer__links ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.footer__links li + li {
  margin-top: 6px;
}

.footer__links a,
.footer__link {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-decoration: none;
  opacity: 0.82;
  cursor: pointer;
  transition: opacity 0.15s ease;
}

.footer__links a:hover,
.footer__link:hover {
  opacity: 1;
  text-decoration: underline;
}

/* Set past the bottom edge and clipped by the footer, as in the reference: the
   word reads as the ground the page ends on rather than as a caption. */
.footer__word {
  position: absolute;
  left: clamp(-6px, -0.6vw, 0px);
  bottom: 0;
  margin: 0;
  font-family: var(--font);
  font-size: clamp(72px, 15vw, 210px);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 0.82;
  color: var(--canvas);
  transform: translateY(30%);
  pointer-events: none;
}

/*
 * The paragraph, then the comparison. One centred measure for both, so the
 * table's outer edges line up with where the sentence turns.
 */
.compare {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(36px, 5vh, 76px) 0 clamp(96px, 16vh, 200px);
}

/*
 * Set tight and large: the measure is wide enough for four or five full lines,
 * `pretty` keeps the last one from ending on a single word, and the leading is
 * close enough that the block reads as one paragraph rather than as stacked
 * sentences. It rises into place on scroll (js/scroll-in.js) — travel only, no
 * fade, like the line and the orb before it.
 */
.compare__lede {
  max-width: min(920px, 70vw);
  padding-inline: 24px;
  margin: 0 auto clamp(220px, 40vh, 480px);
  font-family: var(--font-display);
  font-size: clamp(24px, 2.9vw, 54px);
  font-weight: 450;
  line-height: 1.02;
  letter-spacing: -0.024em;
  text-align: center;
  text-wrap: pretty;
  color: var(--nav-bg);
  will-change: transform;
}

/*
 * The table is a real table — it is a comparison, and the row and column
 * headers are what carry it to a screen reader. `separate` borders are what
 * let the branded column read as one raised card: only its first and last
 * cells are rounded, and the rest share its fill.
 */
.compare__sub {
  margin: 0 0 clamp(30px, 5vh, 62px);
  font-family: var(--font-display);
  font-size: clamp(13px, 1.15vw, 19px);
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: 1.3;
  text-align: center;
  color: rgb(255 255 255 / 0.76);
}

/* Fit the frame even on narrow screens; keep both result columns aligned. */
.compare__table {
  width: 100%;
  max-width: 764px;
  table-layout: fixed;
  margin-inline: auto;
  border-collapse: separate;
  border-spacing: 0;
  font-family: var(--font);
}

.compare__head {
  width: 24%;
  padding: 0 0 18px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: rgb(255 255 255 / 0.74);
  text-align: center;
  vertical-align: bottom;
}

/* The card behind the column starts at the logo, not at the first row, so the
   column reads as one object the way the reference's does. The fill itself is
   the card's, below. */
.compare__head--brand {
  padding-top: 26px;
  color: var(--nav-bg);
}

.compare__logo {
  display: block;
  width: 116px;
  height: auto;
  /* The file's own transparent margin, taken back so the mark sits on the
     column's centre line rather than floating above it. */
  margin: calc(116px * -0.1853) auto calc(116px * -0.1776);
}

.compare__table th[scope="row"] {
  position: relative;
  padding: 22px 30px 22px 20px;
  font-size: 15px;
  font-weight: 400;
  line-height: 1.35;
  letter-spacing: -0.005em;
  text-align: left;
  color: var(--white);
}

.compare__cell {
  width: 184px;
  padding: 22px 8px;
  text-align: center;
  vertical-align: middle;
}

/*
 * The rows are one pane of glass, not a pane each: the group is positioned and
 * its ::before covers it edge to edge, carrying the trailer badge's three
 * layers at once — a bend that blurs and displaces what is behind it
 * (#glass-blur, index.html), the glow, and the inset edges. Per-cell panes
 * gave every row its own rim, which read as a grid of boxes rather than as one
 * sheet laid over the picture.
 */
/* Positioned, so the sheet below can be pinned to it — but deliberately NOT
   isolated: an isolated row group is its own stacking context, and the raised
   card is a sibling of the table, so the cells could never rank above it and
   the column's ticks were painted over. Left open, the sheet's -1 falls through
   to the plate (which is the isolated one) and the order is card, then cells. */
.compare__table tbody {
  position: relative;
}

.compare__table tbody::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 16px;
  background: rgb(255 255 255 / 0.08);
  backdrop-filter: blur(7px) saturate(1.2);
  -webkit-backdrop-filter: blur(7px) saturate(1.2);
  /* No displacement on a sheet this size. The bend is what gives the badge its
     liquid edge, but over a panel it drags the corners into rags — here the
     tint, the blur and the inset edges carry it, and the rectangle stays a
     rectangle. */
  box-shadow: 0 4px 14px rgb(0 0 0 / 0.16), inset 2px 2px 2px rgb(255 255 255 / 0.3),
    inset -2px -2px 2px rgb(255 255 255 / 0.22);
}

/*
 * The raised column is one element, not a fill on each cell: cells cannot share
 * a shadow, and one per cell drew a band across the next. The card is
 * placed by js/compare-frame.js from the column's own box, sits above the sheet
 * of glass, and the cells' contents sit above it.
 */
.compare__card {
  position: absolute;
  z-index: 1;
  border-radius: 16px;
  background: var(--white);
  box-shadow: 0 10px 34px rgb(0 0 0 / 0.3);
  opacity: 0;
  pointer-events: none;
}

.compare__cell--brand,
.compare__head--brand {
  position: relative;
  z-index: 2;
  background: none;
}

/* The rest of the table ranks above the sheet as well, so the glass stays
   behind every row and not only behind the raised column. */
.compare__table th[scope="row"],
.compare__table .compare__cell {
  z-index: 1;
}

/* The closing line is outside both: no card, no glass, just the words on the
   page — as the reference leaves its own total row. */
.compare__table tfoot .compare__cell--brand,
.compare__table tfoot .compare__cell {
  background: none;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.compare__table tfoot th[scope="row"],
.compare__table tfoot .compare__cell {
  padding-top: 26px;
}

/* No rules between the rows: the glass panes are separated by their own edges,
   and a line on top of that is one separator too many. */

.compare__icon {
  display: inline-block;
  width: 22px;
  height: 22px;
  color: var(--nav-bg);
}

.compare__icon--no {
  width: 19px;
  height: 19px;
  color: rgb(255 255 255 / 0.62);
}

.compare__table tfoot th[scope="row"] {
  font-weight: 500;
}

.compare__sum {
  font-size: 13px;
  line-height: 1.3;
  letter-spacing: -0.005em;
  color: rgb(255 255 255 / 0.7);
}

.compare__cell--brand.compare__sum {
  color: var(--white);
}

/* The note under the table: small, quiet and centred under the closing line —
   it qualifies the comparison rather than taking part in it. */
.compare__note {
  max-width: 62ch;
  margin: clamp(16px, 2.4vh, 28px) auto 0;
  font-family: var(--font);
  font-size: 11px;
  line-height: 1.5;
  letter-spacing: -0.005em;
  text-align: center;
  text-wrap: pretty;
  color: rgb(255 255 255 / 0.55);
}

/* Announced, not shown */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/*
 * Showreel overlay. The frame opens by un-clipping from a small window in the
 * middle; --spring is that motion's spring (stiffness 100, damping 20, mass 1,
 * critically damped) sampled into linear(), with a bezier for browsers that
 * lack linear(). On close the frame shrinks back first and only then fades, and
 * visibility waits out both so the exit is actually seen.
 */
.reel-modal {
  --spring: cubic-bezier(0.2, 0.6, 0.3, 1);
  position: fixed;
  inset: 0;
  z-index: 101;
  display: grid;
  place-items: center;
  visibility: hidden;
  transition: visibility 0s linear 1s;
}

@supports (transition-timing-function: linear(0, 1)) {
  .reel-modal {
    --spring: linear(0, 0.045, 0.144, 0.264, 0.385, 0.496, 0.594, 0.677, 0.745, 0.801, 0.845, 0.881, 0.908, 0.93, 0.947, 0.96, 0.969, 0.977, 0.983, 0.987, 0.99, 0.993, 0.995, 0.996, 1);
  }
}

.reel-modal.is-open {
  visibility: visible;
  transition-delay: 0s;
}

.reel-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgb(249 245 242 / 0.9);
  backdrop-filter: blur(16px);
  opacity: 0;
  transition: opacity 0.2s ease;
}

.reel-modal.is-open .reel-modal__backdrop {
  opacity: 1;
}

.reel-modal__frame {
  position: relative;
  /* Fit inside the viewport on both axes instead of overflowing a short one */
  width: min(1280px, calc(100vw - 32px), calc((100vh - 32px) * 16 / 9));
  aspect-ratio: 16 / 9;
  clip-path: inset(43.5% 43.5% 33.5% 43.5%);
  opacity: 0;
  transition: clip-path 0.8s var(--spring), opacity 0.2s linear 0.8s;
}

.reel-modal.is-open .reel-modal__frame {
  clip-path: inset(0);
  opacity: 1;
  transition: clip-path 0.8s var(--spring), opacity 0.7s var(--spring);
}

.reel-modal__player {
  display: block;
  width: 100%;
  height: 100%;
  background: #000;
}

.reel-modal__video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.reel-modal__close {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 10;
  padding: 4px;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--white);
  /* Same as the control bar: plain white vanishes on a white frame */
  mix-blend-mode: exclusion;
  line-height: 0;
  cursor: pointer;
}

.reel-modal__close svg {
  width: 20px;
  height: 20px;
  rotate: 45deg;
}

.reel-modal__close:focus-visible {
  outline: 2px solid var(--white);
}

/* Bare transport: play, a hairline scrubber, mute. Exclusion again, so the bar
   stays visible over any frame. */
.reel-modal__bar {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  padding: 12px 20px;
  mix-blend-mode: exclusion;
  --media-control-background: transparent;
  --media-control-hover-background: transparent;
  --media-primary-color: #fff;
  --media-range-thumb-opacity: 0;
  --media-range-track-height: 2px;
}

@media (min-width: 768px) {
  .reel-modal__bar {
    padding: 20px 40px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .reel-modal__frame,
  .reel-modal.is-open .reel-modal__frame {
    clip-path: none;
    transition: opacity 0.2s linear;
  }
}

/* Phones: the button moves onto its own row above the image and the stack */
/*
 * shadcn/ui Button, carried over as plain CSS: the cva base, size="default",
 * and variant="default" — except that the hover state is variant="outline"'s
 * resting look, so the dark button turns into the outlined one under the
 * pointer. --primary is the site's ink so it matches the nav; --radius is
 * shadcn's default, which rounded-lg resolves to.
 */
:root {
  --radius: 0.625rem;
  --radius-lg: var(--radius);
  --primary: var(--nav-bg);
  --primary-foreground: #fafafa;
  --ring: #a3a3a3;
  --background: var(--white);
  --foreground: var(--nav-bg);
  --border: #e4dfdb;
}

[data-slot="button"] {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--radius-lg);
  background-clip: padding-box;
  font-family: var(--font);
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.25rem;
  white-space: nowrap;
  outline: none;
  user-select: none;
  cursor: pointer;
  transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

[data-slot="button"]:focus-visible {
  border-color: var(--ring);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--ring) 50%, transparent);
}

[data-slot="button"]:active:not([aria-haspopup]) {
  translate: 0 1px;
}

[data-slot="button"]:disabled {
  pointer-events: none;
  opacity: 0.5;
}

[data-slot="button"] svg {
  pointer-events: none;
  flex-shrink: 0;
  width: 1rem;
  height: 1rem;
}

[data-slot="button"][data-size="default"] {
  height: 2rem;
  gap: 0.375rem;
  padding-inline: 0.625rem;
}

[data-slot="button"][data-variant="default"] {
  background-color: var(--primary);
  color: var(--primary-foreground);
}

/* The outline variant's resting state, used here as the hover state, except
   that it fills with the page's own colour rather than white, so the button
   reads as an outline drawn straight on the canvas. */
[data-slot="button"][data-variant="default"]:hover {
  border-color: var(--border);
  background-color: var(--canvas);
  color: var(--foreground);
}

/* A size of its own, above size="default" — the hero carries a bigger control.
   It has to out-specify the size rule above, hence the attributes. */
.hero__cta[data-slot="button"][data-size="default"] {
  height: 2.875rem;
  margin-top: 42px;
  padding-inline: 1.375rem;
  font-size: 0.9375rem;
}

/* Preserve the desktop hierarchy with readable, naturally wrapping phone text. */
@media (max-width: 700px) {
  .hero {
    padding-inline: 16px;
  }

  .hero__title {
    max-width: 16ch;
    font-size: clamp(34px, 8vw, 52px);
    line-height: 1.08;
    white-space: normal;
    text-wrap: balance;
  }

  .hero__lede {
    width: min(100%, 38ch);
    margin-top: 24px;
    font-size: 16px;
    line-height: 1.5;
    color: #77716c;
  }

  .hero__break {
    display: none;
  }
}

/* A 100px gutter either side is most of a phone, so the video keeps the page's
   own 16px edge instead. */
@media (max-width: 900px) {
  .reel {
    width: calc(100% - 32px);
  }

  .reel__badge[data-slot="badge"] {
    height: 2.5rem;
    padding: 0 1rem;
    font-size: 0.8125rem;
  }

  .reel__badge-label > svg {
    width: 1rem;
    height: 1rem;
  }

  .reel__copy {
    margin-top: 16px;
    font-size: clamp(16px, 2.3vw, 19px);
    line-height: 1.45;
  }

  .statement {
    height: 450svh;
  }

  .compare__lede {
    max-width: 100%;
  }

  .compare__table th[scope="row"] {
    padding-right: 14px;
    font-size: 13.5px;
  }

  .compare__cell {
    width: 96px;
    padding-inline: 4px;
  }

  .compare__logo {
    width: 88px;
    margin-block: calc(88px * -0.1853) calc(88px * -0.1776);
  }

  .compare__sum {
    font-size: 12px;
  }

  .statement__line {
    font-size: clamp(22px, 5.2vw, 40px);
  }
}

/*
 * The bar: the lockup top left, the waitlist button top right, both following
 * the page. The row between them is inert — it spans the width only to push
 * the two apart, and takes no pointer events, so everything under it stays
 * clickable.
 */
.nav {
  position: fixed;
  top: clamp(10px, 1.1em, 18px);
  left: 0;
  right: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-inline: clamp(16px, 2em, 32px);
  pointer-events: none;
}

/* Both sit straight on the page — no bar, no plate behind either. */
.nav__logo,
.nav__cta {
  --bubble: 44px;
  pointer-events: auto;
}

/*
 * It opens on the page's centre line and travels out to its own place as the
 * reader scrolls (js/nav-centre.js). Its transform belongs to that script
 * alone: the entrance animates the mark inside it, because GSAP clears the
 * individual transform properties on anything it tweens and the two would
 * otherwise overwrite each other.
 */
.nav__logo {
  /* Declared here, where js/nav-centre.js sets it: a declaration on the image
     itself would shadow the inherited value and the size would never change.
     It opens at the size it is read at — the script's own starting value, so
     the first painted frame is already right and the mark never pops. */
  --logo-w: 196px;
  display: inline-flex;
  align-items: center;
  height: var(--bubble);
  background: none;
  text-decoration: none;
  will-change: transform;
}

/* The one thing in the bar besides the mark: the same dark button the hero
   carries, at the height of the row. */
.nav__cta {
  display: inline-flex;
  align-items: center;
  height: 44px;
  padding: 0 18px;
  border: 1px solid transparent;
  border-radius: var(--radius-lg);
  background: var(--primary);
  background-clip: padding-box;
  color: var(--primary-foreground);
  font-family: var(--font);
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  letter-spacing: -0.01em;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.15s ease, transform 0.12s ease;
}

.nav__cta:hover {
  border-color: var(--border);
  background-color: var(--canvas);
  color: var(--foreground);
}

.nav__cta:active {
  transform: scale(0.97);
}

/*
 * The lockup is its own dark ink on transparent, which is what the page wants,
 * so it is used as it comes. It carries a wide transparent margin — 13.9% /
 * 13.8% at the sides and 32.9% / 31.6% top and bottom of the file — and the
 * negative margins take exactly that back, so the row packs to the ink rather
 * than to the empty PNG. Re-measure them if the file is ever re-exported.
 *
 * It opens large on the centre line and settles to this size as it crosses to
 * the corner; js/nav-centre.js sets --logo-w along the way.
 */
.nav__logo-img {
  display: block;
  width: var(--logo-w);
  height: auto;
  margin: calc(var(--logo-w) * -0.1853) calc(var(--logo-w) * -0.1376)
          calc(var(--logo-w) * -0.1776) calc(var(--logo-w) * -0.1394);
}

.nav__logo:focus-visible,
.nav__cta:focus-visible {
  outline: 2px solid var(--nav-bg);
  outline-offset: 3px;
}

@media (min-width: 768px) {
  .nav__logo,
  .nav__cta {
    --bubble: 48px;
  }
}

@media (prefers-reduced-motion: reduce) {
}

/* Hidden until js/nav-intro.js has its opening frame set, so the finished
   bubbles never flash first. Only with script: without it the rule never
   applies. The button waits for the webfont as well — its label is what sets
   its width, and it is pinned to the right, so a late swap jumped its left
   edge across the corner. */
.js-anim .nav__logo-img,
.js-anim .nav__cta {
  opacity: 0;
}

/* The page's opening state, set only when there is script to animate it out of
   (js/hero-intro.js). Without it the page is simply there. */
.js-anim .hero__title,
.js-anim .hero__lede,
.js-anim .hero__cta,
.js-anim .reel {
  opacity: 0;
}

/* Keep the same comparison composition without animating narrow-screen width. */
@media (max-width: 1100px) {
  .compare__plate {
    width: calc(100% - 32px);
    padding-inline: 24px;
    will-change: auto;
  }
}

@media (max-width: 700px) {
  .nav {
    top: 0;
    padding-top: max(16px, env(safe-area-inset-top));
    padding-bottom: 12px;
    padding-left: max(20px, env(safe-area-inset-left));
    padding-right: max(20px, env(safe-area-inset-right));
    background: rgb(249 245 242 / 0.94);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
  }

  .nav__logo-img {
    width: min(var(--logo-w), 160px);
    margin: calc(min(var(--logo-w), 160px) * -0.1853)
      calc(min(var(--logo-w), 160px) * -0.1376)
      calc(min(var(--logo-w), 160px) * -0.1776)
      calc(min(var(--logo-w), 160px) * -0.1394);
  }

  .nav__cta {
    padding-inline: 14px;
    font-size: 14px;
  }

  .hero__cta[data-slot="button"][data-size="default"] {
    margin-top: 28px;
  }

  .trailer {
    padding-top: 36px;
    padding-bottom: 64px;
  }

  .reel__badge .glass__bend {
    filter: none;
    background: rgb(255 255 255 / 0.65);
  }

  .statement {
    height: 350svh;
  }

  .statement__stage {
    padding-inline: 16px;
  }

  .statement__line {
    font-size: clamp(20px, 5.2vw, 36px);
  }

  .statement__media {
    --media: clamp(32px, 8vw, 44px);
  }

  .dock.is-open {
    width: calc(100% - 40px);
    height: 184px;
  }

  .dock.is-open .dock__slot {
    align-self: flex-end;
    margin-bottom: 14px;
    width: 44px;
    height: 44px;
  }

  .dock__composer {
    inset: 16px;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }

  .dock__input {
    width: 100%;
    min-height: 96px;
    padding: 0;
    align-self: stretch;
    font-size: 16px;
  }

  .dock__send {
    align-self: flex-end;
    width: 44px;
    height: 44px;
  }

  .compare {
    padding-bottom: 80px;
  }

  .compare__lede {
    padding-inline: 24px;
    margin-bottom: 96px;
    font-size: clamp(24px, 5.8vw, 36px);
    line-height: 1.2;
  }

  .compare__plate {
    padding: 40px 12px 28px;
    border-radius: 16px;
  }

  .compare__title {
    margin-bottom: 16px;
    font-size: clamp(26px, 6.5vw, 36px);
    line-height: 1.12;
    text-wrap: balance;
  }

  .compare__sub {
    margin-bottom: 28px;
    font-size: 14px;
    line-height: 1.45;
    text-wrap: balance;
  }

  .compare__head {
    font-size: 13px;
  }

  .compare__logo {
    width: min(88px, 100%);
    margin-block: -14px;
  }

  .compare__table th[scope="row"] {
    padding: 18px 12px 18px 10px;
    font-size: 13px;
    line-height: 1.45;
    overflow-wrap: break-word;
  }

  .compare__cell {
    padding: 18px 5px;
  }

  .compare__sum {
    font-size: 11px;
    line-height: 1.45;
    overflow-wrap: break-word;
  }

  .compare__note {
    margin-top: 24px;
    font-size: 12px;
    line-height: 1.5;
  }

  .footer {
    height: 280px;
  }

  .footer__links {
    font-size: 16px;
  }

  .footer__links a,
  .footer__link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  .footer__word {
    font-size: 28vw;
  }

  .reel-modal__close {
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
  }

  .reel-modal__frame {
    width: min(calc(100vw - 24px), calc((100svh - 24px) * 16 / 9));
  }
}
