/* Backdrop landing page. Rules retain cascade order; responsive variants stay explicit. */
:root {
  color-scheme: dark;
  --stage: #000000;
  --text: #f5f5f7;
  --muted: #86868b;
  --control: #1d1d1f;
  /* One focus ring across the site: pricing's white. */
  --focus: rgb(255 255 255 / .85);
  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
  background: var(--stage);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}
/* The page keeps its own place (app.js restores the visitor's beat by itself), so the browser must never shift it to
   keep some content in view while the layout settles: on a reload that carried Safari from the tour into the FAQ. */
html {
  overflow-anchor: none;
}
/* Where a link from the keyboard lands (app.js gives it focus), without a ring around a whole section. */
[tabindex="-1"]:focus {
  outline: none;
}
/* While app.js restores a place (a reload, Back, a link into the tour), the head script hides the page, so the first
   thing shown is the restored scene rather than the top of the page. Should the script never come, the page shows
   anyway. */
html[data-restoring] body {
  /* Faded out, not hidden: an element that sets its own visibility (the lid's video) would show through a hidden body. */
  opacity: 0;
  animation: restoring-fallback 0s linear 4s forwards;
}
@keyframes restoring-fallback {
  to { opacity: 1; }
}
/* Hero and photographic stage */
* {
  box-sizing: border-box;
}
body {
  margin: 0;
}
.hero {
  position: relative;
  min-height: 480px;
  height: 100svh;
  /* Clipped, not hidden: a box with overflow: hidden can still be scrolled, and a link to one of the cards inside it
     (#projects) made the browser scroll the hero itself, shifting the whole scene. */
  overflow: hidden;
  overflow: clip;
  display: grid;
  place-items: end center;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  isolation: isolate;
}
.hero-stage {
  position: relative;
  cursor: default;
  -webkit-user-select: none;
  user-select: none;
  /* The stage stands on the hero's floor (3svh up), and the title's box
     starts 7.16% down it, so a stage (0.97 × screen − clearance) / 0.9284 tall
     leaves that clearance above the title: 40px, or 84px, below Get Backdrop,
     where the title is wide enough to run under it (half its width is 0.245
     of the stage's, and the button's left edge is 182px in from the right,
     counting a 12px gap). 1.5573 is 1920 / 1328 / 0.9284. */
  width: min(125vw, 2000px, calc((97svh - 40px) * 1.5573), max(calc(204.1vw - 743px), calc((97svh - 84px) * 1.5573)));
  aspect-ratio: 1920 / 1328;
  justify-self: center;
  transform: translateY(-3svh);
  container-type: inline-size;
}
.hero-stage::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 5%;
  background: linear-gradient(transparent, var(--stage));
  pointer-events: none;
}
.hero-still, .hero-video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.hero-video {
  position: absolute;
  inset: 0;
  visibility: hidden;
}
.hero[data-state="loading"] .hero-video, .hero[data-state="playing"] .hero-video, .hero[data-state="paused"] .hero-video {
  visibility: visible;
}
/* Until its first frame is up the video shows the lid's, and the open Mac beneath it stays hidden: Safari draws neither
   the poster nor a frame between the source being set and the first frame decoding, which let the open Mac show through
   for a few frames before the lid. */
.hero[data-state="idle"] .hero-video, .hero[data-state="loading"] .hero-video {
  background: center / contain no-repeat url("/assets/macbook-start.jpg");
}
.hero[data-state="loading"] .hero-still {
  visibility: hidden;
}
.hero[data-state="ended"] .hero-video {
  display: none;
}
/* The windows of the opening pile spill past the screen's edges (sections/desk.js), so the screen doesn't clip; its
   desktop and menu bars round its top corners themselves. The screen has the desktop's own proportions, 1512 × 982
   points, so no layer is squeezed to fit it; the quarter point it runs past the MacBook's glass sits behind the
   bezel. */
.screen-overlay {
  position: absolute;
  left: 18.65%;
  top: 34.35%;
  width: 62.7%;
  aspect-ratio: 1512 / 982;
  isolation: isolate;
  pointer-events: none;
  visibility: hidden;
}
.hero[data-state="ended"] .screen-overlay, .hero[data-state="still"] .screen-overlay {
  visibility: visible;
}
/* While the lid plays (again, on Replay) the screen is dark: the pile's windows, which desk.js shows by name, too. */
.hero:not([data-state="ended"], [data-state="still"]) .screen-overlay .desk-win {
  visibility: hidden !important;
}
/* The screen: one 1512 × 982 point desktop with the windows of three projects, each window a 2x capture of a real
   window with its shadow (output/launch-video/source/site-captures.py), placed so the window lands on its tile.
   The desktop and menu bars are renders (site-export.mjs). --pt is one desktop point in pixels, from the camera.
   sections/desk.js lays every layer out in whole device pixels from its box in points; the boxes below, in percent of
   the desktop, place the Main and stack desktop without JavaScript, sized for the 1 pixel a point pictures (whose
   transparent padding runs a few pixels past the right and bottom edges). */
.screen-overlay {
  --ptn: .4;
  --pt: calc(var(--ptn) * 1px);
}
.desk-base, .desk-win, .desk-menubar {
  position: absolute;
  display: block;
  max-width: none;
  /* Pictures of a desktop, not pictures to drag off the page (notchboard.js also refuses dragstart). */
  -webkit-user-drag: none;
}
.desk-base {
  left: 0;
  top: 0;
  width: 100%;
  height: 100.20367%;
  border-radius: 1.8% 1.8% 0 0 / 1.79641% 1.79641% 0 0;
}
/* Development, Main and stack. */
.desk-xcode {
  left: -3.04233%;
  top: .40733%;
  width: 66.66667%;
  height: 98.98167%;
}
.desk-terminal {
  left: 58.59788%;
  top: 2.64766%;
  width: 42.46032%;
  height: 48.26884%;
}
.desk-safari {
  left: 58.59788%;
  top: 46.74134%;
  width: 42.46032%;
  height: 48.26884%;
}
/* School, Focus. */
.desk-textedit {
  left: -3.04233%;
  top: .40733%;
  width: 106.34921%;
  height: 98.98167%;
  --tx: -9;
  --ty: -31;
}
/* Personal, Keep my layout. */
.desk-safari-keep {
  left: 48.74339%;
  top: 17.71894%;
  width: 42.85714%;
  height: 65.98778%;
  --tx: -556;
  --ty: 119;
}
.desk-preview {
  left: 3.57143%;
  top: 2.85132%;
  width: 54.76190%;
  height: 95.31568%;
  --tx: 344;
  --ty: -23;
}
/* A window minimizes into its app's Dock icon as the launch video draws it: it falls toward the icon from its bottom
   edge, tipping back in perspective and narrowing, speeding up as it goes (--tx, --ty: from the image's bottom centre to
   the icon, in points). A window coming back out reverses it, slowing as it lands. desk.js staggers them (--delay):
   windows going away leave 50 ms apart, and the ones coming back rise 400 ms after the first went. At rest a window
   has no transform at all, so the browser draws it flat and crisp. */
.desk-win {
  transform-origin: 50% 100%;
  transition: transform var(--t-move) var(--ease-out) var(--delay, 0ms), opacity var(--t-move) var(--ease-out) var(--delay, 0ms),
    visibility 0s linear var(--delay, 0ms);
}
.desk-win.gone {
  transform: translate(calc(var(--tx) * var(--pt)), calc(var(--ty) * var(--pt))) perspective(calc(500 * var(--pt))) rotateX(-34deg) scale(.07, .14);
  opacity: .8;
  visibility: hidden;
  /* Put away, a window follows the screen's scale (--pt) at once; only the flight into the Dock is animated. */
  transition: none;
}
.desk-win.gone.flying {
  transition: transform var(--t-move) var(--ease-in) var(--delay, 0ms), opacity var(--t-move) var(--ease-in) var(--delay, 0ms),
    visibility 0s linear calc(var(--delay, 0ms) + var(--t-move));
}
/* While the opening pile is on screen, desk.js places every window itself, frame by frame; while it pops out of the
   screen each window gets a layer of its own, which it gives back once landed so it is drawn crisp again. */
.screen-overlay.messy .desk-win {
  transition: none;
  animation: none;
}
.screen-overlay.spilling .desk-win {
  will-change: transform, opacity, filter;
}
/* The window in hand on the Notchboard stop gets a layer of its own too (notchboard.js): Safari's glass follows a
   layer as it moves, but over a window repainted inside the desktop's layer it kept showing where the window had been. */
.desk-win.held {
  will-change: transform;
}
/* The layers of the screen, back to front: the desktop, the windows (the front one of Keep my layout on top), a window
   flying into or out of the Dock, the menu bar with its notch, and Backdrop's own panels (.desk-ui), as on a Mac. The
   opening pile spills out of the screen toward the viewer, so it lies over the menu bar and the notch. */
.desk-win.flying {
  z-index: 15 !important;
}
.desk-menubar {
  z-index: 20;
}
.screen-overlay.messy .desk-menubar {
  z-index: 0;
}
/* The captures of a window's other sizes, until a layout uses them. */
.desk-win.idle {
  opacity: 0;
  visibility: hidden;
  transition: none;
}
/* A window's frame while it moves to a new layout (desk.js morph): its colour and its shadow under the two captures
   riding on it, fitted to the captures' own (an active window's is deeper). */
.desk-shade {
  position: absolute;
  display: none;
  border-radius: calc(16 * var(--pt));
  background: #222733;
  box-shadow: 0 0 calc(4 * var(--pt)) rgb(0 0 0 / .1), 0 calc(8 * var(--pt)) calc(16 * var(--pt)) rgb(0 0 0 / .41);
  pointer-events: none;
}
.desk-shade.on {
  display: block;
}
.desk-shade[data-win="xcode"] {
  background: #262626;
  box-shadow: 0 0 calc(2 * var(--pt)) rgb(0 0 0 / .1), 0 calc(18 * var(--pt)) calc(40 * var(--pt)) rgb(0 0 0 / .68);
}
.desk-shade[data-win="safari"] {
  background: #0b1424;
}
.desk-menubar {
  left: 0;
  top: 0;
  width: 100%;
  height: 3.66599%;
  /* The screen's corner: 1.8% of the screen's height is 49% of the bar's picture. */
  border-radius: 1.8% 1.8% 0 0 / 49.11% 49.11% 0 0;
  opacity: 0;
  /* The bar changes as the new project's windows come back (desk.js --bar-delay). */
  transition: opacity 0s linear var(--bar-delay, 0ms);
}
.desk-menubar.on {
  opacity: 1;
}
/* When the lid has opened, the desktop wakes: the Dock and menu bar fade in while the pile pops out (desk.js). Once
   that has played the screen is awake, and changes only use the transitions. A desktop that wakes already sorted
   (the dive off) settles its windows in instead. */
.hero[data-state="ended"] .screen-overlay:not(.awake) .desk-base, .hero[data-state="ended"] .screen-overlay:not(.awake) .desk-menubar.on {
  animation: desk-fade-in 360ms var(--ease-out) backwards;
}
.hero[data-state="ended"] .screen-overlay:not(.awake, .messy) .desk-win:not(.gone, .idle) {
  animation: desk-window-in var(--t-move) var(--ease-out) backwards;
}
.desk-xcode {
  animation-delay: 100ms;
}
.desk-terminal {
  animation-delay: 150ms;
}
.desk-safari {
  animation-delay: 200ms;
}
@keyframes desk-fade-in {
  from { opacity: 0; }
}
@keyframes desk-window-in {
  from { opacity: 0; transform: translateY(2%) scale(.94); }
}
/* Reduced motion: nothing flies or settles; a window going away or coming back fades where it is. */
@media (prefers-reduced-motion: reduce) {
  .hero[data-state="ended"] .screen-overlay .desk-base, .hero[data-state="ended"] .screen-overlay .desk-menubar,
  .hero[data-state="ended"] .screen-overlay .desk-win {
    animation: none;
  }
  .desk-win {
    transition: opacity var(--t-fast) linear, visibility 0s;
  }
  .desk-win.gone {
    transform: none;
    opacity: 0;
    transition: opacity var(--t-fast) linear, visibility 0s linear var(--t-fast);
  }
  .desk-menubar {
    transition: none;
  }
}
/* Backdrop's own panels, in desktop points: the board dropping from the Backdrop icon in the menu bar (its centre at
   1215 points), the switch pop-up and the Notchboard, as the app draws them, over every window. switch.css and
   notchboard.css style them. */
.desk-ui {
  z-index: 30;
  position: absolute;
  left: 0;
  top: 0;
  width: 1512px;
  height: 982px;
  /* Scaled, not zoomed: iOS Safari doesn't scale text with zoom (on a phone it holds a 9px minimum, on an iPad its full
     size), so the board's labels overran their boxes. */
  transform: scale(var(--ptn));
  transform-origin: 0 0;
  pointer-events: none;
}
.desk-ui .sw-plate, .desk-ui .sw-board {
  left: 613px;
  top: 36px;
  width: 640px;
  height: 360px;
  border-radius: 12px;
}
.desk-ui .sw-board.open {
  pointer-events: auto;
}
.desk-ui .sw-inner {
  transform: none;
}
.desk-ui .sw-tile, .desk-ui .sw-row {
  cursor: pointer;
}
/* The board is drawn at the screen's scale, rarely a whole number of pixels per point. There a one-point line drawn
   as an inset shadow shimmers as the camera settles, and a row's outline was cut where the rows' scroll box clipped
   it. Borders snap to whole device pixels, and the site's three rows never need to scroll. */
.desk-ui .sw-rows {
  overflow: visible;
}
.desk-ui .sw-rline, .desk-ui .sw-rhov {
  box-sizing: border-box;
  box-shadow: none;
  border: 1px solid rgba(255, 255, 255, 0.5);
}
.desk-ui .sw-rhov {
  border-color: rgba(255, 255, 255, 0.1);
}
.desk-ui .sw-tile {
  padding: 5px;
  box-shadow: none;
  border: 1px solid rgba(255, 255, 255, 0.16);
}
.desk-ui .sw-preview-bg {
  box-sizing: border-box;
  box-shadow: none;
  border: 1px solid rgba(255, 255, 255, 0.07);
}
/* An open board has no filter left on it, which would keep it on a layer redrawn at its own scale. */
.desk-ui .sw-board.open {
  filter: none;
}
.desk-ui .sw-app img {
  display: block;
  width: 16px;
  height: 16px;
}
/* The switch pop-up: in the screen's middle, as on a Mac. The camera keeps it clear of the Projects card (app.js). */
.desk-ui .sw-hud {
  left: 606px;
  top: 437px;
}
/* The guided runs' pointer (projects.js, notchboard.js): macOS's own arrow, 22 × 31 points, its tip on the element's
   corner, over Backdrop's panels as on a Mac. */
.desk-ui .desk-cursor {
  position: absolute;
  z-index: 9;
  left: 0;
  top: 0;
  width: 22px;
  height: 31px;
  margin: -2.5px 0 0 -3.3px;
  opacity: 0;
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, 0.35));
  transition: opacity var(--t-fast) var(--ease-out);
}
.desk-ui .desk-cursor.on {
  opacity: 1;
}
.desk-cursor img {
  display: block;
  width: 100%;
  height: 100%;
  transform-origin: 15% 8%;
  transition: transform var(--t-press) var(--ease-out);
}
.desk-cursor.press img {
  transform: scale(0.9);
}
/* The dive (app.js): .hero stays on screen while .hero-dive scrolls past it. The opening pile sorts itself, the
   camera pushes into the screen and in on the board for the Projects stop, back out for Layouts, close on the notch
   for the Notchboard, and each stop's card lifts over the desktop in turn.
   The dive's final layout comes from here, before any script runs, so a reload, Back or a link into the tour finds
   the page as long as it will be: the hero exactly one screen tall (no 480px floor, so a landscape phone's beats all
   fit), Pricing seven of its heights down (six of travel through the stops, then one over which Pricing rises), the
   cards out of the flow until app.js moves them into the hero. The dive is a screen longer than that and gives the
   screen back with its margin, so the hero holds still behind Pricing as it rises: the end card covers the Mac as the
   camera pulls back and the scene fades. The same rules follow data-on for a browser without the scripting query.
   Without JavaScript the hero scrolls away as a normal section and the cards follow it. */
.hero-dive {
  position: relative;
}
@media (scripting: enabled) {
  .hero-dive:not([data-on="false"]) {
    height: calc(100svh * 8);
    margin-bottom: -100svh;
  }
  :where(.hero-dive:not([data-on="false"])) + #pricing {
    position: relative;
    z-index: 1;
    background-color: var(--stage);
  }
  .hero-dive:not([data-on="false"]) > .hero {
    position: sticky;
    top: 0;
    min-height: 0;
  }
  .hero-dive:not([data-on="false"]) > .tour-card {
    position: absolute;
    left: 0;
    top: 0;
    visibility: hidden;
  }
  .hero-dive:not([data-on="false"]) > .hero-sentinel {
    height: calc(100svh * .6);
  }
}
.hero-dive[data-on="true"] {
  height: calc(100svh * 8);
  margin-bottom: -100svh;
}
:where(.hero-dive[data-on="true"]) + #pricing {
  position: relative;
  z-index: 1;
  background-color: var(--stage);
}
.hero-dive[data-on="true"] > .hero {
  position: sticky;
  top: 0;
  min-height: 0;
}
.hero-dive[data-on="true"] .hero-stage {
  transform-origin: 0 0;
}
/* The buy bar shows once this has left the screen (sections/buybar.js): while diving, from the first step on. */
.hero-sentinel {
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: max(480px, 100svh);
  pointer-events: none;
}
.hero-dive[data-on="true"] > .hero-sentinel {
  height: calc(100svh * .6);
}
/* On a touch screen the browser rests the dive on its beats: app.js puts a marker at each beat, which the page snaps
   to and never skips (a fling moves one scene, and nothing moves under a finger), and Pricing is one snap area that
   scrolls freely inside. app.js turns snapping on once the markers stand, and off while it moves the page itself. */
.beat-snap {
  position: absolute;
  left: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
@media (hover: none) and (pointer: coarse) {
  html[data-snap] {
    scroll-snap-type: y mandatory;
  }
  /* Its top and its end (the foot of the page) are its edges; anywhere between is free. */
  html[data-snap] #pricing {
    scroll-snap-align: start end;
  }
}
/* Until app.js has chosen how the hero starts, a page that will play the lid shows the lid's first frame, so the Mac
   never shows open and then closes. */
@media (scripting: enabled) and (prefers-reduced-motion: no-preference) {
  .hero[data-state="idle"] .hero-video {
    visibility: visible;
  }
  .hero[data-state="idle"] .hero-still {
    visibility: hidden;
  }
}
/* The scene fades into this as Pricing rises over it (app.js sets its opacity from the scroll). */
.hero-veil {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: #000;
  opacity: 0;
  pointer-events: none;
}
/* A cut dips the whole page through black (app.js): above the scene and Pricing, below the buy bar. */
.page-cut {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100vh;
  z-index: 49;
  background: #000;
  opacity: 0;
  pointer-events: none;
}
/* app.js lays the screen out at its zoomed size; it keeps the stage's corner rounding and sits above it. */
.hero > .screen-overlay {
  z-index: 2;
}
/* The stops' cards, the dim behind a stop's first headline and the headline itself: sections/tour.css. */
.hero-scroll {
  opacity: 0;
  transition: opacity 700ms var(--ease-out);
  position: absolute;
  bottom: max(22px, env(safe-area-inset-bottom));
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 7px;
  min-height: 44px;
  padding: 4px 16px;
  border: 0;
  background: transparent;
  font: inherit;
  color: #929297;
  font-size: 13px;
  line-height: 1.4;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.hero-scroll[inert] {
  pointer-events: none;
}
/* It leaves at once when the scene moves on, and comes back slowly when it rests. */
.hero-scroll[data-shown="false"] {
  transition-duration: var(--t-fast);
}
@media (prefers-reduced-motion: reduce) {
  .hero-scroll {
    transition: none;
  }
}
.hero-scroll svg {
  width: 14px;
  height: 14px;
  color: #747479;
}
/* Each time the cue comes in, its words rise out of a soft blur, as the tagline's do, and the chevron drops in after
   them. Then, while the page rests, a light sweeps across the words and the chevron runs down out of sight and back as
   the light reaches it: the two loops share one beat. The tour's Next buttons run the same loop (sections/tour.css). */
@keyframes scroll-cue-rise {
  from { opacity: 0; translate: 0 8px; filter: blur(6px); }
  to { opacity: 1; translate: 0 0; filter: blur(0); }
}
@keyframes scroll-chevron-in {
  from { opacity: 0; translate: 0 -6px; }
  to { opacity: 1; translate: 0 0; }
}
@keyframes scroll-cue-sheen {
  0% { background-position: 100% 0; animation-timing-function: var(--ease-in-out); }
  40%, 100% { background-position: 0 0; }
}
@keyframes scroll-chevron-run {
  0%, 32% { opacity: 1; translate: 0 0; animation-timing-function: var(--ease-in); }
  52% { opacity: 0; translate: 0 7px; }
  53% { opacity: 0; translate: 0 -7px; animation-timing-function: var(--ease-out); }
  76%, 100% { opacity: 1; translate: 0 0; }
}
@media (prefers-reduced-motion: no-preference) {
  .hero-scroll[data-shown="true"] > span {
    animation: scroll-cue-rise 900ms var(--ease-out) both, scroll-cue-sheen 3.4s 1.1s infinite;
  }
  .hero-scroll[data-shown="true"] svg {
    animation: scroll-chevron-in 700ms var(--ease-out) 150ms both, scroll-chevron-run 3.4s 1.1s infinite;
  }
  /* The light is the words' own fill: a band of white in their gray, off to the left between sweeps. */
  @supports (-webkit-background-clip: text) or (background-clip: text) {
    .hero-scroll > span {
      background: linear-gradient(100deg, currentColor 42%, var(--text) 50%, currentColor 58%) 100% 0 / 300% 100%;
      -webkit-background-clip: text;
      background-clip: text;
      -webkit-text-fill-color: transparent;
    }
  }
}
/* Beside a wide stage the MacBook's base reaches almost to the screen's lower
   edge, so the cue runs on one line beneath it. The button keeps its height
   as a target; only its content sits low. */
@media (min-width: 601px) {
  .hero-scroll {
    bottom: max(8px, env(safe-area-inset-bottom));
    flex-direction: row;
    align-items: flex-end;
    gap: 8px;
    padding: 0 16px 2px;
  }
  .hero-scroll svg {
    margin-bottom: 2px;
  }
}
@media (hover: hover) {
  .hero-scroll:hover, .hero-scroll:hover svg {
    color: var(--text);
  }
}
.playback {
  position: absolute;
  bottom: max(28px, env(safe-area-inset-bottom));
  right: max(32px, calc((100vw - 1280px) / 2));
  display: inline-flex;
  gap: 8px;
  align-items: center;
  min-height: 44px;
  padding: 0 15px;
  border: 1px solid #ffffff1f;
  border-radius: 24px;
  background: #1d1d1fb3;
  color: #c5c5c9;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: color 160ms ease, background-color 160ms ease;
}
[hidden] {
  display: none !important;
}
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 5px;
}
@media (hover: hover) {
  .playback:hover {
    color: var(--text);
    background: var(--control);
  }
}
@media (max-aspect-ratio: 3/4) {
  .hero {
    place-items: center;
  }
  .hero-stage {
    width: 140vw;
    max-width: none;
  }
}
@media (max-width: 600px) {
  .hero-scroll {
    bottom: max(82px, calc(env(safe-area-inset-bottom) + 60px));
  }
  .playback {
    right: 20px;
    bottom: max(22px, env(safe-area-inset-bottom));
  }
}
/* A short phone (an iPhone SE in Safari) has the opening pile reaching down to that line: the cue goes to the foot. */
@media (max-width: 600px) and (max-height: 600px) {
  .hero-scroll {
    bottom: max(16px, env(safe-area-inset-bottom));
  }
}
/* A short landscape screen (a phone on its side) is the hero's whole height while diving: the stage stands a little
   smaller and higher, so the risen title keeps its room at the top and the cue its own line under the MacBook. */
@media (max-height: 500px) and (orientation: landscape) {
  .hero-stage {
    width: min(125vw, 2000px, calc((97svh - 68px) * 1.5573));
    transform: translateY(-28px);
  }
  .hero-scroll {
    bottom: max(4px, env(safe-area-inset-bottom));
  }
}
@media (prefers-reduced-motion: reduce) {
  .playback {
    transition: none;
  }
}
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.title-reveal {
  position: absolute;
  inset: 0 0 auto;
  /* Just above the settled lid; keep in sync with titleRevealTime in app.js. Only that lower edge clips: the risen
     title's ascenders may stand above the box on a short screen. */
  height: 32.3%;
  clip-path: inset(-50% -25% 0);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  pointer-events: none;
}
/* Instrument Serif's tall ascenders set the size and baseline that clear the
   top of the screen once the title has risen. At 13.5cqw, raised 54% of its
   line, its ascenders stand where the stage's clearance expects them, and its
   "p" leaves the tagline room above the lid. */
.hero-title {
  display: block;
  color: var(--text);
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 13.5cqw;
  font-weight: 400;
  letter-spacing: -.02em;
  font-kerning: normal;
  line-height: .9;
  padding-inline: .08em;
  margin-bottom: -.1em;
  /* Where it waits under the lid before it rises; phones, which lift it, start it lower. */
  --title-start: 100%;
  transform: translateY(var(--title-start));
}
.hero[data-title-visible="true"] .hero-title {
  animation: backdrop-rise 950ms cubic-bezier(.22, 1, .36, 1) both;
}
.hero[data-state="paused"] .hero-title {
  animation-play-state: paused;
}
.hero[data-state="still"] .hero-title {
  animation: none;
  transform: translateY(-54%);
}
@keyframes backdrop-rise {
  0% { transform: translateY(var(--title-start)); }
  100% { transform: translateY(-54%); }
}
@media (prefers-reduced-motion: reduce) {
  .hero[data-title-visible="true"] .hero-title {
    animation: none;
    transform: translateY(-54%);
  }
}
/* The tagline sits between the descender of Backdrop's "p" and the lid, a little nearer the "p", so it reads as the
   title's line rather than resting on the MacBook. */
.hero-subtitle {
  position: absolute;
  bottom: 1.2cqw;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .45em;
  width: 90cqw;
  color: #b8b8bf;
  font: 400 clamp(16px, 1.8cqw, 24px)/1.4 "Geist", -apple-system, "Helvetica Neue", sans-serif;
  text-align: center;
  opacity: 0;
}
.hero[data-title-visible="true"] .hero-subtitle {
  /* A beat after the title starts to rise, as the pile lands, with the film's reveal. */
  animation: subtitle-reveal var(--t-reveal) var(--ease-out) 1000ms both;
}
.hero[data-state="paused"] .hero-subtitle {
  animation-play-state: paused;
}
.hero[data-state="still"] .hero-subtitle {
  animation: none;
  opacity: 1;
}
/* The tagline breaks, where it must, between its two sentences. */
.hero-subtitle > span > span {
  display: inline-block;
}
@keyframes subtitle-reveal {
  from { opacity: 0; transform: translateY(12px); filter: blur(10px); }
  to { opacity: 1; transform: none; filter: none; }
}
/* Without scripting the intro never runs, so show the still state: title, tagline and screen. */
@media (scripting: none) {
  .hero .hero-title { transform: translateY(-54%); }
  .hero .hero-subtitle { opacity: 1; }
  .hero .screen-overlay { visibility: visible; }
}
/* On phones, portrait or landscape, the tagline holds its 16px minimum while
   the title shrinks with the stage, so the title lifts as well to keep the "p"
   of Backdrop clear of it (they crossed by 10px on landscape phones), and
   waits that much lower before it rises, so none of it shows above the box's
   edge early. */
@media (max-width: 600px), (max-width: 1000px) and (max-height: 500px) {
  .hero-title {
    position: relative;
    top: -2cqw;
    --title-start: 114%;
  }
  .hero-subtitle {
    align-items: flex-start;
  }
}
/* A landscape phone with Safari's toolbars showing needs another cqw: the
   title lifts that much more, and waits that much lower. */
@media (max-width: 1000px) and (max-height: 420px) {
  .hero-title {
    top: -3cqw;
    --title-start: 122%;
  }
}
@media (prefers-reduced-motion: reduce) {
  .hero[data-title-visible="true"] .hero-subtitle {
    animation: none;
    opacity: 1;
  }
}
.playback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 17px;
  border: 1px solid rgb(255 255 255 / .14);
  border-radius: 999px;
  background: linear-gradient(180deg, rgb(255 255 255 / .07), rgb(255 255 255 / .025)), #101012;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .055), 0 3px 12px #0003;
  color: #d4d4d8;
  font: 500 12px/1 -apple-system, BlinkMacSystemFont, sans-serif;
  letter-spacing: .01em;
  cursor: pointer;
  transition: border-color 180ms ease, color 180ms ease, background-color 180ms ease;
}
.playback {
  min-width: 104px;
}
.playback svg {
  flex: 0 0 15px;
  width: 15px;
  height: 15px;
}
.playback-symbol path {
  display: none;
}
.playback[data-action="pause"] .symbol-pause, .playback[data-action="play"] .symbol-play, .playback[data-action="replay"] .symbol-replay {
  display: block;
}
.playback:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 4px;
  border-radius: 999px;
}
@media (hover: hover) {
  .playback:hover {
    color: #fff;
    border-color: #ffffff40;
    background-color: #202024;
  }
}
.playback:active {
  background-color: #2a2a2e;
}
@media (prefers-reduced-motion: reduce) {
  .playback {
    transition: none;
  }
}
/* Get Backdrop over the hero, at the top right (its look: tokens.css .lp-cta). */
.hero-buy {
  position: absolute;
  z-index: 10;
  top: max(22px, env(safe-area-inset-top));
  right: 32px;
}
@media (max-width: 760px) {
  .hero-buy {
    right: 20px;
    top: 20px;
  }
}
.hero-stage .playback {
  z-index: 9;
  top: calc(94% - 22px);
  left: calc(81.35% - 22px);
  right: auto;
  bottom: auto;
  width: 44px;
  height: 44px;
  min-width: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  box-shadow: none;
  color: #929298;
}
.hero-stage .playback:hover, .hero-stage .playback:active {
  background: transparent;
  box-shadow: none;
  color: #f5f5f7;
}
.hero-stage .playback svg {
  width: 17px;
  height: 17px;
  flex-basis: 17px;
}
/* 404 page */
/* The page links sections/tokens.css for the site's type system. */
.not-found-page body {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  font-family: var(--lp-body);
}
.not-found-header {
  padding: 24px clamp(24px, 5vw, 72px);
}
.not-found-header a {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: #eee;
  font: 400 25px/1 var(--lp-display);
  letter-spacing: -.01em;
}
.not-found-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 32px 24px 56px;
}
.lost-window {
  position: relative;
  width: min(320px, 78vw);
  height: 210px;
  margin-bottom: 44px;
  border: 1px solid #ffffff30;
  border-radius: 16px;
  background: linear-gradient(145deg, #27272c, #101012 70%);
  box-shadow: inset 0 1px #ffffff0d, 0 20px 80px #ffffff04;
}
.lost-window::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 18px -15px -18px 15px;
  border: 1px solid #ffffff15;
  border-radius: 16px;
  background: #0a0a0c;
}
.lost-window-bar {
  height: 34px;
  display: flex;
  align-items: center;
  padding-inline: 14px;
  border-bottom: 1px solid #ffffff0b;
}
.lost-window-bar img {
  width: 42px;
  height: auto;
  opacity: .65;
}
.lost-window > span {
  display: grid;
  place-items: center;
  height: calc(100% - 34px);
  font: 400 108px/1 var(--lp-display);
  letter-spacing: -.02em;
  color: #c4c4cc;
}
.not-found-main h1 {
  margin: 0;
  font: 400 clamp(40px, 5.1vw, 64px)/1 var(--lp-display);
  letter-spacing: -.02em;
}
.not-found-main h1 em {
  color: var(--lp-muted);
}
.not-found-main > p {
  color: #a1a1a6;
  margin: 20px 0 28px;
  font-size: 16px;
  line-height: 1.65;
}
/* The outline pill of the pricing section's buttons. */
.not-found-home {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 26px;
  min-height: 48px;
  border: 1px solid rgb(255 255 255 / .24);
  border-radius: 999px;
  text-decoration: none;
  background: rgb(255 255 255 / .04);
  color: var(--text);
  font-size: 15px;
  font-weight: 500;
  line-height: 1;
  transition: transform 240ms cubic-bezier(.22, 1, .36, 1), background-color 200ms ease, border-color 200ms ease;
}
.not-found-home svg {
  order: -1;
  transition: transform 300ms cubic-bezier(.22, 1, .36, 1);
}
@media (hover: hover) {
  .not-found-home:hover {
    background: rgb(255 255 255 / .12);
    border-color: rgb(255 255 255 / .56);
    transform: scale(1.03);
  }
  .not-found-home:hover svg {
    transform: translateX(-2px);
  }
}
.not-found-home:active {
  transform: scale(.97);
  background: rgb(255 255 255 / .18);
  border-color: rgb(255 255 255 / .6);
}
.not-found-home:focus-visible {
  outline: 2px solid rgb(255 255 255 / .85);
  outline-offset: 3px;
}
.not-found-footer {
  padding: 20px 24px 28px;
  text-align: center;
  font-size: 12px;
  color: #85858c;
}
/* The homepage footer's links, so a lost visitor can still reach help and the policies. */
.not-found-footer nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 24px;
}
.not-found-footer nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: #a1a1a6;
  font-size: 14px;
  text-decoration: none;
  transition: color var(--t-fast) var(--ease-ui);
}
@media (hover: hover) {
  .not-found-footer nav a:hover {
    color: var(--lp-text);
  }
}
.not-found-footer p {
  margin: 8px 0 0;
}
@media (max-height: 660px) {
  .lost-window {
    height: 150px;
    margin-bottom: 30px;
  }
  .lost-window > span {
    font-size: 80px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .not-found-home, .not-found-home svg {
    transition: none;
  }
  .not-found-home:hover, .not-found-home:active, .not-found-home:hover svg {
    transform: none;
  }
}
.screen-overlay {
  isolation: isolate;
  z-index: 1;
}
/* Mask only the photograph: masking the glass ancestor causes iPhone artefacts. */
.hero-still, .hero-video {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}
